知识点:
php代码审计,文件读取漏洞,文件上传绕过,phar协议反序列化漏洞
开始
打开靶场
首先有一个查询文件的功能和一个文件读取的功能,一开始以为是文件上传的漏洞,嘎嘎传(虽然我也不太熟悉文件上传),后面发现不行,应该是网站在后端限制了文件上传的后缀,观察到这里有个文件查询的功能应该是文件读取,试一下直接读flag
不行,那就直接读取当前页面index.php,
成功
复制出来
通过代码审计,我们可以看到,这里有php的魔术方法,有对flag的正则匹配限制,但是这里没有unserialize()函数,猜想这里应该是利用了phar协议的反序列化来拿flag
Phar反序列化
Phar之所以能反序列化,是因为Phar文件会以序列化的形式存储用户自定义的meta-data,PHP使用phar_parse_metadata在解析meta数据时,会调用php_var_unserialize进行反序列化操作。
通过f12看到还有一个upload.php文件,读它复制出来
可以看到首先是对文件后缀的限制,然后是对phar文件里的_HALT_COMPILER();进行匹配,这个函数是phar文件的标志性函数,这种限制手法是有漏洞的,可以绕过的,我们可以将phar文件用linux的gzip进行压缩来加密它,以此来绕过此检测,在上面的魔术方法的图里看到了wakeup函数,在php低版本里,可以通过修改属性个数大于实际属性个数,来绕过wakeup函数,但是因为phar文件生成时是自动进行序列化的,所以我们我们需要修改文件,phar文件生成时会进行签名,来防止被修改,所以修改文件后我们需要对phar文件重新签名,phar文件有几种不同的加密签名选择,默认签名方法应该是要看生成phar文件的php版本
构造恶意phar文件
生成文件
修改文件
通过winhex来修改属性个数
然后再利用修复签名的python脚本,将签名修复
python脚本
from hashlib import sha256
with open('test.phar', 'rb') as file:
f = file.read()
s = f[:-28] # 获取要签名的数据
h = f[-8:] # 获取签名类型和GBMB标识
newf = s + sha256(s).digest() + h # 数据 + 签名 + (类型 + GBMB)
with open('newtest.phar', 'wb') as file:
file.write(newf) # 写入新文件
通过kali自带的gzip对phar文件进行压缩
不压缩的话phar的文件头还是会被识别出来
然后修改文件后缀为任意白名单后缀上传,解毕