CVE-2013-3897 UAF Analysis

前几天面试管家,让我分析一个IE10以上的漏洞并给出详细报告,我挑了个CVE-2014-0322。从前都是从崩溃点之后开始分析ShellCode,这次把前前后后的细节都看了一遍,受益匪浅。趁着有感觉,今天又看了一下CVE-2013-3897,发现出错的逻辑是一样的,均和AddRef有关。
POC来自这里
分析的目标是Windows XP Professional SP3下IE8的mshtml.dll文件,详细信息如下:

这里只记录一下崩溃点之前对象的LifeTime,这也是UAF的主要原因。
IE内部对对象的管理,几乎都使用了这种方法。摘录一段:

AddRef和Release的功能不言而喻,类似于智能指针,这俩函数用于维护引用计数。当有函数引用对象的时候,应该调用AddRef增加计数,在用完之后调用Release减少计数。而当对象内部计数为0的时候,Release内部会自动释放掉对象。
这个设计的初衷是好的,但是手动档实在不好,程序员在使用的时候经常会手贱多加一个AddRef或者遗漏Release。忘记AddRef可能导致UAF,忘记Release则导致内存泄漏。
通过POC的崩溃点可以很容易的知道,被UAF的是一个CDisplayPointer对象,在进入CDisplayPointer::ScrollIntoView的时候,该对象还是好的。

之后的流程会往CDoc::ScrollPointerIntoView走,走了很多很多代码之后,最后会到这里:

ClearInterfaceFn将调用这个CDisplayPointer的Release函数,减少引用计数,并释放该对象。之后的代码,还会继续使用该对象,导致了UAF。
到这里,可以判断,CDisplayPointer的引用计数一定出了问题,至于是在CSelectTracker::Destroy手贱多写了一句,还是在CDisplayPointer::ScrollIntoView之前就忘记AddRef了,不得而知。
对于这种情况,只能通过补丁后的代码进行对比,分析是什么地方出了问题。用于进行对比的文件信息如下:

首先对比CSelectTracker::Destroy,看看是否手贱:

没有问题。那肯定就是在CDisplayPointer::ScrollIntoView之前忘记了AddRef。在CDisplayPointer::ScrollIntoView下断点观察之后,发现补丁后的版本,在进入CDisplayPointer::ScrollIntoView的时候,该CDisplayPointer的引用计数为2。所以,目前已经十分明显,在CDisplayPointer::ScrollIntoView之前的代码中,某处对CDisplayPointer的操作忘记了AddRef。
要找到这个地方只能通过补丁后的版本来跟踪。跟踪的方法和简单:首先,找个地方停下来,拍个快照,此举是为了保证堆地址不会变化;然后记录所有CDisplayPointer的构造函数,对比进入CDisplayPointer::ScrollIntoView时候的CDisplayPointer对象,得到我们需要的CDisplayPointer对象地址;接下来恢复快照,对这个对象+4的地方进行内存写入操作监视,对于IE的大部分对象来说,+4偏移处的含义是该对象的引用计数。在进入CDisplayPointer::ScrollIntoView之前的最后一次AddRef,也便是原来忘记添加的AddRef。
以下代码说明了这个补丁的原因以及修补方法:
8.00.6001.18702中CDisplayPointer对象的虚表:

对应的代码片段:

8.00.6001.23569中CDisplayPointer对象的虚表:

包含补丁的代码片段:

补丁后的代码在CHTMLEditor::SelectRangeInternal中增加了对AddRef的调用。可见,原来导致漏洞的原因就是因为在CHTMLEditor::SelectRangeInternal忘记对CDisplayPointer进行AddRef。如果把3C96DC4F的两句去掉,原来的POC还是会Crash掉IE,这也证明了漏洞的根源再次。
至于为什么会在这,恐怕得十分熟悉mshtml才能解释了。

CVE-2013-3897 UAF Analysis》上有4条评论

  1. Danny

    博主,还有一个问题,我没有明白为什么在定位CDisplayPointer引用计数问题的时候,只在CSelectTracker::Destroy调用ClearInterfaceFn前判断有没有多写Release呢?而不会在CSelectTracker::Destroy的其他位置或其他函数内调用Release?
    我对COM还不太熟,最近陆续在看微软的官方文档,ClearInterfaceFn是不是与QueryInterface对应的,用于释放对对象的引用。
    再次感谢分享~

    回复
    1. TheCjw 文章作者

      似乎我也忘记我怎么做的了。
      不过这样做是有缺陷的,建议使用内存断点来监视。
      上次有个哥们给我发邮件讨论了一下,我这样做有缺陷,但目前在忙别的,这块没深究了。

      回复

发表评论