此文章为XIUNOX版本重构审计时发现问题,XIUNOX版本已优化修复此问题。分享出来方便后续想基于xiuno bbs4.0.4版本制作维护版本或插件模板等需求的开发者和站长参考。
现象
Xiuno BBS 4.0.4 的模板文件(view/htm/*.htm)并非纯模板语言,而是直接包含 <?php ?> 代码块。模板经 _include() 编译后被原样写入 tmp/ 目录并作为 PHP 文件被 include,意味着:
- 主题(
_theme_* 插件)可携带任意 PHP 代码,安装即获得代码执行。
- 模板中的 PHP 与 HTML 强耦合,无法做语法隔离、沙盒、变量过滤。
- 主题作者可轻易在 header.inc.htm 中植入
eval($_POST['x']) 等后门。
- 老主题(继承自 3.0 / 4.0 早期)大量混用
<?php foreach ?> <?php echo ?> <?php include _include(...) ?>,可读性差且易引入 XSS 与 RCE。
源码证据
文件:xiunobbs_4.0.4/view/htm/post_list.inc.htm(头部片段)
<?php
if($postlist) { foreach($postlist as $_post) { ?>
<li class="media <?php echo $_post['classname'];?>" data-pid="<?php echo $_post['pid'];?>" data-uid="<?php echo $_post['uid'];?>">
<a href="<?php echo url("user-$_post[uid]");?>" class="mr-3" tabindex="-1">
<img class="avatar-3" src="<?php echo $_post['user_avatar_url'];?>">
文件:xiunobbs_4.0.4/view/htm/thread.htm(第 1 行 / 第 101 行)
<?php include _include(APP_PATH.'view/htm/header.inc.htm');?>
...
<?php include _include(APP_PATH.'view/htm/post_list.inc.htm'); ?>
文件:xiunobbs_4.0.4/model/plugin.func.php 第 15-37 行 —— 编译产物直接以 PHP 文件形式被 include
function _include($srcfile) {
global $conf;
$len = strlen(APP_PATH);
$tmpfile = $conf['tmp_path'].substr(str_replace('/', '_', $srcfile), $len);
if(!is_file($tmpfile) || DEBUG > 1) {
$s = plugin_compile_srcfile($srcfile);
file_put_contents_try($tmpfile, $s);
$s = plugin_compile_srcfile($tmpfile);
file_put_contents_try($tmpfile, $s);
}
return $tmpfile;
}
调用方(xiunobbs_4.0.4/index.php 第 51-52 行)直接 include _include(...):
include _include(APP_PATH.'model.inc.php');
include _include(APP_PATH.'index.inc.php');
风险等级与结论
风险等级:高(High)|生态缺陷
危害:
- 主题/插件可携带任意 PHP,无沙盒、无 opcode 限制、无函数黑名单。
- 模板与业务逻辑深度耦合,老主题升级困难,新主题作者容易引入安全漏洞。
_include() 把模板编译为 .htm 后缀文件再 include,但内容是 PHP,存在被直接访问 tmp/xxx.htm 暴露源码的风险(取决于服务器配置)。
- 模板中大量
<?php echo $xxx ?> 没有统一转义函数,XSS 风险随主题扩散。
修复建议:
- 引入模板引擎(如 Twig/Plates),禁止模板中直接出现
<?php ?>。
- 至少提供
xn_escape() / e() 等统一转义函数,并在核心模板中替换裸 echo。
- 对主题/插件上传做 PHP 关键字扫描(
eval、system、exec、shell_exec、passthru、preg_replace /e、assert、create_function),命中即拒绝安装。
tmp/ 目录配置 .htaccess/nginx 规则禁止直接访问 .htm .php 文件。
- 长期方案:将模板后缀改为
.tpl.php 并强制 exit; 前缀防直接访问。