1. 从零理解PHP反序列化漏洞
第一次看到CTF赛题里的PHP反序列化漏洞时,我和大多数新手一样满头问号。这玩意儿到底是怎么把一串序列化数据变成攻击武器的?后来在实战中踩过几次坑才明白,反序列化的本质就是把存储的数据重新变成程序可执行的对象,而漏洞就藏在对象重建的过程中。
以这次网鼎杯的AreUSerialz赛题为例,我们先看最关键的漏洞触发点:
php复制if(isset($_GET{'str'})) {
$str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str); // 危险操作!
}
}
这段代码的问题在于:它直接反序列化了用户可控的输入数据。想象你允许陌生人把任意家具搬进你家,他完全可以偷偷塞个炸弹进来。在PHP中,反序列化时会自动调用__wakeup()和__destruct()等魔术方法,这就给了攻击者"安装引爆装置"的机会。
我调试这个漏洞时发现个有趣现象:当FileHandler对象被销毁时,__destruct()方法会强制把op改为1。这就像拆弹时剪错线会触发爆炸一样,开发者本意是增加安全性,却反而制造了新的攻击面。要绕过这个限制,关键在于控制对象销毁前的执行流程。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 突破字符过滤的第一种解法
2.1 is_valid()函数的攻防博弈
题目中的is_valid()函数像道安检门,只允许ASCII码32-125的字符通过:
php复制function is_valid($s) {
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
}
但防护措施总有漏洞可钻。经过多次测试,我发现PHP处理序列化数据时有这些特性:
- 类型标识符
s换成大写S时,支持十六进制编码 - 保护属性名
%00*%00可转为\00*\00 - 数字类型不受字符限制
这就形成了第一个攻击链:
- 构造`op
