零基础入门反序列化及常用trick
字数 1735 2025-08-12 11:33:54

PHP反序列化漏洞全面解析与实战指南

一、序列化与反序列化基础

1. 基本概念

序列化是将数据结构或对象状态转换为可存储或传输的格式的过程,而反序列化则是将这些数据恢复为原始对象状态的过程。

$a = 'quan9i';
$b = serialize($a);  // 序列化
$c = unserialize($b); // 反序列化

2. 序列化格式解析

对于类对象的序列化结果示例:

O:7:"xianzhi":2:{s:3:"age";s:2:"19";s:4:"name";s:6:"quan9i";}

格式说明:

  • O:7:"xianzhi":对象类型,类名长度7,类名"xianzhi"
  • :2::对象有2个属性
  • {s:3:"age";s:2:"19";...}:属性列表,每个属性包含类型、长度、名称和值

3. 数据类型标识符

标识符 数据类型
a array
b boolean
d double
i integer
o common object
r reference
s string
C custom object
O class
N null
R pointer ref
U unicode string

二、PHP魔术方法详解

魔术方法是在特定事件发生时自动调用的方法,以双下划线开头:

1. 构造与析构方法

  • __construct():对象创建时调用
  • __destruct():对象销毁时调用
class bai {
    public function __construct() {
        echo "初始化";
    }
    public function __destruct() {
        echo "销毁";
    }
}

2. 序列化相关方法

  • __sleep():在serialize()前调用,可指定要序列化的属性
  • __wakeup():在unserialize()后调用
public function __sleep() {
    return array('name', 'age');
}

public function __wakeup() {
    $this->age = 1000;
}

3. 其他重要魔术方法

  • __toString():对象被当作字符串使用时调用
  • __invoke():对象被当作函数调用时触发
  • __get()/__set():访问/设置不可访问属性时调用
  • __call():调用不存在的方法时触发
  • __isset()/__unset():对不可访问属性使用isset()/unset()时触发

三、反序列化漏洞利用技术

1. 字符串逃逸

当存在字符串替换函数时,可通过精心构造payload实现逃逸:

// 原始代码
$umsg = str_replace('fuck', 'loveU', serialize($msg));

// 利用方式
$a = new message('fuckfuck...";s:5:"token";s:5:"admin";}','b','c');

利用步骤

  1. 计算需要逃逸的字符串长度
  2. 构造足够数量的被替换字符串
  3. 在尾部添加闭合的序列化数据

2. 正则绕过

当存在正则过滤如preg_match('/^O:\d+/')时,可通过添加+号绕过:

O:+6:"Test":...

3. 引用利用

使用&符号创建变量引用,使两个变量保持同步:

$a = 'we are best';
$b = &$a;  // $b和$a现在引用同一值

4. Session反序列化

PHP有三种session序列化处理器:

  1. php_serialize:完全序列化格式
    a:1:{s:4:"name";s:5:"ocean";}
    
  2. php(默认):简化格式
    name|s:5:"ocean";
    
  3. php_binary:二进制格式

利用场景:当序列化和反序列化使用不同处理器时可能产生漏洞。

四、POP链构造技术

POP(Property-Oriented Programming)链是通过精心设计对象属性调用链来触发敏感操作的技术。

构造步骤

  1. 寻找危险函数(如文件操作、命令执行等)
  2. 分析魔术方法和类方法的调用关系
  3. 构造调用链使程序流最终到达危险函数

示例分析

// 目标:通过__destruct() -> __toString() -> __get() -> __invoke()链触发文件包含
class Modifier {
    protected $var;
    public function __invoke(){
        $this->append($this->var); // 最终触发文件包含
    }
}

class Show {
    public function __toString(){
        return $this->str->page; // 触发__get
    }
}

class Test {
    public function __get($key){
        $function = $this->p;
        return $function(); // 触发__invoke
    }
}

五、实战案例解析

1. 简单反序列化利用

class ctfShowUser{
    public $isVip = false;
    public function vipOneKeyGetFlag(){
        if($this->isVip){
            echo $flag;
        }
    }
}

// 利用:直接修改isVip属性为true

2. 魔术方法利用

class backDoor{
    private $code;
    public function getInfo(){
        eval($this->code); // 危险点
    }
}

// 利用:通过反序列化设置$code为恶意代码

3. 文件操作利用

public function __destruct(){
    file_put_contents("log-".$this->username, $this->password);
}

// 利用:设置username为"shell.php",password为PHP代码

六、防御措施

  1. 输入验证:严格检查反序列化数据来源
  2. 使用安全函数:如hash_hmac()验证数据完整性
  3. 限制反序列化类:使用allowed_classes选项
  4. 日志监控:记录反序列化操作
  5. 代码审计:避免在魔术方法中使用危险操作

七、工具与资源

  1. PHPGGC:PHP反序列化payload生成工具
  2. CodeBrute:自动化POP链构造工具
  3. 反序列化检测工具:如RIPS、SonarQube等

通过深入理解PHP反序列化机制和魔术方法,结合实际的漏洞利用技术,安全研究人员可以更好地发现和防御这类安全风险。

PHP反序列化漏洞全面解析与实战指南 一、序列化与反序列化基础 1. 基本概念 序列化 是将数据结构或对象状态转换为可存储或传输的格式的过程,而 反序列化 则是将这些数据恢复为原始对象状态的过程。 2. 序列化格式解析 对于类对象的序列化结果示例: 格式说明: O:7:"xianzhi" :对象类型,类名长度7,类名"xianzhi" :2: :对象有2个属性 {s:3:"age";s:2:"19";...} :属性列表,每个属性包含类型、长度、名称和值 3. 数据类型标识符 | 标识符 | 数据类型 | |--------|----------------| | a | array | | b | boolean | | d | double | | i | integer | | o | common object | | r | reference | | s | string | | C | custom object | | O | class | | N | null | | R | pointer ref | | U | unicode string | 二、PHP魔术方法详解 魔术方法是在特定事件发生时自动调用的方法,以双下划线开头: 1. 构造与析构方法 __construct() :对象创建时调用 __destruct() :对象销毁时调用 2. 序列化相关方法 __sleep() :在serialize()前调用,可指定要序列化的属性 __wakeup() :在unserialize()后调用 3. 其他重要魔术方法 __toString() :对象被当作字符串使用时调用 __invoke() :对象被当作函数调用时触发 __get() / __set() :访问/设置不可访问属性时调用 __call() :调用不存在的方法时触发 __isset() / __unset() :对不可访问属性使用isset()/unset()时触发 三、反序列化漏洞利用技术 1. 字符串逃逸 当存在字符串替换函数时,可通过精心构造payload实现逃逸: 利用步骤 : 计算需要逃逸的字符串长度 构造足够数量的被替换字符串 在尾部添加闭合的序列化数据 2. 正则绕过 当存在正则过滤如 preg_match('/^O:\d+/') 时,可通过添加 + 号绕过: 3. 引用利用 使用 & 符号创建变量引用,使两个变量保持同步: 4. Session反序列化 PHP有三种session序列化处理器: php_ serialize :完全序列化格式 php (默认):简化格式 php_ binary :二进制格式 利用场景 :当序列化和反序列化使用不同处理器时可能产生漏洞。 四、POP链构造技术 POP(Property-Oriented Programming)链是通过精心设计对象属性调用链来触发敏感操作的技术。 构造步骤 : 寻找危险函数(如文件操作、命令执行等) 分析魔术方法和类方法的调用关系 构造调用链使程序流最终到达危险函数 示例分析 : 五、实战案例解析 1. 简单反序列化利用 2. 魔术方法利用 3. 文件操作利用 六、防御措施 输入验证 :严格检查反序列化数据来源 使用安全函数 :如 hash_hmac() 验证数据完整性 限制反序列化类 :使用 allowed_classes 选项 日志监控 :记录反序列化操作 代码审计 :避免在魔术方法中使用危险操作 七、工具与资源 PHPGGC :PHP反序列化payload生成工具 CodeBrute :自动化POP链构造工具 反序列化检测工具 :如RIPS、SonarQube等 通过深入理解PHP反序列化机制和魔术方法,结合实际的漏洞利用技术,安全研究人员可以更好地发现和防御这类安全风险。