thinkphp 5.0.21 存在多个高危rce漏洞,审计应聚焦入口文件→app::run()→路由解析→控制器调用主链,重点检查未校验的$path拆分、可控的call_user_func_array、method_exists动态调用及未过滤的invokefunction。

ThinkPHP 5.0.21 是一个已知存在多个高危 RCE 漏洞的版本(如未强制路由导致的控制器任意调用、invokeFunction 链路可被滥用等),学习它的代码审计,不是为了“复现漏洞炫技”,而是建立对框架核心机制与危险模式的敏感度。起点要准,路径要实。
从入口文件开始逆向追踪执行链
ThinkPHP 的请求生命周期非常清晰:public/index.php → thinkphp/start.php → App::run() → 路由解析 → 控制器调用。审计第一步就是顺这条主干走一遍。重点关注:
-
index.php中是否定义了APP_PATH、是否禁用了调试模式(APP_DEBUG=false) -
App::run()内部如何获取$request->path(),这个路径字符串是否未经校验就用于反射调用 -
routeCheck()方法里对?s=xxx参数的解析逻辑,尤其是模块/控制器/操作名的拆分是否依赖explode('/', $path)且未过滤点号、反斜杠、双冒号等字符
聚焦三类高危函数调用模式
ThinkPHP 5.0.x 的 RCE 多数围绕动态调用展开,遇到以下写法必须停下来细看:
-
call_user_func_array($func, $vars)—— 检查$func和$vars是否完全可控(如来自$_GET['function']和$_GET['vars']) -
method_exists($obj, $method) && $obj->$method(...)——$method是否来自用户输入且未白名单限制 -
think\app::invokeFunction()或think\app::invokeMethod()—— 这两个方法在 5.0.21 中默认开放,且参数未做深度过滤,是经典 POC 的触发点
对照已知漏洞补丁反推问题点
官方在 5.0.24 后修复了多个 RCE,你可以直接比对 thinkphp/library/think/App.php 的 diff:
- 5.0.21 中
invokeFunction()直接 unpack$vars并传入call_user_func_array - 5.0.24 中增加了
is_callable($function)校验,并对$vars做了类型约束(如仅允许数组、禁止对象) - 对
?s=路由参数的解析,后续版本加入了Loader::parseName()的规范化处理,过滤掉非法字符
看补丁,等于看到攻击面在哪里被堵住;反过来,就能理解原始代码中哪个变量是“没锁住的闸门”。
动手搭建最小验证环境快速验证假设
不用配完整项目,建一个极简测试入口:
// test.php
define('APP_PATH', __DIR__.'/application/');
require __DIR__.'/thinkphp/start.php';
然后用 curl 测试典型 payload:curl "http://localhost/test.php?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1"
如果返回 phpinfo 页面,说明环境可触发 —— 此时再打开 Xdebug 断点跟到 App.php 的 invokeFunction 方法内部,观察变量实际值和调用栈,比读十页文档更直观。
不复杂但容易忽略。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











