ThinkPHP反序列化漏洞关键在于魔术方法触发的POP链:__wakeup()初始化时路径拼接致路径遍历;__destruct()销毁时调用file_put_contents等引发PHAR利用;__toString()隐式转换触发任意函数调用;__call()和__get()则因动态调用导致访问控制绕过。

ThinkPHP反序列化漏洞的关键,不在序列化本身,而在于反序列化过程中自动触发的魔术方法。这些方法本为框架内部功能服务,但一旦被攻击者控制对象属性,就可能串联成危险调用链(POP链),最终导致任意代码执行。
__wakeup():反序列化完成后的“第一响应”
该方法在unserialize()执行完毕、对象刚被重建时立即调用。ThinkPHP多个类(如think\model\Pivot、think\cache\driver\File)在__wakeup()中执行初始化逻辑,例如重设缓存路径、恢复模型关联等。若其中使用了用户可控属性(如$this->tag、$this->options)拼接文件路径或构造SQL片段,就可能引发路径遍历或命令注入。
__destruct():对象销毁前的“最后机会”
这是最常被利用的入口点。ThinkPHP 6.0.x 中,think\process\pipes\Pipes、think\cache\driver\Redis等类的__destruct()会调用file_put_contents()、unlink()或eval()(间接通过回调)。例如,当一个恶意构造的Pipes对象被销毁时,其$this->files属性若被设为phar://xxx,就可能触发PHAR反序列化二次利用。
__toString():隐式字符串转换的“跳板”
该方法在对象被echo、print、字符串拼接(如"result: " . $obj)时触发。ThinkPHP中think\model\Relation、think\console\Output等类实现了__toString(),内部调用toJson()或render(),进而可能触发toArray()→getAttr()→getValue()链。若getValue()接收了用户可控的闭包($closure)和数据($this->data),即可实现任意函数调用,如system('id')。
立即学习“PHP免费学习笔记(深入)”;
__call()与__get():访问控制失效的“后门”
当调用不存在的方法或读取不可见属性时触发。ThinkPHP的门面(Facade)机制和动态模型属性大量依赖这两个方法。例如,think\Facade类的__call()会转发调用到容器中的实例;若攻击者能控制容器绑定或反射目标类,就可能绕过类型限制,将调用导向危险方法。类似地,__get()在获取模型字段时若未严格校验键名,可能被诱导执行array_key_exists()→__toString()→eval()链。



















