反序列化漏洞是攻击者通过构造恶意序列化字符串,在未过滤用户输入时触发PHP魔术方法执行任意代码。关键在于__wakeup、__destruct等方法中存在危险函数调用,且序列化字符串长度必须精确匹配。

反序列化漏洞到底是什么
它不是PHP独有的问题,但PHP里特别常见。简单说:程序把一个对象变成字符串存起来(叫序列化),之后再从字符串还原成对象(叫反序列化)。这个“还原”过程本身没问题,危险在于——如果字符串来自用户输入,而程序不加过滤就直接unserialize(),攻击者就能塞进恶意内容,让PHP自动执行不该执行的代码。
关键点:魔术方法是触发器
PHP在反序列化过程中会自动调用某些以__开头的特殊方法,它们就像开关一样,不需要你手动调用。最常被利用的是:
- __wakeup():反序列化刚完成时立刻触发
- __destruct():对象生命周期结束(比如脚本运行完)时触发
- __toString():对象被当成字符串拼接或输出时触发
只要这些方法里有危险操作(比如file_put_contents、system、include),攻击者就能通过构造特定字符串,在反序列化时“顺手”执行命令。
看懂序列化字符串,才能动手改
这是真实序列化结果:
O:4:"User":2:{s:4:"name";s:5:"alice";s:4:"role";s:5:"admin";}
拆开看:
立即学习“PHP免费学习笔记(深入)”;
- O 表示对象(Object),4 是类名长度,"User" 是类名
- 2 表示有2个属性,花括号里是键值对
- s:4:"name" 意思是“字符串类型,长度4,内容是name”
- s:5:"alice" 就是“字符串,长度5,值是alice”
注意:长度数字必须完全匹配,多1少1都会导致反序列化失败。私有属性会变成\0User\0password这种格式,写payload时得URL编码或用十六进制表示。
新手第一步:从靶场练起
别一上来就啃CTF题。推荐先搭Pikachu或easy_serialize_php靶场,找一个明确调用unserialize($_GET['data'])的地方。操作流程很直接:
- 先找源码里定义了哪些类,重点看有没有__wakeup或__destruct方法
- 确认类名、属性名、属性数量,照着格式手工拼一个合法串(比如O:4:"User":1:{s:4:"name";s:3:"abc";})测试能否正常反序列化
- 把属性值换成系统命令,例如s:10:"ls -la /";,前提是对应方法里用了system($this->name)这类逻辑
- 遇到报错先检查引号、分号、长度数字是否全对,尤其注意空格和不可见字符
真正卡住的往往不是原理,而是字符串格式写错了一位数。



















