Phar反序列化
什么是Phar
JAR 是开发 Java 程序一个应用,包括所有的可执行、可访问的文件,都打包进了一个 JAR 文件里,使得部署过程十分简单
phar是 PHP 里类似于 JAR 的一种打包文件,说白了其本质可以理解为一个压缩包
对于 PHP 5.3 或更高版本,phar后缀文件时默认开启支持的,可以直接使用
一般使用文件包含中的**phar伪协议进行读取.phar文件**
Phar文件结构
- **stub phar:**这是phar文件标识,格式为xxx<?php xxx;__HALT_COMPILER();?>(头部信息),这是 PHAR 文件的入口点,当 PHP 解释器加载 PHAR 文件时,会首先执行 Stub 代码
- manifest:压缩文件的属性等信息,以序列化方式存储
- **contents:**压缩文件的内容
- **signature:**签名,放在文件末尾
phar协议解析文件时,会自动触发对**manifest字段的序列化字符串进行反序列化**

以下是官方文档,红框部分是要进行利用的序列化部分

phar文件的压缩和解压缩
| 1 |  | 
- Phar类:- Phar是 PHP 内置的一个类,用于创建、操作和管理 PHAR 文件
- **$phar = new Phar('test2.phar',0,'test2.phar');**第一个参数test2.phar是创建的 PHAR 文件名,如果文件不存在会创建一个新的文件,如果文件存在并允许进行修改,会对其进行更新;第二个参数0表示文件创建的标志,实际应用中会使用如:Phar::CREATE表示创建新的 PHAR 文件,来指定不同的创建模式;第三个参数test2.phar指定 PHAR 文件的别名,可以在后续中引用该 PHAR 文件时使用
- **$phar->buildfromDirectory('f:\0Day');**指定要打包的目录路径
- **$phar->setDefaultStub('test.txt','test.txt');**中setDefaultStub用于为 PHAR 文件设置默认的 Stub,即默认入口;第一个参数test.txt是入口文件的路径,第二个参数'test.txt'是内部文件的路径
| 1 |  | 
- **$phar = new Phar('test.phar');**通过new Phar('test.phar')语句,程序尝试打开名为test.phar的 Phar 压缩包文件,并将其封装成一个Phar对象存储在变量$phar中。如果test.phar文件不存在,会报错
- **$phar->extractTo('test');**调用Phar对象的extractTo方法,该方法的作用是将 Phar 压缩包中的所有内容提取到指定的目录;参数'test'是目标目录,即 Phar 压缩包中的文件和目录会被解压到名为test的目录下。如果该目录不存在,PHP 会尝试创建它;若已存在,则会将文件解压到该目录内
创建一个.phar文件的模板
| 1 |  | 
具体解析
| 1 |  | 
Phar反序列化漏洞原理
manifest压缩文件的属性等信息,以序列化存储,存在一段序列化的字符串
调用phar伪协议,可读取.phar文件
phar协议解析文件时,会自动触发对manifest字段的序列化字符串进行反序列化
phar需要满足 PHP >= 5.2,在php.ini中将phar.readonly设为Off
以下是这个漏洞受到影响的函数(即可以使用phar伪协议读取.phar文件的函数)

具体题目解析
第一个是漏洞页面index.php,源码如下

第二个是可以生成phar文件的页面phar.php,源码如下

审计代码
| 1 |  | 
- 在漏洞页面index.php的源码中,定义了Testobj这个类,有一个属性output,和一个__destruct()魔术方法,会执行output的内容,这里可以进行RCE执行命令
- 然后是可以GET传参filename,并且使用了file_exists()函数检查文件或目录是否存在,这个函数存在与受影响的函数之中,所以这里存在phar反序列化漏洞
| 1 |  | 
- 在phar.php页面可以生成.phar文件,源码中同样定义了Testobj类和output属性,与index.php中的一致
- 生成.phar文件部分的解析见源码
在index.php页面中传入GET参数filename,其值为/etc/passwd
| 1 |  | 

正常会根据文件是否存在得到一个布尔值的回显
因为这里使用的是file_exists函数,是可以使用phar://伪协议的,但是可以使用phar伪协议并不代表一定存在phar反序列化漏洞,还要看能否触发魔术方法进而可以执行一些操作,在这里就是要触发__destruct()这个魔术方法进而可以执行命令,所以存在漏洞
访问phar.php这个页面,然后这个页面中的代码会自动生成一个test.phar的文件,查看tmp目录下会发现生成了这个文件

可以使用xxd命令查看文件内容

可以看到写入了序列化后的数据
| 1 |  | 
接着在index.php页面中查看这个文件发现是存在的
| 1 |  | 

最后就可以利用phar伪协议读取这个文件,会自动将序列化部分的数据进行反序列化,然后就会自动触发__destruct()魔术方法,从而可以执行eval($_GET["a"]);,也就是可以进行GET传参一个a进行RCE
| 1 |  | 

Phar反序列化漏洞使用条件
- phar文件可以上传到服务器端
- 要有可用反序列化魔术方法作为跳板(就是可以通过触发魔术方法__destruct()或__wakeup()进行RCE之类的操作)
- 要有文件操作函数,如:file_exists(),fopen(),file_get_contents()
- 文件操作函数的参数可控
- 要使用的伪协议phar://中的字符和关键字没有被过滤

小知识
使用phar://伪协议读取文件是不看后缀的
如果服务器对上传的文件有限制,只能上传一些png、jpg、gif等图片文件,我们可以把phar文件修改成其他的任何一个格式的文件,并且不会受到影响
如下,使用mv命令将test.phar文件修改成test.png文件,改变其后缀名

然后使用phar伪协议读取test.png文件仍然是可以执行命令的
| 1 |  | 

所以后缀名是没有影响的,只要可以上传到服务器就行
Phar反序列化例题
题目分析
index.php页面源码如下
| 1 |  | 
可以发现定义了一个TestObject()类,存在一个__destruct()魔术方法可以获取flag.php中的flag,然后可以进行传参一个POST参数file,并使用md5_file 函数读取指定文件的内容,并基于这些内容生成哈希值,提示有一个upload.php页面,访问发现可以上传文件,并且根据标题可知只能上传图片文件

这里使用md5_file 函数读取指定文件,并且有上传文件的接口,存在phar反序列化漏洞,可以通过上传一个phar文件,并在index.php页面通过POST参数file读取文件,从而进行反序列化触发__destruct()魔术方法获取flag,不过指定了上传的文件只能是图片,但是在前面学习的小知识中可知可以将phar文件后缀改成其他的,并且不受影响,所以可以上传一个图片格式并可以被解析
首先可以先试试POST传参file查看文件
| 1 |  | 

可以看到可以读取到/etc/passwd文件并输出一段哈希值
这题中满足了以下条件,可以进行phar反序列化的利用
解题步骤
- **生成一个phar文件:**在mate-data里放置一个包含TestObject()序列化字符串
- 上传文件:md5_file执行伪协议,触发反序列化,从而触发__destruct()魔术方法执行echo flag
开始解题
生成一个phar文件
可以在自己本地的PhpStorm中生成一个phar文件,不过注意要设置PhpStorm中的phar.readonly为Off,否则会出现以下报错

找到当前使用的php版本的php.ini文件

直接搜索找到phar.readonly就行,以下是原本的样子

把On修改为Off,还要把前面的分号去掉,修改后如下

然后直接运行以下脚本就可以在脚本的同一目录下生成phar文件了
| 1 |  | 

然后就是在upload.php页面上传文件,抓包改后缀和MIME头就行

可以看到成功上传进去了

最后就是使用phar伪协议读取上传的文件
| 1 |  | 
