问题:install/index.php 中 CREATE DATABASE 语句直接拼接用户输入,存在 SQL 注入
此文章为XIUNOX版本重构审计时发现问题,分享出来方便后续想基于xiuno bbs4.0.4版本制作维护版本或插件模板等需求的开发者和站长参考。
现象
安装脚本 install/index.php 在初始化数据库时,将用户从 POST 表单提交的数据库名 $name、数据库用户 $user 等参数直接拼接进 CREATE DATABASE SQL 语句并执行。param('name') 默认只做 htmlspecialchars 处理(不会转义单引号),未做 addslashes 或预处理,攻击者可在数据库名中注入单引号及后续 SQL 语句,导致任意 SQL 执行。
安装脚本位于 install/ 目录,根据另案审计结论该目录在安装完成后并未被自动清理,且 DEBUG == 2 时跳过 conf.php 已存在的检测,意味着该注入入口在已部署站点上仍可被远程访问,构成实际可达攻击面。
源码证据
文件:xiunobbs_4.0.4/install/index.php 行 92-102(接收用户提交的数据库连接参数)
$type = param('type');
$engine = param('engine');
$host = param('host');
$name = param('name');
$user = param('user');
$password = param('password');
$force = param('force');
$adminemail = param('adminemail');
$adminuser = param('adminuser');
$adminpass = param('adminpass');
文件:xiunobbs_4.0.4/install/index.php 行 133-152(直接拼接 SQL 执行 CREATE DATABASE)
if($errno == 1049 || $errno == 1045) {
if($type == 'mysql') {
mysql_query("CREATE DATABASE $name");
$r = db_connect($db);
} elseif($type == 'pdo_mysql') {
if(strpos(':', $host) !== FALSE) {
$arr = explode(':', $host);
$host = $arr[0];
$port = $arr[1];
} else {
$port = 3306;
}
try {
$attr = array(
PDO::ATTR_TIMEOUT => 5,
);
$link = new PDO("mysql:host=$host;port=$port", $user, $password, $attr);
$r = $link->exec("CREATE DATABASE `$name`");
文件:xiunobbs_4.0.4/xiunophp/misc.func.php 行 73-84(param 默认仅做 htmlspecialchars,不转义单引号)
function param($key, $defval = '', $htmlspecialchars = TRUE, $addslashes = FALSE) {
if(!isset($_REQUEST[$key]) || ($key === 0 && empty($_REQUEST[$key]))) {
}
$val = $_REQUEST[$key];
$val = param_force($val, $defval, $htmlspecialchars, $addslashes);
return $val;
}
文件:xiunobbs_4.0.4/install/index.php 行 29(已安装检测在 DEBUG==2 时被绕过)
is_file(APP_PATH.'conf/conf.php') AND DEBUG != 2 AND message(0, jump(lang('installed_tips'), '../'));
文件:xiunobbs_4.0.4/install/index.php 行 3(DEBUG 在本文件内被硬编码为 2)
define('DEBUG', 2);
风险等级与结论
高危
危害后果:
- 攻击者构造
name=x'; SELECT ...; -- 或 name=x; DROP DATABASE bbs; --` 形式的数据库名,可在安装请求中执行任意 SQL,包括创建恶意表、写入 webshell 到文件、提权到数据库 root 等。
- 由于
install/index.php 自身 define('DEBUG', 2),绕过了已安装检测,使得即使站点已完成安装,该注入入口依旧可达。
- 攻击者无需任何鉴权即可访问
install/index.php,配合上一条等于无门槛 RCE 入口。
修复建议:
install/index.php 接收的 $name、$user、$host、$port 等参数需用白名单正则 ^[a-zA-Z0-9_\-\.]+$ 严格校验后再拼接。
- CREATE DATABASE 语句改为 PDO prepare:
$link->prepare("CREATE DATABASE \?`")->execute([$name])`(注意 PDO 对 DDL 支持有限,更稳妥是白名单校验)。
- 安装脚本完成后强制删除
install/ 目录或写入 .lock 文件,所有请求检测到锁文件即 exit('Access Denied')。
- 移除
define('DEBUG', 2) 与已安装检测中 DEBUG != 2 的旁路条件,安装完成后无条件拒绝访问。
- 安装脚本独立鉴权(如安装令牌),禁止任意匿名访问。