thinkphp 5.0控制器漏洞核心是控制器名未校验与路由解析缺陷,导致任意类方法调用和rce;修复需入口拦截、参数过滤、配置加固三同步,仅升级版本无效。

ThinkPHP 5.0 控制器漏洞核心在于**控制器名未校验 + 路由解析缺陷**,攻击者可绕过正常路由机制,直接调用任意类的任意方法(如 hinkpp/invokefunction),或通过变量覆盖触发 RCE。修复不是加个补丁就行,而是必须从入口拦截、参数过滤、配置加固三方面同步落地。
典型漏洞利用方式
以下 payload 在 TP5.0 ≤ 5.0.22(未修复)且未开启强制路由时普遍有效:
-
远程命令执行:
?s=index/ hinkpp/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami -
写入 WebShell:
?s=/index/thinkpp/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=shell.php&vars[1][1]=<?php @eval($_POST[x]); ?> -
变量覆盖型 RCE(需 POST):
_method=__construct&filter[]=system&method=GET&get[]=id,配合后续input()触发 filter 执行
关键修复代码(必须手动添加)
仅升级框架版本无法根除漏洞,以下代码需在项目中显式插入,不可依赖配置开关:
-
控制器名白名单校验(修改
thinkApp的module()方法):
在解析出$controller后立即加入正则判断:
if (!preg_match('/^[A-Za-z][w.]*$/', $controller)) { throw new HttpException(404, 'controller not exists: ' . $controller); } -
Request method 安全加固(修改
thinkRequest的method()方法):
对$_POST[Config::get('var_method')]的值做严格限制,仅允许标准 HTTP 方法:
if (in_array(strtoupper($method), ['GET','POST','PUT','DELETE','PATCH'])) { $this->method = $method; } else { $this->method = 'POST'; } -
入口文件硬性拦截高危请求(在
public/index.php开头添加):
if (isset($_GET['s']) && preg_match('/\\think\\|invokefunction|call_user_func/i', $_GET['s'])) { die('Access Denied'); }
配套必须关闭的危险配置
代码修复后,若以下配置仍开启,漏洞仍可能被绕过:
-
禁用调试模式:确保
config/app.php中'app_debug' => false,避免报错泄露路径与配置 -
关闭自动路由:设
'url_route_on' => true(启用路由)但'route_complete_match' => true,并禁用'auto_route' => false -
清除默认 var_method:在
config/app.php中显式设'var_method' => '',防止 _method 被滥用
验证是否修复成功
修复完成后,需主动测试以下请求是否返回 404 或 403,而非执行结果:
?s=index/ hinkpp/invokefunction?s=index/think emplatedriverFile/write&cacheFile=shell.php&content=<?php phpinfo();?>- 发送 POST:
_method=__construct&filter[]=phpinfo











