作品发布     邀请码    设为首页  收藏 

当前位置:文章漏洞 → 文章内容 >> CVE-2014-1772 – IE浏览器 Use After Free 漏洞详细分析


CVE-2014-1772 – IE浏览器 Use After Free 漏洞详细分析

更新时间:2014-11-15 16:56:32   作者:佚名  来源:不详

http://blog.trendmicro.com/trendlabs-security-intelligence/root-cause-analysis-of-cve-2014-1772-an-internet-explorer-use-after-free-vulnerability/

译自TrendLabs

http://hackdig-h.stor.sinaapp.com/pictures/month_1411/201411120135227445.jpg

我们经常会看到各种各样的漏洞,从user-after-free漏洞,类型混淆漏洞,缓冲区溢出到XSS攻击。但最重要的是要理解漏洞的根本原因,本篇文章从根源上分析了一个IE浏览器漏洞(CVE-2014-1772)

这个漏洞TrendLabs在今年私下发给微软,并且成为微软6月份补丁,编号MS14-035。尽管这个漏洞已经修复,它仍然是个值得学习的UAF案例。

触发这个漏洞的POC如下:

http://hackdig-h.stor.sinaapp.com/pictures/month_1411/201411120135237040.png



1. 触发漏洞的HTML代码

在调试之前,为了便于分析,几个标志位必须提前设置好。使用gflags.exe /i iexplore.exe +hpa +us命令启用page heap (HPA)user stack trace (UST)。这可以使查找内存数据损坏和追踪堆分配更简单。这个文件可以在Windbg安装目录下找到。你现在可以运行Windbg附加IE进程,然后使用它去浏览HTML文件。

通过检测JavaScript的运行流程,崩溃发生在第18行代码运行时。

http://hackdig-h.stor.sinaapp.com/pictures/month_1411/201411120135241777.png


崩溃代码输出

我们可以看到EDI寄存器指向了一段释放后的内存空间,导致访问违规。

我们查看下面的代码来看看EDI寄存器的值。

http://hackdig-h.stor.sinaapp.com/pictures/month_1411/201411120135243521.png


3汇编代码

上面的代码可以看出EDICTreePos*类型,是第一个参数。我们可以认为EDI是指向CTreePos的指针。因为CTreePos对象已经释放,我们怎么得到这个对象释放的位置?因为UST标志位已经设置,我们可以使用windbg 中的!heap -p -a edi命令。

http://hackdig-h.stor.sinaapp.com/pictures/month_1411/201411120135251016.png


调用堆栈

上图显示的是CTreePos对象释放后的调用过程。其中有很多关键信息。我们可以看到CMarkup::FreeTreePos方法;这里有证据可以显示CTreePos存在use-after-free问题。

因为他是use-after-free问题,我们希望深入了解这个问题。我们首先需要定位CTreePos对象创建,释放和重新使用的位置。图4可以看出对象释放的位置。为了找出重用的位置,我们需要分析崩溃点,调用堆栈如下。

http://hackdig-h.stor.sinaapp.com/pictures/month_1411/201411120135267598.png


调用堆栈

我们怎么找出CTreePos对象创建的位置?我喜欢使用重新跑一遍代码,在对象释放点下断点然后使用!heap -p -a xxxx命令来回溯到对象创建的位置。调用栈如下:

http://hackdig-h.stor.sinaapp.com/pictures/month_1411/201411120135265037.png


6调用堆栈

针对UAF问题,我喜欢去对比3处位置(创建,释放和重用)来找线索。

http://hackdig-h.stor.sinaapp.com/pictures/month_1411/201411120135276514.png

7调用堆栈

在图7中有三列,他们分别是对象创建,释放和重用的调用栈。

其中有不少有用信息。首先我们找到3者之间的联系。在黄色线下方,CDoc::CutCopyMove是创建调用栈和释放栈的最后一个方法。这意味着运行流程创建了CTreePos对象并且在Doc::CutCopyMove中释放了它。在红色线下方可以看到,运行流程释放了它并且在CSpliceTreeEngine::InsertSplice中重新使用导致崩溃。

在第二栏,我们可以看到CSpliceTreeEngine::InsertSplice方法在执行过程中遇到一个错误然后调用了Fire_onerror方法。这个方法会调用JavaScript对象的onerror事件。在这个事件中,会调用CMarkupPointer::UnEmbed来释放这个对象。

目前为止,我们有4个问题:

1. 为什么它会触发一个onerror事件

2. 为什么它创建了CTreePos对象

3. 为什么它释放了CTreePos对象

4. 为什么它再次使用了释放后的对象

在回答这些问题之前,我想要总结一下IE浏览器DOM数实现的背景知识。因为IE没有开放源代码,这些信息通过逆向工程获得。所以不可能保证100%准确。

一个页面包含CMarkup对象来表示页面的结构或者DOM数。CMarkup对象包含一个指向根CElement对象的指针。CElement对象是很多实体类的父类。在图1Javascript对象e_1e_2是继承自CElementCObjectElement对象。CElement对象存在一个指向CTreeNode对象的指针。CTreeNode对象还存在一个与CElement对象相关的指针。CTreeNode的对象有一对指向CTreePos对象的指针。

那为什么一个CTreePos是必须的?因为IE使用了伸展树算法(Splay Tree)来操控DOM树。在伸展树算法树中CTreePos对象作为一个节点。CMarkupPointer对象代表CMarkup对象中的一个地址。所以CMarkupPointer对象有一个指向CTreePos对象的指针来代表他的地址。CMarkup对象有很多与UAF相关的状态。

嵌入状态:这意味着CMarkupPointer创建了CTreePos对象并加入了伸展树中。

非嵌入状态:这意味着CMarkupPointerCTreePos对象移出伸展树并释放。

下图展示了伸展树的交互过程:

http://hackdig-h.stor.sinaapp.com/pictures/month_1411/201411120135271387.png


伸展树

现在回到前面提到的4个问题

为什么它会触发一个onerror事件

从图1Javascript代码中,我们可以看到e_2.onerror设置了一个处理方法在代码22行,e_2.swapNode会触发DOM树变化;这就会调用CObjectElement::CreateObject方法这个方法检查了对象的CLSID。因为e_2CLSID没有设置,导致触发onerror的事件处理器。

22行的处理器处,Javascript代码r.insertNode(e_2)会改变DOM树一遍并且改变CObjectElement::CreateObject(因为e_2没有CLSID)它会再次触发onerror事件处理器。这个处理器第二次运行时(r.setEnd(document.all[1],0)代码处),它会释放CTreePos对象。

为什么它创建了CTreePos对象

从图6中可以看到,CTreePos对象在调用CDomRange::InsertNode方法时生成。我们可以关联这个方法到图119行—r.insertNode(e_2)CDomRange::InserNode方法会把元素插入到DOM树中。一个叫Doc::CutCopyMove的方法接受几个参数输入,可以修改和移动DOM树。它的第一个CMarkupPointer类型的参数是CMarkup(DOM)的起始地址。第二个CMarkupPointer类型的参数是CMarkup(DOM)的结束地址。第三个CMarkupPointer类型参数是指向CMarkup的目的地址。

Doc::CutCopyMove会拷贝和移动子DOM树到目的DOM树。因为使用了扩展树算法(使用CTreePos作为一个节点)Doc::CutCopyMove需要通过源和目的地址创建一个CTreePos对象并且把它加入到扩展树。Doc::CutCopyMove 调用 CMarkup::DoEmbedPointers 来使得 CMarkupPointer变为嵌入状态最后, CTreePos 对象被创建这就为e_1元素创建了UAF CTreePos对象。

为什么它释放了CTreePos对象

从调用栈去追踪CTreePos 对象的释放( 4), 我们可以找到CDomRange::setEnd方法这个方法可以对应到图117: r.setEnd(e_1,0)。这意味着CTreePos 对象是setEnd的一个实现. CDomRange::setEnd方法是为了替换原始的末指针为新的指针。这个方法最终调用CMarkupPointer::MoveToPointer 来移动DOM树。它首先会调用 CMarkupPointer::UnEmbed 来把CMarkupPointer 对象变为非嵌入状态并从扩展树移除并释放CTreePos。代码r.setEnd的参数是e_1元素。所以CTreePos 对象相关的e_1元素也被一起释放。

为什么它再次使用了释放后的对象

在图7中,红线下方是这个方法在调用CSpliceTreeEngine::InsertSpliceB列为CSpliceTreeEngine::InsertSplice+0x13ffC列是CSpliceTreeEngine::InsertSplice+0x6EDD4AB列是释放调用的堆栈追踪。C列是“重用”调用堆栈追踪。这就意味着释放和重用发生在一个方法(CSpliceTreeEngine::InsertSplice)调用之中。我们继续跟踪方法的执行流程,可以找到:

http://hackdig-h.stor.sinaapp.com/pictures/month_1411/201411120135281920.png


9汇编代码

指令 636898C4, eax UAF CTreePos Objects的地址。这个方法保存了这个地址到一个本地变量var_1E4。然后运行到 6368AA9A

http://hackdig-h.stor.sinaapp.com/pictures/month_1411/201411120135297027.png


10 汇编代码

在 6368AA9A处,它调用了一个虚函数CObjectElement::Notify。 我们可以从图7B列找到。这意味着当执行到这个调用时,他会遇到一个错误并且调用onerror事件处理器。这个过程释放了CTreePos 对象。然而CSpliceTreeEngine::InsertSplice 方法的本地变量var_1E4 中存在一个指向释放后对象的引用。然后执行到63D7735B处。

63D7735B , 他调用CElment::RecordTextChange ForTsfvar_1E4作为第二个参数。当这个方法运行的时候,有任何指令访问 CTreePos 对象的内容时就会产生崩溃。

总结

总之,UAF的根本原因存在于事件交互环境之中—CSpliceTreeEngine::InsertSplice处理本地变量引用验证不当。

DOM是基于事件机制。要想彻底在复杂的交互环境中解决UAF是一个难题。最近Microsoft发布的一系列补丁中引入了内存保护机制,从而减轻了UAF问题。这也是为什么我们要尽可能升级到最新版本。新技术的引入给攻击者带来更高的攻击成本,也使得整体安全性得到提升。

责任编辑:华中帝国        



本文引用网址: 

CVE-2014-1772 – IE浏览器 Use After Free 漏洞详细分析的相关文章
发表评论

用户名: 查看更多评论

分 值:100分 85分 70分 55分 40分 25分 10分 0分

内 容:

         (注“”为必填内容。) 验证码: 验证码,看不清楚?请点击刷新验证码