问题:后台所有操作无 CSRF Token 校验
此文章为XIUNOX版本重构审计时发现问题,分享出来方便后续想基于xiuno bbs4.0.4版本制作维护版本或插件模板等需求的开发者和站长参考。
现象
Xiuno BBS 4.0.4 后台鉴权仅依赖bbs_admin_tokenCookie,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_tokenCookie 未设SameSite属性(见 Cookie 安全审计),浏览器默认不会拦截跨站请求携带 Cookie,CSRF 可直接生效。 - 影响面覆盖后台全部功能:增删管理员、改配置、安装/卸载插件(含
include install.php→ RCE)、删帖删版块。 - 修复建议:在
admin_token_check()中对非 GET 请求强制校验请求体内的 CSRF Token(-session 绑定、一次性 token);校验Origin/Referer头;Cookie 设置SameSite=Lax/Strict;敏感操作(插件安装、配置修改)追加二次密码确认。