此文章为XIUNOX版本重构审计时发现问题,XIUNOX版本已优化修复此问题。分享出来方便后续想基于xiuno bbs4.0.4版本制作维护版本或插件模板等需求的开发者和站长参考。
现象
Xiuno BBS 4.0.4 安装、卸载、升级、设置插件时,会直接 include _include(APP_PATH."plugin/$dir/install.php") 等插件自带脚本,且没有任何沙盒、签名校验、函数黑名单。插件作者可以在 install.php 中植入任意代码:删库、写马、读取 conf.php 中的数据库密码、向远程发送站点密钥。即便禁用插件,install.php 已经执行过一次,后门已落地。
源码证据
文件:xiunobbs_4.0.4/admin/route/plugin.php 第 155-175 行(安装时 include install.php)
} elseif($action == 'install') {
plugin_lock_start();
$dir = param_word(2);
plugin_check_exists($dir);
$name = $plugins[$dir]['name'];
// 插件依赖检查 / check plugin dependency
plugin_check_dependency($dir, 'install');
// 安装插件 / install plugin
plugin_install($dir);
$installfile = APP_PATH."plugin/$dir/install.php";
if(is_file($installfile)) {
include _include($installfile); // 直接 include 插件提供的 PHP,无沙盒
}
plugin_lock_end();
// ...
}
文件:xiunobbs_4.0.4/admin/route/plugin.php 第 203-223 行(卸载时 include unstall.php)
} elseif($action == 'unstall') {
// ...
plugin_unstall($dir);
$unstallfile = APP_PATH."plugin/$dir/unstall.php";
if(is_file($unstallfile)) {
include _include($unstallfile); // 同样无任何校验
}
// ...
}
文件:xiunobbs_4.0.4/admin/route/plugin.php 第 277-310 行(升级时 include upgrade.php)
} elseif($action == 'upgrade') {
// ...
plugin_install($dir);
$upgradefile = APP_PATH."plugin/$dir/upgrade.php";
if(is_file($upgradefile)) {
include _include($upgradefile); // 升级脚本任意执行
}
// ...
}
文件:xiunobbs_4.0.4/admin/route/plugin.php 第 317-324 行(设置页 include setting.php)
} elseif($action == 'setting') {
$dir = param_word(2);
plugin_check_exists($dir);
$name = $plugins[$dir]['name'];
include _include(APP_PATH."plugin/$dir/setting.php"); // 设置页任意 PHP 执行
}
文件:xiunobbs_4.0.4/admin/route/plugin.php 第 388-434 行(plugin_download_unzip 直接解压到 plugin/ 目录,无签名)
function plugin_download_unzip($dir) {
global $conf;
// ...
$url = PLUGIN_OFFICIAL_URL."plugin-download-$dir-$siteid-$app_url.htm";
$s = http_get($url);
// ...
$zipfile = $conf['tmp_path'].'plugin_'.$dir.'.zip';
$destpath = APP_PATH."plugin/";
file_put_contents($zipfile, $s);
// 清理原来的钩子,防止叠加。
rmdir_recusive(APP_PATH."plugin/$dir/hook/", 1);
rmdir_recusive(APP_PATH."plugin/$dir/overwrite/", 1);
// 直接覆盖原来的 plugin 目录下的插件目录
xn_unzip($zipfile, $destpath); // 解压即落地,install.php 即可被 include
// ...
}
风险等级与结论
风险等级:严重(Critical)|生态缺陷
危害:
- 安装任意插件 = 执行任意 PHP,无沙盒、无签名、无函数黑名单。
- install.php 可读取
conf/conf.php中的 DB 密码、auth_key,外传给攻击者。 - install.php 可写文件到
upload/、tmp/、view/,植入持久化 webshell。 - 官方源
plugin.xiuno.com已失效(见独立缺陷),用户被迫从第三方下载,供应链攻击面巨大。 - 即便用户事后禁用、卸载插件,install.php 已执行过的副作用(删表、改密码、写马)无法回滚。
修复建议:
- 引入插件签名机制:插件包必须附
conf.json.sig(Ed25519),plugin_download_unzip解压后立即校验签名,不匹配则拒绝安装。 - install/unstall/upgrade/setting.php 在受限沙盒中执行:禁用
exec/system/eval/file_put_contents/unlink/mysql_query等危险函数(通过disable_functionsini 临时注入)。 - 限制 install.php 只能调用 BBS 提供的
plugin_install_hook()API 完成数据库变更,禁止直接 SQL。 - 安装前展示 install.php 源码摘要给管理员审阅,并扫描危险关键字(
eval、exec、file_put_contents、fopen、mysql、$_POST、$_GET、base64_decode)。 - 强制 install.php 通过
_include()编译时附加前缀防直接访问,但执行前去除(已有此机制,但仅对 hook 生效,install.php 未应用)。