此文章为XIUNOX版本重构审计时发现问题,分享出来方便后续想基于xiuno bbs4.0.4版本制作维护版本或插件模板等需求的开发者和站长参考。
现象
Xiuno BBS 4.0.4 后台鉴权仅依赖 bbs_admin_token Cookie,admin_token_check() 只校验该 Cookie 是否能被 xn_decrypt 解密且未过期,全程不校验任何 CSRF Token(既不校验请求体中的 token 字段,也不校验 Origin/Referer 头)。这意味着攻击者只需诱导已登录管理员访问恶意页面,即可通过跨站请求伪造触发后台任意写操作:增删管理员、修改站点配置、上传/安装插件、清空数据库等。
后台 admin/route/*.php 中所有 POST 分支均未调用任何 token 校验函数,admin_token_check() 是唯一的鉴权入口,且其内部不含任何 anti-CSRF 机制。
源码证据
证据 1:后台鉴权函数仅校验 Cookie,无 CSRF Token 文件:xiunobbs_4.0.4/admin/admin.func.php 行 8-45
function admin_token_check() {
global $longip, $time, $useragent, $conf;
$useragent_md5 = md5($useragent);
//$key = md5($longip.$useragent_md5.$conf['auth_key']); // 有些环境是动态 IP
$key = md5((XN_ADMIN_BIND_IP ? $longip : '').$useragent_md5.xn_key());
// hook admin_token_check_start.php
$admin_token = param('bbs_admin_token');
if(empty($admin_token)) {
$_REQUEST[0] = 'index';
$_REQUEST[1] = 'login';
} else {
$s = xn_decrypt($admin_token, $key);
if(empty($s)) {
setcookie('bbs_admin_token', '', 0, '', '', '', TRUE);
message(-1, lang('admin_token_expiry'));
}
list($_ip, $_time) = explode("\t", $s);
// 后台超过 3600 自动退出。
if((XN_ADMIN_BIND_IP && $_ip != $longip || !XN_ADMIN_BIND_IP) && $time - $_time > 3600) {
setcookie('bbs_admin_token', '', 0, '', '', '', TRUE);
message(-1, lang('admin_token_expiry'));
}
// 超过半小时,重新发新令牌,防止过期
if($time - $_time > 1800) {
admin_token_set();
}
}
}
第 17 行:$admin_token = param('bbs_admin_token'); 仅从 Cookie 取 token,无任何 POST/GET token 字段校验,无 Referer/Origin 校验。默认 XN_ADMIN_BIND_IP 为空(行 6),IP 绑定不生效,CSRF 不受 IP 限制。
证据 2:后台 POST 操作均无 token 校验(示例) 文件:xiunobbs_4.0.4/admin/route/index.php 行 21-40
} else if($method == 'POST') {
// hook admin_index_login_post_start.php
$password = param('password');
if(md5($password.$user['salt']) != $user['password']) {
xn_log('password error. uid:'.$user['uid'].' - ******'.substr($password, -6), 'admin_login_error');
message('password', lang('password_incorrect'));
}
admin_token_set();
xn_log('login successed. uid:'.$user['uid'], 'admin_login');
message(0, jump(lang('login_successfully'), '.'));
}
登录 POST 不校验 token。其余后台路由(admin/route/setting.php、admin/route/user.php、admin/route/forum.php、admin/route/plugin.php 等)的 POST 分支同样仅依赖 admin_token_check(),无独立 token 校验。
证据 3:插件安装/卸载等高危操作无 token 文件:xiunobbs_4.0.4/admin/route/plugin.php 行 155-201
} elseif($action == 'install') {
plugin_lock_start();
$dir = param_word(2);
plugin_check_exists($dir);
$name = $plugins[$dir]['name'];
plugin_check_dependency($dir, 'install');
plugin_install($dir);
$installfile = APP_PATH."plugin/$dir/install.php";
if(is_file($installfile)) {
include _include($installfile);
}
plugin_lock_end();
// ...
$msg = lang('plugin_install_sucessfully', array('name'=>$name));
message(0, jump($msg, http_referer(), 3));
}
插件安装会 include 插件目录下的 install.php(第 173-175 行),属极高危操作,但全程无 CSRF Token。攻击者构造 <img src="http://victim/admin/plugin-install-恶意插件"> 即可诱导管理员访问时自动安装含恶意 install.php 的插件,实现 RCE。
风险等级与结论
风险等级:高危
结论:
- 后台所有 POST 操作无 CSRF Token,鉴权仅靠 Cookie,构成完整的 CSRF 漏洞。
- 结合
bbs_admin_token Cookie 未设 SameSite 属性(见 Cookie 安全审计),浏览器默认不会拦截跨站请求携带 Cookie,CSRF 可直接生效。
- 影响面覆盖后台全部功能:增删管理员、改配置、安装/卸载插件(含
include install.php → RCE)、删帖删版块。
- 修复建议:在
admin_token_check() 中对非 GET 请求强制校验请求体内的 CSRF Token(-session 绑定、一次性 token);校验 Origin/Referer 头;Cookie 设置 SameSite=Lax/Strict;敏感操作(插件安装、配置修改)追加二次密码确认。