什么是Phar
jar是开发java程序的应用,包括所有可执行,可访问的文件打包,方便部署; phar是php里类似jar的一种打包文件
对于php5.3或更高版本,phar后缀文件是默认开启支持的,可以直接使用它
Phar结构
stub phar文件标识,格式为xxx<?php xxx;HALT_COMPiLER0;?>;
(头部信息)
manifest压缩文件的属性等信息,以序列化存储:
contents压缩文件的内容;
signature签名,放在文件末尾;
Phar协议解析文件时,会自动触发对nanifest字段的序列化字符串进行反序列化;
实验一(基本的phar利用)
创建一个test002.php
1 |
|
创建一个test.php用来生成phar;Phar需要PHP >=5.2在php.ini中将phar.readonly设为off,否则生成phar文件时会报错
执行test.php生成phar文件
1 |
|
生成的phar.phar文件结构如下:
1 | --phar.phar |
1 | #.metadata.bin |
1 | stub.php |
最终成功执行
受影响的函数
1 | fileatime |
一些绕过方式
伪造成其他格式的文件
在前面分析phar的文件结构时可能会注意到,php识别phar文件是通过其文件头的stub,更确切一点来说是__HALT_COMPILER();?>
这段代码,对前面的内容或者后缀名是没有要求的。那么我们就可以通过添加任意的文件头+修改后缀名的方式将phar文件伪装成其他格式的文件。
1 | $phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); ///设置stub,增加gif文件头 |
phar不能出现在前面的字符
1 | compress.bzip://phar:///test.phar/test.txt |
值得注意的是:那些可以使得phar文件的metadata反序列化的函数需要支持compress.bzip:
或者php://filter
协议等才行,比如if_file
就不行
绕过后缀检查
将phar.phar更改后缀不影响phar文件的最终执行,所以这一点很好绕过白名单
过滤__HALT_COMPILER();
将phar文件进行gzip压缩 ,使用压缩后phar文件同样也能反序列化 (常用)
linux下使用命令gzip phar.phar
生成
phar 文件签名修改
对于某些情况,我们需要修改phar文件中的内容而达到某些需求(比如要绕过__wakeup要修改属性数量),而修改后的phar文件由于文件发生改变,所以须要修改签名才能正常使用
(__wakeup绕过:在 PHP5 < 5.6.25, PHP7 < 7.0.10 的版本)
以默认的sha1签名为例:
1 | from hashlib import sha1 |
实验
1 |
|
生成phar.phar文件
1 |
|
可以看到被__wakeup
拦截了
执行脚本,绕过wakeup
1 | from hashlib import sha1 |
生成newPhar.phar
;成功绕过
Phar利用条件
- phar文件要能够上传到服务器端。
- 要有可用的魔术方法作为“跳板”。
- 文件操作函数的参数可控,且
:
、/
、phar
等特殊字符没有被过滤。
补充
Phar文件包含
上面讲的都是phar反序列化;本题是利用phar文件包含;来自ctfshow-web803
1 |
|
存在文件上传(当前目录确实是/var/www/html;但是没有权限);文件包含对后缀有限制,并且文件名有过滤;
利用phar文件绕过;生成一个phar后门文件
1 |
|
再利用python脚本,当前没有权限可以写,那就写到/tmp
目录下
1 | import requests |
确实没有可写的权限,
1 | '1': 'system("id");' |
其实这里一开始我是想借用zip伪协议包含绕过的;像下面一样
生成一个test.txt
文件,内容如下;再压缩为test.zip
文件
1 | phpinfo(); |
测试代码如下:
1 |
|
发现是可以成功的;
但是这个办法不可以用来解决web803;因为zip协议在file_exists
判断不出来是文件