TP5.0控制器漏洞本质是路由解析失控导致的远程代码执行(RCE),核心在于未校验控制器名、方法名及参数;需从入口拦截、运行时加固、输入过滤三层面同步修复,包括白名单正则校验控制器、禁用空模块匹配、开启强制路由、限制危险方法参数、统一输入验证与环境隔离,并通过真实POC验证修复效果。

TP5.0控制器漏洞本质是路由解析失控导致的远程代码执行(RCE),核心风险在于未校验控制器名、方法名和参数内容。修复不能只打补丁,必须从入口拦截、运行时加固、输入过滤三层面同步落地。
堵死控制器名解析入口
攻击者常通过 /index.php?s=index/\think\app/invokefunction 这类路径直接调用框架底层方法。TP5.0默认允许任意字符串作为控制器名,且不校验命名规范。
- 在
think\App类的module()方法中,控制器赋值后立即加入白名单正则判断:if (!preg_match('/^[A-Za-z][\w.]*$/', $controller)) { throw new HttpException(404, 'controller not exists: ' . $controller); } - 禁用空模块/空操作自动匹配,在配置中显式设定默认模块与控制器,如
'DEFAULT_MODULE' => 'index',并移除MODULE_ALLOW_LIST等开放配置 - 若项目未启用强制路由,必须立即开启:
'url_route_on' => true,并定义完整路由规则,杜绝动态拼接控制器名的可能
拦截危险方法调用链
漏洞常借道 invokefunction、input、filter 等方法执行任意函数,关键在于阻断参数污染路径。
- 修改
think\Request类的method()方法:对$_POST[Config::get('var_method')]的值做严格白名单限制,仅允许GET/POST/PUT/DELETE/PATCH,非法值直接设为POST并unset原参数 - 检查所有使用
input()的地方,禁用用户可控的filter参数,例如避免input('param', '', $_GET['filter'])这类写法 - 全局搜索项目中
call_user_func、call_user_func_array、eval的调用,确认是否由外部输入直接驱动;若有,替换为预定义方法映射表
强化输入过滤与环境隔离
即使控制器名被拦截,攻击者仍可能通过参数注入触发后续漏洞,因此需在数据进入业务逻辑前完成净化。
- 所有 GET/POST/REQUEST 输入统一走验证器(
think\Validate),数值字段用filter_var($val, FILTER_VALIDATE_INT),字符串字段先htmlspecialchars()再正则限定字符集(如仅允许字母、数字、下划线) - 关闭调试模式:
'app_debug' => false,并删除runtime/log/目录全部内容,Nginx/Apache 配置中禁止 Web 直接访问runtime和config目录 - PHP 层面在
php.ini中启用disable_functions = system,exec,passthru,shell_exec,proc_open,popen,eval,assert,防止框架外调用绕过
验证是否真正生效
修复后必须用真实攻击载荷验证,不能只看状态码或表面报错。
- 重放原始 POC:
?s=index/\think\app/invokefunction&function=phpinfo&vars[0]=1、?_method=__construct&filter[]=system&server[REQUEST_METHOD]=id,响应应为 404 或空内容,且服务器错误日志中无phpinfo、system调用痕迹 - 检查
thinkphp/library/think/Request.php文件 MD5 是否与已知安全版本一致,确认method()方法中已添加白名单逻辑且unset生效 - 人工触发边界场景:传入含反斜杠、点号、大写字母的控制器名,观察是否被统一拦截而非部分放行

















