Xiuno BBS 审计之问题05:数据库存在宽字节注入与转义绕过
贰先生 5小时前

问题:DB 抽象层使用 addslashes 转义而非 PDO 预处理,存在宽字节注入与转义绕过

此文章为XIUNOX版本重构审计时发现问题,分享出来方便后续想基于xiuno bbs4.0.4版本制作维护版本或插件模板等需求的开发者和站长参考。

现象

Xiuno BBS 4.0.4 的数据库抽象层在拼接 SQL 时统一使用 PHP 内置 addslashes() 对字符串值进行转义,并未使用 PDO 预编译语句(prepare + bind)。该转义方式存在以下风险:

  1. 当 MySQL 连接字符集为 GBK/GB2312/BIG5 等多字节字符集时,攻击者可构造 %bf%27 形式的宽字节序列,使 addslashes 添加的反斜杠被前一个字节“吞掉”,从而绕过转义形成 SQL 注入。
  2. addslashes  mysql_real_escape_string 行为不一致,对部分特殊字符(如 \x00\n\r\x1a)处理不当,存在边缘绕过场景。
  3. 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
    // ...
}

风险等级与结论

高危

危害后果:

  • 在 GBK/GB2312 等多字节字符集环境下,攻击者可通过宽字节注入绕过转义,对任意 SQL 语句进行注入,导致拖库、写马、提权、绕过登录。
  • addslashes 转义不如 mysql_real_escape_string 严谨,对部分字符处理存在差异,存在边缘绕过风险。
  • db_mysql.class.php 依赖 PHP 5.x 的 mysql_* 扩展,在 PHP 7+ 环境下直接不可用,且无法使用 mysql_set_charset 同步字符集认知,进一步放大宽字节注入风险。
  • 即使使用 PDO 驱动,也并未启用预处理,无法享受 PDO 参数绑定的安全优势。

修复建议:

  1. 全面切换到 PDO 预编译语句 prepare() + bindParam()/bindValue(),禁止再使用字符串拼接 + addslashes
  2. 在连接时通过 PDO::ATTR_EMULATE_PREPARES => false 关闭模拟预处理,确保语句真正由 server 端编译。
  3. 强制使用 utf8  utf8mb4 字符集,并通过 mysql_set_charset/PDO::query("SET NAMES utf8mb4") 显式同步 client/server 字符集认知。
  4. 移除 db_mysql.class.php  mysql_* 扩展支持,统一使用 db_pdo_mysql.class.php
  5. 对所有进入 SQL 的字段做白名单校验(如表名、列名),数值做 intval 强转。
最新回复 (0)
全部楼主
返回