MacCMS 源码安全审计报告
本页是对本仓库 MacCMS V10 源码(框架为 ThinkPHP 5.0.24)做的一次只读安全审计记录。目标有三个:排查是否存在后门 / webshell、复核历史上影响巨大的 ThinkPHP5 远程命令执行(RCE,Remote Code Execution)漏洞是否已打补丁、并把需要站长手动做的加固项整理出来。
审计元信息(审计的是哪个版本)
安全审计结论只对特定版本的源码成立。下面列清本次审计对应的版本坐标,你应当拿它和自己手上的源码比对,一致才能直接套用本页结论。
| 项目 | 值 |
|---|---|
| 审计日期 | 2026-10-12 |
| 上游仓库 | github.com/magicblack/maccms10(https://github.com/magicblack/maccms10.git) |
程序版本号(code) | 2026.1000.4056(取自 application/extra/version.php) |
升级指纹(update_hash) | 4d95c1cdb0133a17a4e482c72aff430d(同文件,可作版本比对的辅助指纹) |
| 框架版本 | ThinkPHP 5.0.24(thinkphp/base.php 的 THINK_VERSION) |
Git master HEAD | a468b6236c1e028b1aca3f91f463345cf72f16c7 |
审计口径
审计阅读源码,对每个命中的「危险特征」都结合上下文做了人工判读,分成三档:合法(框架/业务正常用法)、可疑(需要关注的攻击面)、恶意(真实后门)。结论:本次审计范围内未发现恶意后门。下文把扫描范围、命中点和判定逐条列清楚,方便你自行复核。
一、审计范围与方法
扫描对象是整套源码,按风险优先级覆盖:
- 入口与安装:
index.php、admin.php、api.php、install.php、application/install/ - 插件(第三方代码重点看):
addons/下的adminloginbg、aicontent、mpt、socialws - 可写 / 上传面:
upload/、runtime/、static/、template/ - 第三方库:
vendor/、extend/、thinkphp/ - 业务代码:
application/admin、application/api、application/index、application/common - 配置:
application/config.php、application/route.php、application/extra/*.php
方法是按一份危险特征清单做全仓匹配,命中后逐条看上下文判定:
- 代码执行:
eval、assert、create_function、call_user_func(_array)、动态可变函数$a($b) - 编解码混淆:
base64_decode、gzinflate、gzuncompress、gzdecode、str_rot13、strrev,尤其是多层嵌套(如eval(gzinflate(base64_decode(...)))) - 命令执行:
system、exec、shell_exec、passthru、popen、proc_open、反引号 - 输入直达危险函数:
$_GET/$_POST/$_REQUEST/$_COOKIE/php://input直接拼进上述函数 - 正则后门:
preg_replace带/e修饰符 - 落地写马:
file_put_contents/fwrite写.php、move_uploaded_file到可执行目录 - 远程回连:
fsockopen/ 远程fopen/curl与编解码组合
二、后门 / Webshell 排查结论
结论:未发现后门或 webshell。 所有命中的危险特征都能对应到框架或业务的正常用途。下面是逐类判定。
代码执行类(eval / assert / create_function)—— 判定:合法
| 位置 | 用途 | 判定 |
|---|---|---|
thinkphp/library/think/view/driver/Php.php | 原生 PHP 模板驱动,eval('?>' . $this->content) 渲染磁盘上的模板文件内容,不是请求参数 | 合法(框架模板引擎标准实现) |
application/common/util/Dir.php | create_function 生成目录排序回调(固定逻辑,无外部输入) | 合法 |
application/common/util/PclZip.php | 多处 eval(...) 全部在注释里(// 开头),实际走的是普通可变函数调用 | 合法(第三方 zip 库) |
application/common/util/SlidingWindowIpLimiter.php | $handler->eval(...) 是 Redis 的 EVAL 命令(执行 Lua 限流脚本),不是 PHP eval | 合法 |
关于模板引擎的 eval
eval('?>' . $this->content) 看着吓人,但它执行的是模板文件内容,和所有 PHP 模板引擎(本质都是 include 或 eval 模板)一样。只要后台模板不被攻击者篡改、不允许上传 .php 到模板目录,它就不是风险点。真正要防的是「别让人往模板目录写文件」,这归入下文的权限收紧。
命令执行类(shell_exec / proc_open 等)—— 判定:合法
| 位置 | 用途 | 判定 |
|---|---|---|
application/admin/controller/Index.php | 后台仪表盘取 CPU / 内存占用,命令是写死的(wmic、free、top、sysctl),无任何用户输入拼接 | 合法(仅后台可触发) |
application/common/util/OpenccConverter.php | 调用 opencc 二进制做简繁转换,命令固定 | 合法 |
thinkphp/library/think/console/output/Ask.php、Console.php | 命令行交互(stty、mode CON),只在 CLI 下跑 | 合法(框架 console) |
thinkphp/library/think/Process.php | 框架 Process 组件封装 proc_open | 合法 |
编解码类(base64_decode)—— 判定:合法
全仓的 base64_decode 没有一处和 eval / 命令执行组合,没有多层嵌套混淆。典型用途:
application/common/model/Collect.php多处base64_decode($param['param']):解码采集附加查询串,解码后拼进采集 URL 并交给checkCjUrl()做 SSRF 校验。这是采集功能的正常参数解码,不是后门。Update.php/Safety.php/common.php/Addon.php里的 base64 是被编码的普通字符串,解码后分别是官方更新地址https://update.maccms.la/、静态接口域名http://api.dplayerstatic.com、「预留功能」字样、以及一段版权说明(指向官方仓库github.com/magicblack)。属于轻度字符串混淆,解码值均为 URL 或文案,不含任何可执行代码。application/common/util/下的JwtService、SensitiveDataCrypto、AddonSecureInstaller、AddonCloudService、PushDispatcher等:base64 用于 JWT、加解密、签名校验,标准用法。
正则后门 / 输入直达 / 落地写马 —— 判定:均未命中
preg_replace /e:未发现带/e修饰符的preg_replace(命中的几处正则不含/e,是普通字符串替换)。- 输入直达危险函数:未发现
eval($_POST[...])、system($_GET[...])、$可变函数($_REQUEST[...])这类把请求输入直接喂给危险函数的写法。 php://input:命中点都是正常用途——微信 / 支付异步回调验签(且WechatPublic.php还显式libxml_disable_entity_loader(true)防 XXE)、JSON 请求体解析、框架自身的 input 捕获。- 落地写
.php:只有两处——install/controller/Index.php安装时写database.php(受 install.lock 控制)、路由缓存命令写runtime/route.php(框架优化)。均无外部可控内容写入可执行路径。 move_uploaded_file/fsockopen:业务代码里未命中,上传走的是框架think\File组件(带类型 / 大小 / 扩展名校验)。
第三方插件(addons)—— 判定:合法
四个插件 adminloginbg、aicontent、mpt、socialws 均通读过。风险最高的 socialws(常驻 WebSocket 服务,依赖 workerman)代码质量反而很规范:握手用 Cookie 还原 uid 时查库校验 user_check,用 PDO 预处理语句 + hash_equals 做常量时间比较,并对常驻进程内存做了上界控制防 DoS。个人房间(user_<uid>)只允许本人订阅。属于考虑了安全的正常功能代码,不是后门。
三、ThinkPHP 5.0.24 RCE 补丁复核
历史上最有名的 ThinkPHP5 RCE 利用链形如:
?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami它靠在路由里塞 \think\app 这种带命名空间分隔符 \ 的「控制器名」,让框架实例化到 \think\App 并触达 invokefunction,从而执行任意函数。复核结论如下:
补丁已覆盖。 关键点在 thinkphp/library/think/App.php 的 module() 方法(约第 554 行),控制器名有正则白名单校验:
if (!preg_match('/^[A-Za-z](\w|\.)*$/', $controller)) {
throw new HttpException(404, 'controller not exists:' . $controller);
}- 该正则只允许「字母开头 + 字母 / 数字 / 下划线 / 点」的控制器名,命名空间分隔符
\直接被拒,所以\think\app这类 payload 会命中 404,进不去。 App::invokeFunction()虽然还在(约第 311 行),但只有case 'function'(开发者在路由里写的闭包)才会调它,无法再通过 URL 直达任意函数。THINK_VERSION在thinkphp/base.php中确认为5.0.24,正则补丁完整存在、未被改动。
此外复核了几个相关面:
Request::method()(Request.php约第 518 行):表单伪方法_method做了白名单限制(只接受GET/POST/DELETE/PUT/PATCH),HTTP_X_HTTP_METHOD_OVERRIDE为标准支持。Request::filterExp()(约第 1122 行):标准的 SQL 关键字过滤(EXP/NEQ/GT/.../IN),是 5.0.24 的正常实现,用于缓解方法覆盖类 SQL 注入。- 路由配置
application/route.php:只有正常的伪静态规则,映射到已知控制器(vod/art/actor/role/manga/live等),没有function闭包路由、也没有允许\think\直达的危险路由。 - 调试默认值
application/config.php:出厂即app_debug => false、app_trace => false,默认不泄露报错细节。
仍需站长手动做的事
补丁在框架层已覆盖经典 RCE,但 ThinkPHP 5.0.x 历史上还有数据库驱动 SQL 注入等 CVE。源码层无法替你拦住所有变体,建议在 Nginx / 云 WAF 再加一层特征拦截(见下)作为纵深防御。
四、加固建议(需站长手动执行)
这些都在源码之外,装完 / 升级后请逐条落实,详细操作见安全加固:
- 加 WAF / 拦截规则:在 Nginx 或云防火墙拦掉带
invokefunction、call_user_func_array、\think\特征的请求,作为 RCE 的纵深防御。 - 后台入口改名(强制):默认
admin.php会被源码强制拦截,必须改名后用新文件名访问。 - 关调试:生产环境确认
app_debug/app_trace为false。 - 收紧目录权限:只给
runtime、upload写权限,其余最小权限;禁止向模板目录写入.php,防止模板引擎eval被利用。 - 锁安装目录:安装后保留
install.lock,避免被触发重装。 - 及时升级:关注官方仓库 magicblack/maccms10 的安全公告,升级前备份数据库与配置。