Phar反序列化
引子:反序列化漏洞一般要借助unserialize()函数,不过在Blackhat2018,出现了一种可以不借助unserialize()函数而触发php反序列化漏洞的方法
论文、blackhat PPT
- 参考1:black hat ppt
- 参考2:论文
博客参考
参考1:Y4tacker师傅的博客
参考2:Seebug
参考3:Phar与php rce的深入挖掘 (强推,phar反序列化的原理解释的很清楚)
参考3:p神离别歌
Phar中的元信息不再自动进行反序列化了,
phar://
触发反序列化的姿势也告别了。——p神关于php 8.0 改动的博客
注:复现最好在8.0之前的版本做(不是最好,是一定,,因为php 8.0后phar://
触发不了反序列化了)
Phar简介
Phar:参考php手册 (吐槽一下这个中文版手册除了简介两个字是中文愣是没有一句话是翻译出来的)
The phar extension provides a way to put entire PHP applications into a single file called a “phar” (PHP Archive) for easy distribution and installation.
——php手册
还不太懂?对比下jar和phar的维基解释:
A JAR (Java ARchive) is a package file format typically used to aggregate many Java class files and associated metadata and resources (text, images, etc.) into one file for distribution.
——wiki)
In software, a PHAR (PHP Archive) file is a package format to enable distribution of applications and libraries by bundling many PHP code files and other resources (e.g. images, stylesheets, etc.) into a single archive file.
——wiki)
简而言之,phar就是像java中的jar一样,是一种可以将整个php应用打包以便于部署的打包文件(本质是个压缩文件)
文件结构
Stub(参考php手册)
A PHP file that will bootstrap the archive. The stub must contain the
__HALT_COMPILER();
token, and the default stub includes the ability to run a PHAR with or without the PHP extension enabled。以
__HALT_COMPILER();
结尾的标志,令php扩展可以将其识别为phar文件php手册中说可以不要
?>
,不过在生成phar包的时候好像会自动带上?>
Manifest
The manifest details the contents of the archive.
在phar中的每个文件的属性等信息都在其中,关键点在于用户自定义的meta-data会以
serialize()
的方式存在这里面(这也是攻击的核心,主要就是利用解析phar时对meta-data的反序列化)Contents
The original files that are included in the archive.
被压缩的文件内容
Signature
签名,在文件末尾
010下打开phar包,可以清晰的看到stub的标志、meta-data的序列化内容
图片来源:BlackHat演讲ppt
Phar生成与打包
生成phar时若报错如下
1 | creating archive "xxx.phar" disabled by the php.ini setting phar.readonly |
需要修改php.ini配置,把phar.readonly=on去掉注释,然后再改为off
1 | [Phar] |
1 |
|
生成的myTest.phar目录结构如下
此时查看myTest.phar的二进制文件,可以发现命令以明文方式存在,如果遇到过滤则无法通过
漏洞原理
漏洞触发点在使用phar://协议读取文件的时候,文件内容会被解析成phar对象,然后phar对象内的Metadata信息会被反序列化。
参考开头放过了….写这个的间隔太久了都忘了,,
触发函数
大部分文件操作的函数都可以触发
来源:https://paper.seebug.org/680/
不过其实不止上面这些函数可以触发,在 https://blog.zsxsoft.com/post/38 这篇文章里,详细描述了phar反序列化漏洞的触发机制,以及其他一些可用函数和奇淫技巧
Demo测试:
利用条件
- phar文件能够上传
- 有可用的魔术方法作为跳板
- 文件操作函数的参数可控
Bypass
压缩文件绕过
- 若题目对
HALT_COMPILER()
及各类命令执行语句进行过滤
新建文件夹.phar
,在文件夹下新建.metadata
文件,写入序列化数据O:1:"A":1:{s:1:"a";s:6:"TEST!!";}
,将.phar
文件夹压缩为1.tar.gz如下,发现已经不存在明文(1.tar时还是存在明文的)
使用phar://1.tar.gz
即可读取并触发反序列化
头部字符串禁phar绕过
压缩过滤器触发phar时解决phar:// 不能出现在首部
1 | compress.bzip://phar://... |
这里测试时要注意,php默认不开启bzip2(bz2)支持,需要在php.ini 867行(可能有差)将
extension=php_bz2.dll
的注释取消否则会报
Unable to find the wrapper "compress.bzip2"
并且在php.ini 725行(可能有差)将
extension_dir
修改为自己的ext路径(我的是extension_dir = "D:/DevelopTools/php-7.0.0/ext"
,然后记得要用斜杠而不是反斜杠)否则会报
PHP Startup: Unable to load dynamic library
(好像ext不设置的话默认路径是C:/php/ext(windows))
经测试均能触发反序列化
Gif绕过
由于php中判断一个文件是不是phar是根据有没有__HALT_COMPILER();
来判断的,而不管其前后,因此在文件头写入GIF的文件头,可以让文件被识别为gif的同时,也能被phar://解析
在生成phar时,通过setStub
在文件头部添加GIF89a
的gif头部标志,生成后再修改后缀名为gif
$phar->setStub(“GIF89a”."<?php __HALT_COMPILER(); ?>");
先生成一个gifTest.phar后修改后缀为gifTest.gif,再用phar://去读,发现仍然可以反序列化,并且获取文件信息发现是GIF,可以绕过文件类型检测
获取文件类型的finfo函数也需要在php.ini内注释掉
extension=php_fileinfo.dll
来支持扩展