PHP反序列化绕过__wakeup()的核心是篡改序列化字符串中属性数量声明值(如将:2改为:3),使PHP 5.6.25前/7.0.10前版本因属性数不匹配而跳过该方法;需注意private/protected属性编码及URL编码传输。

PHP反序列化中绕过__wakeup(),核心是让PHP解析器在反序列化过程中跳过该魔术方法的自动调用。这并非通用技巧,而是依赖特定PHP版本存在的解析逻辑缺陷——主要影响 PHP 5.6.25 之前 和 PHP 7.0.10 之前 的版本。
关键原理:属性数量不一致触发跳过
PHP反序列化时会先读取序列化字符串中声明的属性数量(如 O:4:"Test":2:{...} 中的 2),再逐个恢复属性。当这个数字大于类实际定义的属性个数时,解析器会认为数据异常,直接跳过__wakeup()执行,继续完成对象重建。
- 类定义了 2 个属性(如
$user、$cmd) - 原始序列化串是
O:4:"Test":2:{...} - 把
:2改成:3或更大值,就能绕过
手动构造绕过Payload的步骤
拿到源码后,按顺序操作:
- 写出含目标逻辑的类实例(比如设置
$cmd = 'cat flag.txt'),本地运行serialize()得到原始串 - 定位串中类似
O:4:"Test":2:的结构,修改冒号后的数字为比实际属性数多 1(例如改成:3) - 若涉及
private或protected属性,注意名称编码:private要加%00类名%00,protected加%00*%00 - 整个串必须做 URL 编码后再传入
$_GET等参数,否则{、:、"等字符会被截断或解析错误
其他可行绕过方式(辅助场景)
当属性数量篡改不可行时,可考虑:
立即学习“PHP免费学习笔记(深入)”;
-
引用型属性(R标记):用
R:2;复用已有属性地址,干扰解析流程,部分旧版本会因此跳过__wakeup -
松散比较陷阱:如果
__wakeup()里用了==判断用户输入,可构造类型不同的值(如字符串"0"与整数0)绕过校验逻辑 -
版本已修复则无效:PHP 5.6.25+ 或 7.0.10+ 默认不再跳过,此时需转向
__destruct()、__toString()等后续链利用
绕过本身不是目的,而是为了把控制权交到后续危险方法手上。盯紧__destruct()有没有system()、file_get_contents(),或者__toString()是否参与日志拼接、SQL 拼接——那里才是真正执行命令或泄露数据的地方。



















