thinkphp 5.1系列典型rce漏洞源于反序列化校验缺失,通过windows→conversion→request等类的魔术方法链调用call_user_func_array执行任意命令,修复需禁用危险反序列化、升级至5.1.40+、关闭调试模式并增加入口层拦截。

ThinkPHP 5.1 系列存在多个高危 RCE 漏洞,其中最典型的是反序列化触发的远程代码执行(如 CVE-2018-17796、CVE-2019-10904 及后续变种),核心问题在于框架对用户输入的反序列化操作缺乏校验,配合特定类的魔术方法链(__destruct → __toString → __call → call_user_func_array)最终调用危险函数(如 system、exec 或 file_put_contents)。
TP5.1常见RCE触发路径
漏洞多出现在以下场景:
- 控制器中直接反序列化用户可控数据,例如:
unserialize($_GET['data'])或unserialize(base64_decode($_POST['a'])) - 使用了未加固的
Request、Windows、Conversion、Cache等类参与 POP 链,尤其在__destruct、__toString、__call中调用可控制参数的方法 - 开启调试模式(
app_debug=true)且错误页面回显详细信息,便于攻击者探测利用链 - 版本处于 5.1.0–5.1.30(含)或 5.1.31–5.1.37 中未修复补丁的构建包
典型漏洞复现关键点(以5.1.37为例)
攻击链常从 Windows::__destruct() 入口,调用 removeFiles() → 触发 file_exists($file) → 强制调用 $file->__toString() → 进入 Conversion::__toString() → 调用 toJson() → toArray() → visible() → 最终通过 Request::__call() 执行 call_user_func_array(['system'], ['whoami'])。
有效 payload 示例(需 base64 编码后传参):
O:27:"think\process\pipes\Windows":1:{s:34:"&think\process\pipes\Windows&files";a:1:{i:0;s:23:"phpinfo();";}}修复方案与加固代码
修复不是打补丁,而是从设计上切断不可信输入进入执行环节。推荐以下四层防御措施:
-
禁用危险反序列化:绝对禁止对
$_GET、$_POST、$_COOKIE中任意字段直接调用unserialize()。如必须反序列化,请先校验签名(如 HMAC-SHA256)并限定白名单类名 - 升级并锁定框架版本:升级至 ThinkPHP 5.1.40+(官方已移除不安全的 POP 链入口)或直接迁移到 6.x(默认禁用反序列化、增强类型约束)
-
关闭调试模式上线环境:确保生产环境
config/app.php中'app_debug' => false,避免错误泄露类结构和路径 - 代码层主动拦截:在公共入口或中间件中增加检测逻辑,例如:
// app/middleware/SecurityCheck.php
namespace app\middleware;
use think\Request;
class SecurityCheck
{
public function handle(Request $request, \Closure $next)
{
// 拦截可疑反序列化参数
if ($request->param('data') && stripos($request->param('data'), 'O:') === 0) {
abort(400, 'Forbidden: Unsafe serialization detected');
}
if ($request->isPost() && $request->post('a')) {
$a = $request->post('a');
if (is_string($a) && (stripos($a, 'O:') === 0 || base64_decode($a, true) !== false && stripos(base64_decode($a), 'O:') === 0)) {
abort(400, 'Serialization input blocked');
}
}
return $next($request);
}
}
开发规范建议
真正防住 RCE,靠的不是某段代码,而是习惯:
- 永远假设所有用户输入都是恶意的——包括 URL 参数、HTTP 头、上传文件名、JSON 字段
- 系统命令调用务必使用白名单 + 参数化方式(如
proc_open()配合固定参数数组),禁用system()、exec()、shell_exec()直接拼接 - 模板渲染禁用动态表达式(如
{{ $user_input }}应改为{{ htmlspecialchars($user_input) }}) - 定期扫描项目依赖(
composer audit)及框架安全公告,订阅 ThinkPHP 官方 GitHub 的 Security Advisories











