此文章为XIUNOX版本重构审计时发现问题,分享出来方便后续想基于xiuno bbs4.0.4版本制作维护版本或插件模板等需求的开发者和站长参考。
Xiuno BBS 4.0.4 的数据库抽象层在拼接 SQL 时统一使用 PHP 内置 addslashes() 对字符串值进行转义,并未使用 PDO 预编译语句(prepare + bind)。该转义方式存在以下风险:
%bf%27 形式的宽字节序列,使 addslashes 添加的反斜杠被前一个字节“吞掉”,从而绕过转义形成 SQL 注入。addslashes 与 mysql_real_escape_string 行为不一致,对部分特殊字符(如 \x00、\n、\r、\x1a)处理不当,存在边缘绕过场景。db_mysql.class.php 使用 PHP 7.0 已移除的 mysql_* 扩展,无法设置连接字符集到 mysql_set_charset,只能用 SET NAMES,导致 addslashes 与 server 端字符集认知不一致,是宽字节注入的典型温床。文件:xiunobbs_4.0.4/xiunophp/db.func.php 行 242-279(db_cond_to_sqladd 使用 addslashes)
function db_cond_to_sqladd($cond) {
$s = '';
if(!empty($cond)) {
$s = ' WHERE ';
foreach($cond as $k=>$v) {
if(!is_array($v)) {
$v = (is_int($v) || is_float($v)) ? $v : "'".addslashes($v)."'";
$s .= "`$k`=$v AND ";
} elseif(isset($v[0])) {
// OR 效率比 IN 高
$s .= '(';
foreach ($v as $v1) {
$v1 = (is_int($v1) || is_float($v1)) ? $v1 : "'".addslashes($v1)."'";
$s .= "`$k`=$v1 OR ";
}
// ...
} else {
foreach($v as $k1=>$v1) {
if($k1 == 'LIKE') {
$k1 = ' LIKE ';
$v1="%$v1%";
}
$v1 = (is_int($v1) || is_float($v1)) ? $v1 : "'".addslashes($v1)."'";
$s .= "`$k`$k1$v1 AND ";
}
}
}
}
return $s;
}文件:xiunobbs_4.0.4/xiunophp/db.func.php 行 303-342(insert/update 拼 SQL 也用 addslashes)
function db_array_to_update_sqladd($arr) {
$s = '';
foreach($arr as $k=>$v) {
$v = addslashes($v);
// ...
$v = (is_int($v) || is_float($v)) ? $v : "'$v'";
$s .= "`$k`=$v,";
}
return substr($s, 0, -1);
}
function db_array_to_insert_sqladd($arr) {
// ...
foreach($arr as $k=>$v) {
$k = addslashes($k);
$v = addslashes($v);
$keys[] = '`'.$k.'`';
$v = (is_int($v) || is_float($v)) ? $v : "'$v'";
$values[] = $v;
}
// ...
}文件:xiunobbs_4.0.4/xiunophp/db_mysql.class.php 行 52-58(使用废弃 mysql_* 扩展,且 SET NAMES 设置字符集)
public function real_connect($host, $user, $password, $name, $charset = '', $engine = '') {
$link = @mysql_connect($host, $user, $password);
if(!$link) { $this->error(mysql_errno(), '连接数据库服务器失败:'.mysql_error()); return FALSE; }
if(!mysql_select_db($name, $link)) { $this->error(mysql_errno(), '选择数据库失败:'.mysql_error()); return FALSE; }
$charset AND $this->query("SET names $charset, sql_mode=''", $link);
return $link;
}文件:xiunobbs_4.0.4/xiunophp/db_pdo_mysql.class.php 行 114-128(虽然使用 PDO,但 query/exec 均直接拼接 SQL 字符串,未使用 prepare/execute)
public function query($sql) {
if(!$this->rlink && !$this->connect_slave()) return FALSE;
$link = $this->link = $this->rlink;
try {
$t1 = microtime(1);
$query = $link->query($sql); // 直接 query,未 prepare
$t2 = microtime(1);
} catch (Exception $e) {
$this->error($e->getCode(), $e->getMessage());
return FALSE;
}
// ...
}
public function exec($sql) {
// ...
$n = $link->exec($sql); // 直接 exec,未 prepare
// ...
}高危
危害后果:
addslashes 转义不如 mysql_real_escape_string 严谨,对部分字符处理存在差异,存在边缘绕过风险。db_mysql.class.php 依赖 PHP 5.x 的 mysql_* 扩展,在 PHP 7+ 环境下直接不可用,且无法使用 mysql_set_charset 同步字符集认知,进一步放大宽字节注入风险。修复建议:
prepare() + bindParam()/bindValue(),禁止再使用字符串拼接 + addslashes。PDO::ATTR_EMULATE_PREPARES => false 关闭模拟预处理,确保语句真正由 server 端编译。utf8 或 utf8mb4 字符集,并通过 mysql_set_charset/PDO::query("SET NAMES utf8mb4") 显式同步 client/server 字符集认知。db_mysql.class.php 中 mysql_* 扩展支持,统一使用 db_pdo_mysql.class.php。原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。