ThinkPHP反序列化漏洞本质是攻击者控制unserialize()输入,触发__wakeup/__destruct等魔术方法,通过POP链调用最终导致RCE或任意文件写入;常见入口包括Session/缓存反序列化、调试数据还原及开发者自定义unserialize调用。

ThinkPHP反序列化漏洞的本质,是攻击者通过控制传入 unserialize() 的数据,触发框架中特定类的魔术方法(如 __wakeup、__destruct、__toString),借助已有类方法间的链式调用,最终达成任意文件写入或远程代码执行(RCE)。
关键触发点:哪些位置容易调用 unserialize()?
ThinkPHP 6.0+ 中常见风险入口包括:
- Session 反序列化:当使用非原生驱动(如 Memcache、Redis)且未严格校验 session 数据时,
think\Session\Driver\Memcache等类可能在读取 session 后直接反序列化 - 缓存反序列化:
think\Cache组件若配置为使用File或Memcache驱动,且缓存键可控(如用户输入拼接进缓存 key),可能间接触发反序列化 - 日志/调试数据处理:某些开发环境开启调试模式后,异常堆栈或请求参数被序列化存储,再被不安全地还原
- 自定义反序列化入口:开发者在控制器中显式调用
unserialize($_GET['data'])或类似逻辑,未限制类名白名单
核心利用链:POP 链如何在 ThinkPHP 6 中成型?
ThinkPHP 6 的 POP 链依赖其容器(think\Container)、门面(Facade)、模型(Model)等组件中广泛使用的魔术方法。典型路径如下:
-
think\Container的__destruct()调用invokeClass(),进而加载并实例化任意类 -
think\Facade的__callStatic()触发getFacadeRoot(),若 root 被设为恶意对象,可衔接后续调用 -
think\Model或其子类中__toString()方法调用toSql()或toArray(),若内部引用了可控对象,可继续跳转 - 配合
think\process\pipes\Windows或think\cache\driver\File等类,最终导向file_put_contents或system
PHPGGC 是怎么把漏洞“一键化”的?
PHPGGC 不是生成通用 EXP,而是根据目标环境自动匹配可用 gadget 链。对 ThinkPHP 6.x,它会:
立即学习“PHP免费学习笔记(深入)”;
- 扫描已知可利用类(如
think\Container、think\cache\driver\File、think\session\driver\Memcache)及其魔术方法调用关系 - 按 PHP 版本、ThinkPHP 小版本(6.0.1 vs 6.0.13)、是否启用 opcache 等条件筛选兼容链
- 将攻击目标(如写 shell 到
public/shell.php)编译为属性值,注入到链首对象中 - 输出完整 payload 字符串,可直接用于 GET 参数、POST body 或 Cookie
防御要点:不止是禁用 unserialize
真正有效的缓解需分层落地:
- 升级到 ThinkPHP 6.3+ 并确认已合并官方修复补丁(如对
Container::make()的类名过滤) - 禁用危险函数:在
php.ini中设置disable_functions = system,exec,passthru,shell_exec,proc_open,popen,pcntl_exec - 强制指定
unserialize()的allowed_classes参数,仅允许业务必需的类(PHP 7.4+ 支持) - 避免将用户输入(尤其是 Cookie、Header、GET/POST 参数)直接送入反序列化流程;改用 JSON 格式传输结构化数据
- 生产环境关闭调试模式(
app_debug = false),防止敏感类信息泄露辅助攻击链构造



















