先检查响应头或HTML中是否有ThinkPHP标识,再发GET /index.php?s=/think\app/invokefunction试探;若返回class not found: think\app等错误而非404,说明是未修复的ThinkPHP 5.0.x,存在RCE风险。

怎么确认目标用了 ThinkPHP 5.0.x 且可能有 RCE?
先看响应头或 HTML 源码里有没有 ThinkPHP、Powered by ThinkPHP,再抓一个请求看是否返回 index.php?s= 这类典型路由参数。更可靠的是发个试探性请求:GET /index.php?s=/think\app/invokefunction,如果返回 class not found: think\app 或直接报错(而非 404),说明框架在解析反斜杠命名空间,大概率是未修复的 5.0.x。
为什么 _method=__construct 能触发 RCE?
这个利用链依赖于 Request::method() 方法对 $_POST['_method'] 的不安全处理。当传入 __construct 时,框架会把后续 POST 参数当作构造函数参数注入到 Request 实例中,其中 filter 属性可被覆盖为 assert 或 system 等危险函数。
- 必须使用 POST 请求,且 Content-Type 为
application/x-www-form-urlencoded -
filter[]是数组,得写成filter[]=assert,单值写法(如filter=assert)在 5.0.22 前无效 -
server[REQUEST_METHOD]是最终执行点,内容会被assert()直接求值,所以传phpinfo()或file_put_contents('x.php','=$_POST[1]?>')都能成功
invokefunction 路由方式和 _method 方式有什么区别?
前者走 URL 路由解析,后者走表单参数注入,触发路径不同但危害相当。前者要求 URL 中包含 /think\app/invokefunction,利用 call_user_func_array 直接触发函数调用;后者则依赖 Request 类的构造逻辑缺陷,更隐蔽也更常出现在表单提交场景。
-
invokefunction方式不需要 POST 数据,纯 GET 即可,例如:/index.php?s=/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id -
_method方式必须 POST,且需确保Config::get('var_method')返回的是_method(默认值),否则参数名不匹配就失败 - 5.0.23+ 版本已禁用
invokefunction路由,但若手动开启或降级配置,仍可能生效
修复后为什么还会漏掉某些利用变体?
补丁只堵住了已知入口,比如限制 method() 中的 HTTP 方法白名单,或过滤 invokefunction 路由,但没动底层反射机制或动态函数调用逻辑。一旦开发者自己写了类似 call_user_func($_GET['func']) 或用 eval(base64_decode($_POST['data'])),漏洞就绕过所有框架补丁。
立即学习“PHP免费学习笔记(深入)”;
真正容易被忽略的是:业务代码里对 $_REQUEST、$_GET、$_POST 的直接拼接,哪怕框架升级了,只要存在 assert($_REQUEST['x']) 或 preg_replace('/.*/e', $_GET['p'], ''),RCE 就依然成立。



















