1.1 简介
Phar(PHP Archive)文件是一种打包格式,将PHP代码文件和其他资源放入一个文件中来实现应用程序和库的分发。
在来自Secarma的安全研究员Sam Thomas在18年的Black Hat上提出后利用方式后,开始受到广泛的关注。
Phar可利用是因为Phar以序列化的形式存储用户自定义的meta-data,而以流的形式打开的时候,会自动反序列化,从而触发对应的攻击载荷。
1.2 详细介绍
对于Web应用的开发,如果你没用使用正确的工具,那开发过程可能会变得困难和痛苦。如果你之前开发过Java程序,我相信你肯定知道Jar文件(Jar是Java ARchive的缩写)。一个应用,包括所有的可执行、可访问的文件,都打包进了一个JAR文件里,使得部署过程十分简单。
PHAR (“Php ARchive”) 是PHP里类似于JAR的一种打包文件。如果你使用的是 PHP 5.3 或更高版本,那么Phar后缀文件是默认开启支持的,你不需要任何其他的安装就可以使用它
PHAR文件缺省状态是只读的,使用Phar文件不需要任何的配置。部署非常方便。因为我们现在需要创建一个自己的Phar文件,所以需要允许写入Phar文件,这需要修改一下 php.ini
打开 php.ini
,找到 phar.readonly
指令行,修改成:
phar.readonly = 0
现在,我们就可以来把PHP应用打包成Phar文件了。
我们的第一个 PHAR 文件
首先我要按按照一个的规则创建应用的目录结构,就行下面这样:
其中的 build
目录里将放置 PHAR 文件,这样能避免它跟源码程序混合到一起。src
放的就是我们的PHP源码。
index.php
会成为我们的应用的入口程序,common.php
可以放置应用需要的一些共有代码,config.ini
是我们的配置文件。
1.3 phar 运行原理
stub:phar文件的标志,必须以 xxx __HALT_COMPILER();?> 结尾,否则无法识别。xxx可以为自定义内容。
manifest:phar文件本质上是一种压缩文件,其中每个被压缩文件的权限、属性等信息都放在这部分。这部分还会以序列化的形式存储用户自定义的meta-data,这是漏洞利用最核心的地方。
content:被压缩文件的内容
signature (可空):签名,放在末尾。
------------------------------------------------------------------------------------------------------------------------
一个新 Phar
对象的创建通常需要三个参数。第一个参数是Phar文件的路径。你不仅可以通过它创建Phar文件,还可以对现存的Phar文件进行操作。
第二个参数是设定 Phar
对象如何处理文件。Phar
对象继承了 PHP RecursiveDirectoryIterator
对象,这个参数是直接传递到父类里。这里提供的值是RecursiveDirectoryIterator
的缺省值,能满足目前的要求。
第三个参数是Phar文件的别名,在内部引用这个Phar文件时都要使用这个别名。也就是说,Phar内部文件的相互include都需要显式的使用这个别名。例如,之前的index.php
对 common.php
的引用就是这种方式。
具体移步 PHP开发常识:什么是Phar? – WEB骇客 (webhek.com)
1.4 相关漏洞原理
phar的实现在 php-src/ext/phar/phar.c
中,主要是 phar_parse_metadata
函数在解析phar文件时调用了 php_var_unserialize
,因而造成问题。
而php在文件流处理过程中会调用 _php_stream_stat_path
(/main/streams/streams.c) ,而后间接调用 phar_wrapper_stat
,所以大量的文件操作函数都可以触发phar的反序列问题。
目前已知部分的触发函数有:
1.5 漏洞利用条件
-
phar可以上传到服务器端(存在文件上传)
-
要有可用的魔术方法作为“跳板”。
-
文件操作函数的参数可控,且
:
、/
、phar
等特殊字符没有被过滤
phar 的生成
<?php
class TestObject {
}
$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$o = new TestObject();
$o -> data='hu3sky';
$phar->setMetadata($o); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
?>
1.6 绕过方式
当环境限制了phar不能出现在前面的字符里。可以使用compress.bzip2://和compress.zlib://等绕过
compress.bzip://phar:///test.phar/test.txt
compress.bzip2://phar:///test.phar/test.txt
compress.zlib://phar:///home/sx/test.phar/test.txt
也可以利用其它协议
php://filter/read=convert.base64-encode/resource=phar://phar.phar
1
GIF格式验证可以通过在文件头部添加GIF89a绕过
1、$phar->setStub(“GIF89a”."<?php __HALT_COMPILER(); ?>"); //设置stub
2、生成一个phar.phar,修改后缀名为phar.gif
1.7 Phar文件的一些缺陷
如果你开发的类库或可引用程序需要被多个项目使用,把它打包成Phar文件是一个省事的解决方案。Phar文件是经过高度优化过的,它和普通文件的执行效率相比完全不弱,所以,你不需要担心效率问题。
但需要注意的是,Phar文件的使用有一些限制。下面是一些提示让你更好的理解它:
- 我们可以整个应用都打包到一个Phar文件里,但Phar只提供了一个单一入口。
- 在生产环境里,我们应该避免将东西回写进Phar,我们应该将哪些可能被修改的文件放到Phar之外,在标准PHP安装里,Phar是不允许回写的,因为安全问题。