PHP反序列化漏洞本质是将不可信字符串交由unserialize()解析,触发__wakeup、__destruct等魔术方法,导致任意代码执行或文件操作;需通过POP链利用已加载类,防御核心是禁用不可信数据反序列化、启用allowed_classes白名单、改用JSON替代。

PHP反序列化漏洞的本质,是程序将不可信的字符串直接交由 unserialize() 解析,从而触发恶意对象中的魔术方法(如 __wakeup、__destruct),最终导致任意代码执行、文件读写或命令注入。它不依赖外部组件,只要存在可控输入+危险魔术方法,就可能被利用。
常见利用姿势:从构造到触发
攻击者不是凭空造出“能执行命令”的类,而是利用应用已加载的类(即 gadget),串联其魔术方法形成攻击链(POP Chain)。关键在于找到可被调用且含危险操作的函数路径。
-
直接触发 __destruct 或 __wakeup:若某个类的
__destruct()中调用了file_get_contents($this->filename),攻击者只需控制$filename属性值为/etc/passwd,即可实现任意文件读取 -
利用 __toString() 链式调用:当反序列化后的对象被拼接进字符串(如
echo $obj)时会触发__toString();若该方法中又调用了其他对象的方法(如$this->handler->run()),就可继续跳转,扩大利用面 -
绕过基础过滤(如 str_replace):题目常过滤方括号
[ ]、空格或双引号。可行方式包括:用十六进制编码属性名(s:10:"%00Demo%00file";)、在数字与冒号间插入空格(O:4:"Demo" :1:{...})、用 URL 编码或 base64 二次封装后再解码 -
私有/受保护属性名格式必须精准:private 属性序列化后为
%00类名%00属性名(如%00User%00pwd),protected 是%00*%00属性名;长度标记(如s:12:)必须与后续实际字节数严格一致,否则解析失败
关键防御措施:不止禁用函数
单纯禁用 exec、system 等函数治标不治本——攻击者可通过文件写入、DNS外带、SSRF等方式绕过。防御需分层落地:
-
杜绝反序列化不可信数据:这是最根本原则。所有来自
$_GET、$_POST、$_COOKIE、Session 数据等用户输入,一律不得直接传入unserialize() -
改用安全替代方案:优先使用
json_encode/json_decode传输结构化数据;若必须持久化对象,可用igbinary(需服务端统一支持)或自定义白名单类 + 手动赋值 -
启用类白名单机制:PHP 7.4+ 支持
unserialize($data, ['allowed_classes' => ['WhitelistClass']]);低版本可先正则校验字符串是否只含允许类名和基础类型标识(a:|O:|s:|i:等) -
审计魔术方法逻辑:检查所有
__wakeup、__destruct是否包含文件操作、数据库查询、系统调用;若有,确保其参数经严格过滤或来源可信(如仅读取配置常量)
开发阶段必须做的几件事
很多漏洞在编码初期就已埋下,后期修复成本远高于预防。
-
禁用危险配置:在
php.ini中设置allow_url_include = Off、disable_functions = system,exec,passthru,shell_exec,proc_open,popen - 对 Session 数据保持警惕:不要把用户可控字段(如昵称、头像URL)直接存入 Session 后又反序列化;建议 Session 存 ID,状态查数据库
-
日志记录反序列化异常:捕获
unserialize()的 false 返回或 Warning,记录原始输入,便于事后溯源 - 升级框架与组件:ThinkPHP、Laravel 等主流框架近年多次修复反序列化相关 CVE(如 CVE-2024-44902),及时更新可规避已知 POP Chain
反序列化漏洞不是玄学,它依赖确定的语法结构和确定的执行流程。理解序列化格式、盯紧魔术方法、切断用户输入与 unserialize() 的直连通道,就能大幅压缩攻击面。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











