一、基础概念

  1. 序列化/反序列化

    • serialize():将变量、对象转为可存储/传输的字符串(打包)。

    • unserialize():将序列化字符串还原为原数据(拆包),必须先序列化再反序列化

    • 作用:数据持久化存储、跨环境数据传递。

  2. 格式标识

    • s:长度:"字符串":字符串类型;i:数字:整型;O:类名长度:"类名":属性数:{属性内容}:对象类型。

二、无类序列化(基础考点)

核心逻辑:反序列化结果与目标值全等(===) 即可触发逻辑、获取Flag。

  1. 常规场景 直接对目标字符串序列化,通过GET/POST/Cookie传入参数即可。 示例:目标值derry → 序列化结果 s:5:"derry";

  2. 代码审计坑点变量定义在判断逻辑之后,目标变量实际为空字符串,需序列化空值:s:0:"";

三、类序列化 & PHP魔术方法(核心漏洞点)

1. 类序列化规则

对象序列化会保留类名、属性、属性值;反序列化会重建对象,自动触发对应魔术方法

  • public属性:序列化直接显示属性名;

  • protected/private属性:序列化会携带\00空字符,URL传输需注意编码,也是CTF常见坑点。

2. 高频魔术方法(漏洞触发核心)

反序列化过程中满足条件会自动调用,是漏洞利用的关键:

方法 触发时机 用途/考点
__construct 对象创建(new)时 构造方法,反序列化不主动触发,多为干扰代码
__destruct 对象销毁、脚本执行结束 最常用漏洞入口,反序列化结束必触发
__sleep 序列化对象时 自定义序列化保留的属性
__wakeup 反序列化重建对象时 常规反序列化优先执行,可被漏洞绕过
__toString 对象被当作字符串输出时 常用于原生类XSS利用
__get/__set 访问/赋值不存在/私有属性 属性调用触发
__call/__callStatic 调用不存在(静态)方法 方法调用触发
__invoke 对象被当作函数调用 小众考点
__isset/__unset 检测/销毁不可访问属性 辅助考点

四、经典CTF真题&漏洞利用

1. 网鼎杯 AreUSerialz(类序列化+魔术方法)

  1. 核心逻辑:依靠__destruct触发process()方法,op=2时执行文件读取,调用NewFlag::getFlag()获取Flag。

  2. 难点:目标类属性为protected,直接序列化含\00空字符,URL传参解析异常。

  3. 解法:将类属性改为public再序列化,规避空字符问题,构造合法序列化字符串传入。

2. 极客大挑战2019 PHP(CVE-2016-7124)

  1. 漏洞原理:PHP版本低于 5.6.25 / 7.0.10 时,若序列化字符串中声明的属性数量 > 类真实属性数,会跳过__wakeup执行

  2. 利用步骤:

    • 扫描获取网站备份www.zip,审计源码发现反序列化入口与__wakeup防护;

    • 篡改序列化字符串:增大属性计数值,绕过__wakeup

    • 类属性为private,序列化结果自带%00类名%00前缀,直接URL传参。

3. 原生类反序列化XSS

  1. 原理:利用PHP内置原生类(无需自定义类),反序列化后输出对象触发__toString

  2. 常用类:ExceptionError

  3. 利用方式:构造异常对象,传入XSS载荷<script>alert(1)</script>,序列化后URL编码传参,实现弹窗。

五、关键防护与考点总结

  1. 核心攻击链 可控参数 → 传入恶意序列化字符串 → unserialize()重建对象 → 自动触发魔术方法 → 执行恶意代码/读取文件/XSS。

  2. 高频坑点

    • 代码顺序:变量定义位置决定目标值;

    • 访问修饰符:public/protected/private 影响序列化格式与URL传输;

    • 版本漏洞:CVE-2016-7124 绕过__wakeup

    • 特殊字符:\00空字符在URL中需编码,易解析失败。

  3. 基础防御

    • 严格过滤unserialize()的入参,不接收用户可控的序列化数据;

    • 升级PHP版本,修复已知反序列化漏洞;

    • 对敏感类、魔术方法做权限与逻辑限制。

更多推荐