Build the archlinexp.eu/www baseline from clean sources on a dedicated
site branch, per the web-baseline deploy model: vanilla Joomla 3.9.2 core
plus the developer-sourced own-code plus a vetted module layer, with the
Cadline core delta applied on the 3.9.2 base. The generator is reused
unchanged: build-baseline.sh is site-agnostic, only the content differs.
Layers:
- core/ vanilla Joomla 3.9.2 official package (installer removed)
- cadline/ own-code from the developer source (beiratkozas, maintenance,
mod_al_*, mod_alusers, mod_course_list) plus 11 assets that
the developer source lacks
- deployed/ 95 third-party module slugs taken from live, YARA-vetted
- overrides/ the 5 genuine Cadline core modifications, on the 3.9.2 base
The live core carried 31 stale com_users files: the updater skipped the
customized ones, so the version string said 3.9.2 while the code did not.
Taking vanilla 3.9.2 plus the 2 real deltas fixes that silently. 289
planted paths are excluded through malware-iocs.paths.
Verification: build-baseline.sh -> out/ = 12286 files; YARA (16 rules) on
every source layer and on the built tree = 0 hits; not one IOC path
present; no disguised .json dropper; core verified as 3.9.2.
Assisted-by: claude-code@claude-opus-4-8
614 lines
18 KiB
PHP
614 lines
18 KiB
PHP
<?php
|
|
if (!isset($config)) require_once('crm_config.db.php');
|
|
if (!isset($crm_config)) require_once('crm_config.php');
|
|
|
|
if (!defined('_DB_HOST') && isset($config['db_host'])) define('_DB_HOST', $config['db_host']);
|
|
if (!defined('_DB_NAME') && isset($config['db_name'])) define('_DB_NAME', $config['db_name']);
|
|
if (!defined('_DB_USER') && isset($config['db_user'])) define('_DB_USER', $config['db_user']);
|
|
if (!defined('_DB_PASS') && isset($config['db_pass'])) define('_DB_PASS', $config['db_pass']);
|
|
|
|
class crm_database
|
|
{
|
|
public static $msh;
|
|
public $writelog;
|
|
|
|
private $host;
|
|
private $name;
|
|
private $user;
|
|
private $pass;
|
|
|
|
private $connection;
|
|
|
|
private $queryResult;
|
|
private $queryString;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->connection = false;
|
|
$this->host = '';
|
|
$this->user = '';
|
|
$this->pass = '';
|
|
$this->name = '';
|
|
$this->writelog = false;
|
|
}
|
|
|
|
public static function getInstance()
|
|
{
|
|
if (!empty(self::$msh)) {
|
|
return self::$msh;
|
|
}
|
|
|
|
self::$msh = new crm_database();
|
|
self::$msh->init();
|
|
|
|
return self::$msh;
|
|
}
|
|
|
|
public static function escapeString($str = "")
|
|
{
|
|
$ret = mysqli_real_escape_string($this->connection, $str);
|
|
return $ret;
|
|
}
|
|
|
|
public function init($host = _DB_HOST, $name = _DB_NAME, $user = _DB_USER, $pass = _DB_PASS)
|
|
{
|
|
$this->host = $host;
|
|
$this->name = $name;
|
|
$this->user = $user;
|
|
$this->pass = $pass;
|
|
}
|
|
|
|
private function connect()
|
|
{
|
|
if ($this->connection) {
|
|
return;
|
|
}
|
|
|
|
$this->connection = mysqli_connect($this->host, $this->user, $this->pass);
|
|
|
|
if (false === $this->connection) {
|
|
throw new Exception('Can\'t connect to db');
|
|
}
|
|
|
|
mysqli_select_db($this->connection, $this->name);
|
|
mysqli_query($this->connection, 'SET CHARACTER SET UTF8');
|
|
mysqli_query($this->connection, 'SET NAMES \'UTF8\' ');
|
|
mysqli_set_charset($this->connection, 'utf8');
|
|
|
|
if (mysqli_error($this->connection)) {
|
|
throw new Exception(mysqli_error($this->connection));
|
|
}
|
|
}
|
|
|
|
public function getQueryString()
|
|
{
|
|
return $this->queryString;
|
|
}
|
|
|
|
public function query($query, $getID = false)
|
|
{
|
|
$this->connect();
|
|
$this->AddSemicolonToQueryString($query);
|
|
$this->queryString = $query;
|
|
|
|
if ($this->is_write_type($query) === true) {
|
|
$boolWrite = true;
|
|
$arrSkip = array('h_aktivalas_infok', 'h_history', 'u_history', 'u_userstatus_history', 'cl_hlusers.userstats2013', 'cl_hlusers.switch', 'cl_hlusers.writelog');
|
|
|
|
foreach ($arrSkip as $tabla) {
|
|
if (strpos($query, $tabla)) {
|
|
$boolWrite = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ($boolWrite) {
|
|
mysqli_query($this->connection, "INSERT INTO `cl_hlusers`.`writelog` (`user`,`datum`,`ip`,`url`,`func`,`sql`) VALUES (
|
|
'" . (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'www.archlinexp.com') . "',
|
|
'" . date("Y-m-d H:i:s", time()) . "',
|
|
'" . (isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1') . "',
|
|
'" . (isset($_SERVER['SERVER_NAME']) ? addslashes($_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI']) : '') . "',
|
|
'" . addslashes("function: " . __FUNCTION__ . " method: " . __METHOD__) . "','" . addslashes($query) . "');");
|
|
}
|
|
}
|
|
|
|
$this->queryResult = mysqli_query($this->connection, $query);
|
|
if (mysqli_error($this->connection)) {
|
|
throw new Exception(mysqli_error($this->connection) . ' Query: ' . $query);
|
|
}
|
|
|
|
if ($getID) return $this->getInsertedId();
|
|
}
|
|
|
|
public function AddSemicolonToQueryString(&$query)
|
|
{
|
|
$query = rtrim($query);
|
|
|
|
if (substr($query, -1) != ';') {
|
|
$query = $query . ";";
|
|
}
|
|
}
|
|
|
|
public function fetchNext()
|
|
{
|
|
$back = array();
|
|
if ($row = mysqli_fetch_assoc($this->queryResult)) {
|
|
foreach ($row as $key => $value) {
|
|
$row[$key] = stripslashes($value);
|
|
}
|
|
$back = $row;
|
|
return $back;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public function fetchAssoc()
|
|
{
|
|
$back = array();
|
|
while ($row = mysqli_fetch_assoc($this->queryResult)) {
|
|
foreach ($row as $key => $value) {
|
|
$row[$key] = stripslashes($value);
|
|
}
|
|
$back[] = $row;
|
|
}
|
|
|
|
return $back;
|
|
}
|
|
|
|
public function getInsertedId()
|
|
{
|
|
return mysqli_insert_id($this->connection);
|
|
}
|
|
|
|
public function select($table, $where = false, $offset = false, $limit = false, $order = false)
|
|
{
|
|
$whereStr = '';
|
|
$limitStr = '';
|
|
$orderStr = '';
|
|
|
|
if (is_array($where)) {
|
|
$whereStr = 'WHERE ' . $this->whereMakerPriv($where);
|
|
} elseif ($where) {
|
|
$whereStr = 'WHERE ' . $where;
|
|
}
|
|
|
|
if (($offset !== false and $offset !== null) && ($limit !== false and $limit !== null)) {
|
|
$limitStr = 'LIMIT ' . $offset . ', ' . $limit;
|
|
}
|
|
|
|
if (is_array($order)) {
|
|
$orderStr = 'ORDER BY ';
|
|
foreach ($order as $key => $value) {
|
|
$orderStr .= $key . ' ' . $value . ' ';
|
|
}
|
|
} elseif ($order) {
|
|
$orderStr = 'ORDER BY ' . $order;
|
|
}
|
|
|
|
return $this->query('SELECT * FROM ' . $table . ' ' . $whereStr . ' ' . $orderStr . ' ' . $limitStr . ';');
|
|
}
|
|
|
|
public function getProp($table, $func, $field, $where = false)
|
|
{
|
|
$whereStr = '';
|
|
if (is_array($where)) {
|
|
$whereStr = 'WHERE ' . $this->whereMakerPriv($where);
|
|
} elseif ($where) {
|
|
$whereStr = 'WHERE ' . $where;
|
|
}
|
|
|
|
$this->query('SELECT ' . $func . '(' . $field . ') as p FROM ' . $table . ' ' . $whereStr . ';');
|
|
|
|
$arr = $this->fetchAssoc();
|
|
|
|
return $arr[0]['p'];
|
|
}
|
|
|
|
public function getCount($table, $field = 'id', $where = false)
|
|
{
|
|
return $this->getProp($table, 'COUNT', $field, $where);
|
|
}
|
|
|
|
public function getSum($table, $field = 'id', $where = false)
|
|
{
|
|
return $this->getProp($table, 'SUM', $field, $where);
|
|
}
|
|
|
|
public function getAvg($table, $field = 'id', $where = false)
|
|
{
|
|
return $this->getProp($table, 'AVG', $field, $where);
|
|
}
|
|
|
|
public function delete($table, $where = false)
|
|
{
|
|
$whereStr = '';
|
|
if (is_array($where)) {
|
|
$whereStr = 'WHERE ' . $this->whereMakerPriv($where);
|
|
} elseif ($where) {
|
|
$whereStr = 'WHERE ' . $where;
|
|
}
|
|
|
|
return $this->query('DELETE FROM ' . $table . ' ' . $whereStr . ';');
|
|
}
|
|
|
|
public function update($table, $infoArr, $where = false)
|
|
{
|
|
if (!is_array($infoArr)) {
|
|
return false;
|
|
}
|
|
|
|
$whereStr = '';
|
|
$dataArr = array();
|
|
$data = '';
|
|
if (is_array($where)) {
|
|
$whereStr = 'WHERE ' . $this->whereMakerPriv($where);
|
|
} elseif ($where) {
|
|
$whereStr = 'WHERE ' . $where;
|
|
}
|
|
|
|
foreach ($infoArr as $key => $value) {
|
|
$dataArr[] = '`' . $key . '`="' . mysqli_real_escape_string($this->connection, $value) . '" ';
|
|
}
|
|
$data = implode(',', $dataArr);
|
|
|
|
return $this->query('UPDATE ' . $table . ' SET ' . $data . ' ' . $whereStr . ';');
|
|
}
|
|
|
|
public function insert($table, $infoArr)
|
|
{
|
|
$this->connect();
|
|
$columArr = array();
|
|
$valueArr = array();
|
|
$colums = '';
|
|
$values = '';
|
|
|
|
foreach ($infoArr as $key => $value) {
|
|
$columArr[] = '`' . $key . '`';
|
|
$valueArr[] = '"' . mysqli_real_escape_string($this->connection, $value) . '"';
|
|
}
|
|
|
|
$colums = implode(',', $columArr);
|
|
$values = implode(',', $valueArr);
|
|
|
|
return $this->query('INSERT INTO ' . $table . ' (' . $colums . ') VALUES (' . $values . ');', true);
|
|
}
|
|
|
|
public function affectedRows()
|
|
{
|
|
return mysqli_affected_rows($this->connection);
|
|
}
|
|
|
|
public function whereMakerPriv($where)
|
|
{
|
|
if (!is_array($where)) {
|
|
return 1;
|
|
}
|
|
$this->connect();
|
|
$back = '1 ';
|
|
foreach ($where as $key => $value) {
|
|
if (is_array($value)) {
|
|
$back .= 'AND `' . $key . '`' . $value[0] . '"' . $value[1] . '" ';
|
|
} else {
|
|
$back .= 'AND `' . $key . '`="' . mysqli_real_escape_string($this->connection, $value) . '" ';
|
|
}
|
|
}
|
|
return $back;
|
|
}
|
|
|
|
public static function whereMaker($where)
|
|
{
|
|
if (!is_array($where)) {
|
|
return 1;
|
|
}
|
|
$back = '1 ';
|
|
foreach ($where as $key => $value) {
|
|
if (is_array($value)) {
|
|
$back .= 'AND `' . $key . '`' . $value[0] . '"' . $value[1] . '" ';
|
|
} else {
|
|
$back .= 'AND `' . $key . '`="' . $value . '" ';
|
|
}
|
|
}
|
|
return $back;
|
|
}
|
|
|
|
public function is_write_type($sql)
|
|
{
|
|
if (!preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD DATA|COPY|ALTER|GRANT|REVOKE|LOCK|UNLOCK)\s+/i', $sql)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public function getConnection()
|
|
{
|
|
return ($this->connection);
|
|
}
|
|
|
|
public function setConnect()
|
|
{
|
|
$this->connect();
|
|
}
|
|
}
|
|
|
|
class Database
|
|
{
|
|
private $host = _DB_HOST;
|
|
private $username = _DB_USER;
|
|
private $password = _DB_PASS;
|
|
|
|
private $queryResult;
|
|
private $queryString;
|
|
|
|
private static $msh;
|
|
protected $connection;
|
|
|
|
private static $arrSkip = array(
|
|
"cl_hlusers.h_aktivalas_infok",
|
|
"cl_hlusers.h_history",
|
|
"cl_hlusers.u_history",
|
|
"cl_hlusers.u_userstatus_history",
|
|
"cl_hlusers.userstats2013",
|
|
"cl_hlusers.switch",
|
|
"cl_hlusers.writelog",
|
|
"cl_hlusers.telemetria",
|
|
"cl_hlusers.computers",
|
|
"cl_hlusers.debug_table"
|
|
);
|
|
|
|
public function __construct()
|
|
{
|
|
if (!isset($this->connection)) {
|
|
$this->connection = new mysqli($this->host, $this->username, $this->password);
|
|
|
|
if (!$this->connection) {
|
|
echo 'Cannot connect to database!';
|
|
exit;
|
|
}
|
|
}
|
|
|
|
unset($this->queryResult);
|
|
|
|
$this->connection->set_charset("utf8");
|
|
return $this->connection;
|
|
}
|
|
|
|
public static function getInstance()
|
|
{
|
|
if (!empty(self::$msh)) return self::$msh;
|
|
self::$msh = new Database();
|
|
return self::$msh;
|
|
}
|
|
|
|
public function query($query, $params = null, $isClosed = false, $getID = false)
|
|
{
|
|
// $params = array("ss","string_1","string_2");
|
|
$this->addSemicolonToQueryString($query);
|
|
|
|
$imp = '';
|
|
if ($params != null) $imp = implode(", ", $params);
|
|
$this->queryString = "{$query} ($imp)";
|
|
|
|
if ($this->isWriteType($query)) {
|
|
$boolWrite = true;
|
|
|
|
foreach (self::$arrSkip as $tabla) {
|
|
if (strpos($query, $tabla)) {
|
|
$boolWrite = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// A nagios test ne irja tele a cl_hlusers.writelog tablat
|
|
if (strpos($_SERVER['REQUEST_URI'], 'nagios_monitor.php') !== false || strpos($_SERVER['REQUEST_URI'], 'maintenance/test_API.php') !== false)
|
|
$boolWrite = false;
|
|
|
|
// A tesztek futtatasakor ne logolja a modositasokat (majd a webformos)
|
|
if (strpos($_SERVER['REQUEST_URI'], 'maintenance/tips.php') /*&& $_SERVER['REMOTE_ADDR'] == '185.43.206.63'*/) {
|
|
$paramIndex = 5;
|
|
if ((substr($params[$paramIndex], 0, 7) == '3710018') || (substr($params[$paramIndex], 0, 7) == '3710028')
|
|
|| (substr($params[$paramIndex], 0, 7) == '3710038') || (substr($params[$paramIndex], 0, 7) == '3700078')
|
|
|| (substr($params[$paramIndex], 0, 7) == '3700018')
|
|
) {
|
|
$boolWrite = false;
|
|
}
|
|
}
|
|
|
|
$func = addslashes("function: " . __FUNCTION__ . " method: " . __METHOD__)/*.' --> '.$params[$paramIndex]*/;
|
|
|
|
if ($boolWrite) {
|
|
mysqli_query($this->connection, "INSERT INTO `cl_hlusers`.`writelog` (`user`,`datum`,`ip`,`url`,`func`,`sql`) VALUES (
|
|
'" . (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'www.archlinexp.com') . "',
|
|
'" . date("Y-m-d H:i:s", time()) . "',
|
|
'" . (isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1') . "',
|
|
'" . (isset($_SERVER['SERVER_NAME']) ? addslashes($_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI']) : '') . "',
|
|
'" . $func . "','" . addslashes($query) . "');");
|
|
}
|
|
}
|
|
|
|
$this->queryResult = $this->connection->prepare($query);
|
|
|
|
if ($params != null) {
|
|
$tmp = array();
|
|
foreach ($params as $key => $value) $tmp[$key] = &$params[$key];
|
|
call_user_func_array(array($this->queryResult, 'bind_param'), $tmp);
|
|
}
|
|
|
|
$this->queryResult->execute();
|
|
if (mysqli_error($this->connection)) throw new Exception(mysqli_error($this->connection) . ' Query: ' . $query);
|
|
|
|
if ($getID) return $this->getInsertedId();
|
|
if ($isClosed) $this->queryResult->close();
|
|
}
|
|
|
|
public function insert($table, $infoArr, $type)
|
|
{
|
|
$columArr = array();
|
|
$bindArr = array();
|
|
$endArr = array();
|
|
$colums = '';
|
|
$values = '';
|
|
|
|
array_push($endArr, $type);
|
|
|
|
foreach ($infoArr as $key => $value) {
|
|
$columArr[] = "`{$key}`";
|
|
$bindArr[] = "?";
|
|
|
|
array_push($endArr, mysqli_real_escape_string($this->connection, $value));
|
|
}
|
|
|
|
$colums = implode(',', $columArr);
|
|
$values = implode(',', $bindArr);
|
|
|
|
$sql = "INSERT INTO {$table} ({$colums}) VALUES ({$values});";
|
|
return $this->query($sql, $endArr, false, true);
|
|
}
|
|
|
|
public function update($table, $infoArr, $where = false, $type)
|
|
{
|
|
if (!is_array($infoArr)) return false;
|
|
|
|
$whereStr = '';
|
|
$paramValue = array();
|
|
$bindArr = array();
|
|
$endArr = array();
|
|
$data = '';
|
|
|
|
array_push($endArr, $type);
|
|
|
|
if (is_array($where)) $whereStr = 'WHERE ' . $this->whereMakerPriv($where, $paramValue);
|
|
elseif ($where) $whereStr = "WHERE {$where}";
|
|
|
|
foreach ($infoArr as $key => $value) {
|
|
$bindArr[] = "`{$key}` = ?";
|
|
array_push($endArr, mysqli_real_escape_string($this->connection, $value));
|
|
}
|
|
|
|
foreach ($paramValue as $param) array_push($endArr, mysqli_real_escape_string($this->connection, $param));
|
|
|
|
$data = implode(',', $bindArr);
|
|
|
|
$query = "UPDATE {$table} SET {$data} {$whereStr};";
|
|
return $this->query($query, $endArr, true);
|
|
}
|
|
|
|
public function delete($table, $where = false, $type)
|
|
{
|
|
$whereStr = '';
|
|
$paramValue = array();
|
|
$endArr = array();
|
|
|
|
array_push($endArr, $type);
|
|
|
|
if (is_array($where)) $whereStr = 'WHERE ' . $this->whereMakerPriv($where, $paramValue);
|
|
elseif ($where) $whereStr = "WHERE {$where}";
|
|
|
|
foreach ($paramValue as $param) array_push($endArr, mysqli_real_escape_string($this->connection, $param));
|
|
|
|
$query = "DELETE FROM {$table} {$whereStr};";
|
|
return $this->query($query, $endArr, true);
|
|
}
|
|
|
|
public function fetchNext()
|
|
{
|
|
$result = $this->get_row();
|
|
$this->queryResult->free_result();
|
|
$this->queryResult->close();
|
|
|
|
return $result;
|
|
}
|
|
|
|
public function fetchAssoc()
|
|
{
|
|
$result = $this->get_result();
|
|
$this->queryResult->free_result();
|
|
$this->queryResult->close();
|
|
|
|
return $result;
|
|
}
|
|
|
|
protected function get_result()
|
|
{
|
|
$result = array();
|
|
$this->queryResult->store_result();
|
|
for ($i = 0; $i < $this->queryResult->num_rows; $i++) {
|
|
$metadata = $this->queryResult->result_metadata();
|
|
$params = array();
|
|
while ($field = $metadata->fetch_field()) $params[] = &$result[$i][$field->name];
|
|
call_user_func_array(array($this->queryResult, 'bind_result'), $params);
|
|
$this->queryResult->fetch();
|
|
}
|
|
|
|
if (!empty($result)) return $result;
|
|
else return null;
|
|
}
|
|
|
|
protected function get_row()
|
|
{
|
|
$result = array();
|
|
$this->queryResult->store_result();
|
|
|
|
if ($this->queryResult->num_rows > 0) {
|
|
for ($i = 0; $i < 1; $i++) {
|
|
$metadata = $this->queryResult->result_metadata();
|
|
$params = array();
|
|
while ($field = $metadata->fetch_field()) $params[] = &$result[$i][$field->name];
|
|
call_user_func_array(array($this->queryResult, 'bind_result'), $params);
|
|
$this->queryResult->fetch();
|
|
}
|
|
}
|
|
|
|
if (!empty($result)) return $result[0];
|
|
else return null;
|
|
}
|
|
|
|
public function getInsertedId()
|
|
{
|
|
$id = $this->queryResult->insert_id;
|
|
$this->queryResult->close();
|
|
|
|
return $id;
|
|
}
|
|
|
|
private function addSemicolonToQueryString(&$query)
|
|
{
|
|
$query = rtrim($query);
|
|
|
|
if (substr($query, -1) != ';') $query = "{$query};";
|
|
}
|
|
|
|
private function whereMakerPriv($where, &$paramValue = array())
|
|
{
|
|
if (!is_array($where)) return 1;
|
|
$back = '1 ';
|
|
foreach ($where as $key => $value) {
|
|
if (is_array($value)) {
|
|
$back .= 'AND `' . $key . '`' . $value[0] . '"' . $value[1] . '" ';
|
|
} else {
|
|
$back .= "AND `{$key}` = ? ";
|
|
array_push($paramValue, $value);
|
|
}
|
|
}
|
|
return $back;
|
|
}
|
|
|
|
private function isWriteType($sql)
|
|
{
|
|
if (!preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD DATA|COPY|ALTER|GRANT|REVOKE|LOCK|UNLOCK)\s+/i', $sql)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public function getQueryString()
|
|
{
|
|
return $this->queryString;
|
|
}
|
|
public function getQueryResult()
|
|
{
|
|
return $this->queryResult;
|
|
}
|
|
}
|