Pharの妙妙屋

Pharの妙妙屋
不是炒米线Phar(PHP Archive)是一种将多个 PHP 文件及资源打包成单个文件(类似 Java 的 JAR 或 ZIP)的 PHP 归档格式,方便 PHP 应用程序和库的分发,支持 Tar、ZIP 或自定义格式,并可通过 Gzip/Bzip2 压缩和数字签名,主要通过 php.net/manual/zh/book.phar.php 介绍的 Phar 类进行创建和操作,但需注意其反序列化机制曾存在安全漏洞。 Phar 在PHP 5.3 或更高版本中默认开启
前戏
注意要将php.ini中的phar.readonly选项设置为Off,否则无法生成phar文件。如果懒得关或找不到,可以临时使用php -d phar.readonly=0 gen_phar.php
先来看phar的结构
a stub
可以理解为一个标志,格式为xxx,前面内容不限,但必须以__HALT_COMPILER();来结尾,否则phar扩展将无法识别这个文件为phar文件a manifest describing the contents
phar文件本质上是一种压缩文件,其中每个被压缩文件的权限、属性等信息都放在这部分。这部分还会以序列化的形式存储用户自定义的meta-data,这是上述攻击手法最核心的地方the file contents
被压缩文件的内容[optional] a signature for verifying Phar integrity (phar file format only)
签名,放在文件末尾
Metadata反序列化
说到Phar在CTF里的应用,我们常常考虑到phar的Metadata反序列化,当Phar被phar://解析时,会自动触发metadata的反序列化。
来看exp
1 |
|
Phar爱上了Include(LFI),他却想无套(压缩壳)内射(包含)?
当phar被压缩时,php对其有着相当奇妙的特性。
一定一定一定要看 这位师傅的文章
上面那位师傅讲得非常透彻!并且深入底层从源码角度展开了探索。这里总结如下:
- 当phar使用gzip、bz2压缩,并且被include时,会触发自动解压。
- 自动解压只需要文件名带有
.phar即可,甚至在路径里都可以!(后缀不重要)
但实战中我有遇到过打的phar包含没有执行,仔细分析一下,这里补充第三条。
- 未压缩的
.phar会把stub当作入口执行;压缩的phar会尝试执行内部的index.php。
下面具体展开讲讲第三条。
这里给出一个例子(带压缩的phar):
1 |
|
程序很简单,分别往stub和index.php里写了code1和code2,然后gz压缩生成exploit.phar.gz。那么问题来了,此时执行include("exploit.phar"); 究竟执行了code1还是code2呢?
再给出一个例子(纯phar):
1 |
|
依然是分别往stub和index.php里写了code1和code2,但不进行压缩。这时候执行include("exploit.phar");,到底会执行code1还是code2呢?
我们实操一下
结果非常Amazing啊!可以看到,当phar戴套(压缩后),直接include压缩包会执行index.php中的代码。为什么呢?因为当phar不进行压缩时,stub会以明文形式出现在phar头部,而其他文件均以资源形式存贮,除非制定phar内的某段代码,否则不会执行。
而当phar压缩后,实际上php明文已经消失了(这也是绕过文件上传waf的关键)。这个时候,php会尝试解压phar并且自动包含内部的index.php。因此,当使用压缩的方式上传phar绕过waf,并且可控的包含路径使用了basename或者过滤了/时,可以把payload放置在index.php里,当包含压缩phar时会自动执行。
总结:未压缩的 .phar 会把 stub 当作 PHP 入口执行;一旦压缩成 .phar.gz / .phar.bz2,stub 不再是明文入口,PHP 会先解压并把 phar 当作“文件系统”处理,include 时自动落到内部的 index.php,从而执行其中的代码。
另外补充一点我老是搞不清楚的东西:
Phar::compressFiles()和Phar::compress()的区别:
| 特性 | Phar::compress() | Phar::compressFiles() |
|---|---|---|
| 压缩对象 | 整个 phar 文件 | 仅 phar 内文件内容 |
| 输出文件 | 新文件(.phar.gz/.phar.bz2) | 原 phar 文件 |
| stub 行为 | include时不会执行stub | stub是原文,LFI是会执行stub |
| metadata | 包含在压缩流里 | metadata 不变 |









