问题:后台用户搜索将用户输入作为 LIKE/精确条件拼接进 SQL,依赖 addslashes 防注入
现象
后台 admin/route/user.php 的用户搜索接口将用户从 URL 接收的 $keyword 直接作为查询条件,通过 $cond[$srchtype] = $keyword 写入条件数组后交给 db_find() → db_cond_to_sqladd() 拼接 SQL。该流程最终仅靠 addslashes() 进行转义,未做参数预处理。在 GBK/多字节字符集场景下可被宽字节绕过;同时 LIKE 条件未对 %、_ 进行转义,存在 LIKE 注入导致全表遍历和性能 DoS。
$srchtype 虽然做了 in_array($srchtype, $allowtype) 白名单校验,但 $keyword 本身未做任何字符校验,且 $srchtype 同样来自 param(2)(默认 htmlspecialchars),最终被用作列名拼接 `"$srchtype"`=...,若白名单逻辑被插件修改可导致列名注入。
源码证据
文件:xiunobbs_4.0.4/admin/route/user.php 行 14-35(接收用户搜索关键词并写入 cond 数组)
$pagesize = 20;$srchtype = param(2);$keyword = trim(xn_urldecode(param(3)));$page = param(4, 1);$cond = array();$allowtype = array('uid', 'username', 'email', 'gid', 'create_ip');if($keyword) { !in_array($srchtype, $allowtype) AND $srchtype = 'uid'; $cond[$srchtype] = $srchtype == 'create_ip' ? ip2long($keyword) : $keyword; }$n = user_count($cond);$userlist = user_find($cond, array('uid'=>-1), $page, $pagesize);$pagination = pagination(url("user-list-$srchtype-".urlencode($keyword).'-{page}'), $n, $page, $pagesize);Php 代码解读复制代码
文件:xiunobbs_4.0.4/xiunophp/db.func.php 行 242-279(条件拼接最终走 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])) { // ... } 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;}Php 代码解读复制代码
文件:xiunobbs_4.0.4/route/thread.php 行 85 + 117(前台关键词搜索同样将 $keyword 传入 LIKE 条件)
$tid = param(1, 0);$page = param(2, 1);$keyword = param(3);// ...if($keyword) { $thread['subject'] = post_highlight_keyword($thread['subject'], $keyword); $keywordurl = "-$keyword";}Php 代码解读复制代码
文件:xiunobbs_4.0.4/model/thread.func.php 行 290-292(关键词搜索最终调用 db_find + LIKE 条件)
function thread_find_by_keyword($keyword) { $threadlist = db_find('thread', array('subject'=>array('LIKE'=>$keyword)), array(), 1, 60); // ...}Php 代码解读复制代码
文件:xiunobbs_4.0.4/admin/route/thread.php 行 64-66(后台主题扫描关键词同样未校验)
$userip = param('userip');$cond['userip'] = $userip ? ip2long($userip) : 0;$cond['keyword'] = param('keyword');Php 代码解读复制代码
风险等级与结论
高危
危害后果:
- 在 GBK 等多字节字符集环境下,
$keyword通过addslashes后仍可被宽字节绕过,导致后台 SQL 注入。后台注入因管理员权限高,可直接写马提权至服务器 RCE。 LIKE查询未对%、_转义,攻击者可提交%触发全表 LIKE 扫描,对大表造成严重性能 DoS。- 列名
$srchtype通过`"$srchtype"`直接拼接,白名单虽限制了 5 种字段,但任何对白名单的修改(如插件 hook)都会立即转为列名注入点。 - 攻击面:后台接口需管理员登录,但配合 CSRF 缺陷(参见另案)可在管理员不知情的情况下被外部触发。
修复建议:
- 将所有
db_cond_to_sqladd调用改为 PDOprepare()+bindValue(),参数化绑定彻底消除注入。 - LIKE 查询对
$keyword中的%、_、\调用addcslashes($keyword, '%_\\')转义,避免通配符注入。 - 列名
$srchtype用严格的 switch-case 映射到固定字符串,禁止直接用用户输入做列名拼接。 - 强制
utf8mb4字符集连接,关闭PDO::ATTR_EMULATE_PREPARES,杜绝宽字节注入温床。