用最新IE 0day获取RCE绕过ASLR

By Zing - 2014-08-24

原文链接(翻译:Zing)

文章提到的ie 0day链接

词汇解释:

RCE:远程代码执行

LSB:最低有效位

BSTR:“Basic STRing”的简称,微软在COM/OLE中定义的标准字符串数据类型。

译文

概述

最近关于IE 0day被野外利用的事传的沸沸扬扬。FireEye利用了这个漏洞,博客中提到利用了一个flash的bug来绕过ASLR。引起了ZDI注意,我们研究能否在不使用flash的bug的情况下,利用同样的IE bug绕过ASLR和DEP。

初始崩溃

在图1使用pageheap,浏览器在图1所示的函数处崩溃:


图1

崩溃时的栈回溯:


图2

此处的释放:


图3

控制

为了填充释放的内存,我们需要获得对象的长度


图4

填充释放的对象相对来说简单,崩溃看起来是这样的:


图5

利用

根据网上的报告,野外发现的利用方法使用了flash来绕过ASLR
我们来看一下崩溃点附近的汇编代码,来理解为了获取RCE的选择。实验环境为32位 Windows 8.1 ,IE11
如果我们后退一步检查CMarkup::IsConnectedToPrimaryMarkup附近的函数和指令,可以看到返回前有一个可控的call指令:


图6

看起来是合法的,并且在我们的控制之下:


图7

到目前为止,我们知道可以通过这个bug来获得RCE。现在的问题是我们能不能泄漏这个bug。

ASLR绕过

计划是找到一个可控的指令:
1.write-4
2.write-0
3.ADD [controlled],X
4.INC [controlled]
5.DEC [controlled]
6.AND [controlled],XXXXXXX
7.等等..

上面的选项允许我们做下列事情中的一件:
1.改变内存中一些BSTR的长度引发内存泄漏。
2.欺骗IE让它以为一些数字是实际的对象,从而触发类型混淆

CMarkup::IsConnectedToPrimaryMarkup执行之后调用了几个函数。我不会细述所有的函数调用,只强调其中有趣的。

CElement::EnsureFormatCacheChange():

在这个函数内部,我们可以走到调用CElement::EnsureFormatCacheChange()的地方。在CElement::EnsureFormatCacheChange()函数内部,调用了CMarkup::ClearRunCaches():

CMarkup::ClearRunCaches()包含一些有趣的指令。我们可以控制和执行。其中的一些允许可控的空字节,其他的允许可控地址最低有效位(LSB)归零,就像下面这个AND指令一样:


图8

这有助于制造类型混淆。
另外我个人用来引发类型混淆的一个函数是:CView::AddInvalidationTask()

CView::AddInvalidationTask()

如果我们检查函数内部的汇编指令,可以看到一些很有趣的东西:


图9

有一个潜在可控的INC指令。
但是我们真的能控制它吗?


图10

好的,是可以控制的。
这就给了我们两个选择,要么修改BSTR的长度,要么通过控制INC指令并且将LSB设为0来触发类型混淆。

触发类型混淆采取的策略是:

1.在内存中放一个IE认为是数字的值
2.INC这个值,然后LSB为0,这样IE会认为它是个对象
3.修改地址指向的位置,伪造对象
4.使用这个对象读取内存,引发内存地址泄漏

如果一切和计划的一样,会引发基址泄漏


图10

利用中的问题

下面是一些要考虑的问题:
1.尝试多次触发这个bug
2.在CLock:CLock上崩溃
3.绕过RET前面的CALL

为了多次触发这个bug(触发混淆所需要的),我需要重新编译这个文件。使用ducument.write()重写引发这个bug的HTML元素。

第二个问题是制造CLock:CLock上的崩溃使其难以继续执行。

如果我们退回到MSHTML!CView::AddInvalidationTask中,会发现调用了CView::PostCloseView的。

在CView::PostCloseView内部,我们应该执行一个test,然后提前退出:


图12

如果我们不执行那个jump退出,CLock::CLock会在刚触发bug的时候结束,也就不能多次触发了。

最后一个问题是绕过CALL命令获取RCE。

这个问题解决起来很容易:


图13

如果在test处ECX为0,那么我们就可以绕过这个虚拟call,干净的退出。
这就是所有我们可以控制的。到此问题解决了。

整个漏洞利用结构图(红色的部分应该绕过):


图14

当你实际上只能选择一个bug来利用的时候同时用两个是很费事的。Flash的bug已经被使用很多次了。使用已知的bug增加了被检测到的可能性,攻击者不使用它也就不会很快被发现。投入时间研究use-after-free漏洞附近的基本类型是有好处的,减少了代码执行的bug。

From Z1ng'Blog