CVE-2013-3893 UAF Analysis

Intro

前段时间工作中一直在干一些乱七八糟的事情,重心基本都是在Android上,掐指一算大概也有几个月没在Windows上用过调试器了。昨天心血来潮分析了一下IE的CVE-2013-3893漏洞。

POC

POC来自这里,使用XP下的IE8作为调试对象:

调试过程
定位出错对象

IE加载原始的POC,异常中断时的信息如下:

CallStack:

异常的地址位于CElement::Doc函数的第一句:

显然,尝试在获取当前CElement对象的虚表时,发生了内存访问异常错误,当前的对象即ECX的值为feeefeee,即包含了这个CElement的对象在释放后被使用,该对象的内存已经被设为feeefeee,尝试从该对象中取出的CElement对象是一个不存在的对象。
往上一层看代码,当前属于CTreeNode的代码:

根据代码,该CTreeNode偏移0处保存了一个CElement对象的地址,ESI为CTreeNode对象,查看当前对象的内存:

所以,产生异常的对象是CTreeNode。

跟踪对象释放情况

修改POC代码,按照惯例加入Math.atan2

调试器载入IE后,使用sxe ld JScript.dll下断点。接下来载入POC页面,此时由于IE加载JScript.dll,调试器会中断,然后利用如下断点进行整体流程和对象的跟踪:

结果如下:

根据上述Log,可以看到,产生UAF的CTreeNode是最初分配的,姑且称之为Root_0,因为我发现之后Append的两个对象的父节点都是它。CTreeNode +0处是该节点对应的CElement,+4是父节点。
之前的流程都比较清晰,由于id_0设置了onlosecapture回调,id_1调用setCapture()时会导致id_0的onlosecapture回调被调用。而onlosecapture中的document.write(“”);则会导致之前的对象被释放。从逻辑上来看,应该是setCapture内部没有对CTreeNode处理完善,在id_1调用setCapture的某个环节,id_0的onlosecapture被执行,document.write把最初的CTreeNode被释放,之后回到setCapture中,继续使用了该对象,导致UAF。

UAF原因分析

setCapture对应的处理代码位于CDoc::SetMouseCapture,第二次进入CDoc::SetMouseCapture也就是id_1调用的时候,走到的关键代码是这里:

635F3F68的时候,eax是最初创建的CElement对象,+14是对应的CTreeNode,此时,两个对象都还没有被释放。之后调用了CDoc::ReleaseDetachedCaptures。在ReleaseDetachedCaptures函数中,会重新进入CDoc::SetMouseCapture,并走到调用CDoc::ClearMouseCapture,该函数会导致onlosecapture回调的触发:

之后就是进入onlosecapture,执行document.write,CTreeNode被释放。然而,PumpMessage在ReleaseDetachedCaptures之后的代码中,直接使用了保存在栈中的CTreeNode对象,最终通过635F3FDF处调用CTreeNode::NodeAddRef访问到了已经释放的CTreeNode对象。
大体上,触发UAF的原因是:

  1. 保存CTreeNode到栈中;
  2. 调用ReleaseDetachedCaptures导致栈中的对象被释放;
  3. 没有做详细检查直接使用该对象。
未完待续

这次注意到了一些有意思的地方,如:

  • 元素被加入到DOM树的时候,需要用CTreeNode表示各个结点,每个CTreeNode都有其对应的元素(即CElement)和父节点的CTreeNode。
  • document.write导致原始的DOM树失效,并重新建立一个。
  • id_0[‘outerText’]=””;导致了两个元素对应的节点都被摘除。

由于太多细节不清楚,对此还是一知半解,等以后分析再慢慢补了。

参考资料

  1. http://zenhumany.blog.163.com/blog/static/17180663320139305259394/

发表评论