CVE-2014-0322 UAF Analysis

这是上周面试管家时,让我写的漏洞分析报告。虽然最后没去管家,目前,还是不想离开成都:)。

前言

分析环境:

受影响的文件:

漏洞概述:

使用的POC代码如下(来自这里):

为了方便分析,关闭ASLR、切换IE为单进程:

漏洞调试

WinDbg加载IE,打开poc.htm文件,导致内存访问异常。异常信息如下:

触发异常的函数如下:

eax来自于edx,查看edx:

这段代码在访问CMarkup对象的时候,企图从CMarkup的0x0AC偏移中取出另外一个对象,并尝试对该对象0x10处的成员进行自增。由于之前的代码存在漏洞,导致CMarkup对象的内容已经被覆盖,0x10处已经被覆盖为0x41414141, 故尝试自增导致了内存访问异常。所以,需要跟踪CMarkup对象的分配和释放情况。
为了跟踪CMarkup对象的分配和释放情况,可以通过对其构造函数和虚构函数进行监视:

根据分析,在CMarkup::CMarkup的时候,esi指向为该对象分配的内存,CMarkup::~CMarkup的时候则是ecx。
为了准确定位触发漏洞的JavaScript语句,可以使用Math函数输出Log作为Trace,对于新版的Internet Explorer使用的JScript9,可使用如下代码:

接下来修改poc的代码如下:

重新用WinDbg载入IE并运行脚本,得到的LOG如下:

所以,漏洞触发的大体流程如下:

现在需要跟踪CMarkup A对象的分配和释放情况,以便于定位存在漏洞的函数。
通过修改脚本,去掉了“g;”,可以视为对JavaScript的单步。appendChild开始,记录到的CMarkup A对象为0561be50。去掉其他断点,保留对析构函数的断点。当然断下后,ecx=0561be50,查看调用栈如下:

根据调用栈,可以知道,实际上释放CMarkup A对象的代码在函数mshtml!InjectHtmlStream中,对应的代码如下:

该函数头部有对CMarkup对象进行AddRef的操作:

查看CMarkup对象的虚表:

根据上述信息,可知CMarkup使用了类似于智能指针的东西,在引用对象的时候,调用AddRef增加计数;在不需要该对象的时候,调用Release减少引用计数;当引用计数为0的时候,从内存中删除该对象。所以,现在需要跟踪0561be50引用计数的情况。
在执行到mshtml!InjectHtmlStream的时候断下,此时需要跟踪CMarkup A对象在这个scope中的引用情况。
所以,分别对mshtml!CMarkup::AddRef和mshtml!CMarkup::Release函数下断点,根据下面代码,edi和esi分别为要操作的对象,0561be50是需要观察的值。

以下信息记录了mshtml!InjectHtmlStream中对0561be50引用计数的操作:
1. CMarkup::AddRef

2. CMarkup::AddRef

3. CMarkup::Release

4. CMarkup::Release

5. CMarkup::Release

AddRef和Release的次数为奇数,异常的Release操作就在这其中。对应的分析如下:

所以,出问题的是第(3)次的Release。
在该操作之前没有对调用CMarkup::AddRef。在没Ref的情况下对CMarkup进行Release,导致了mshtml!InjectHtmlStream结束的时候,CMarkup对象已经被释放。
根据(3)的CallStack,找到对应的释放代码:

根据上述信息,定位到了真正发生错误的代码。最后执行的路径是CSpliceTreeEngine::RemoveSplice -> CElement::PrivateExitTree。
根据上述信息,没法准确的判断漏洞是如何产生的,下面通过对比打补丁前后的文件,查找漏洞的成因。
补丁后的文件:

先是10.00.9200.16843,进入CSpliceTreeEngine::RemoveSplice的时候:

10.00.9200.16843的CElement::PrivateExitTree函数中释放的代码:

可见,在10.00.9200.16843中,CMarkup::AddRef和CMarkup::Release已经配对。
而10.0.9200.16384的是这样的,进入的CSpliceTreeEngine::RemoveSplice的时候:

离开CSpliceTreeEngine::RemoveSplice:

CMarkup::CLock类,不出意外的只是负责维护引用计数:

而在CElement::PrivateExitTree中,使用CMarkup::Release减少引用次数:

目前,可以猜测这个地方有两个程序员在维护这些代码,前者希望通过CMarkup::CLock来释放引用计数(RAII)。而这个函数提供了另外一个负责资源释放的函数,即CElement::PrivateExitTree。
维护这个函数的程序员不知道前者使用了CMarkup::CLock,简单粗暴的使用了CMarkup::Release()引用计数,导致了AddRef和Release的不平衡,最终导致appendChild分配的对象过早释放,当appendChild使用的时候,造成UAF。
最终,在调用MSHTML!CMarkup::UpdateMarkupContentsVersion的时候,能够触发任意地址内容加1的漏洞。

CVE-2014-0322 UAF Analysis》上有4条评论

发表评论