前言
CVE-2012-0158
出现在MSCOMCTL.OCX
,微软Office在处理MSCOMCTL
的ListView
控件的时候的失误,导致攻击者可以通过构造恶意的文档执行任意代码。
环境
系统: windows XP SP3
office
版本:2003 11.5612.5606
调试分析
打开poc.doc
,程序崩溃在0x41414141
:
1 2 3 4 5 |
eax=00000000 ebx=03e90810 ecx=7c93003d edx=00140608 esi=0018865c edi=00000000 eip=41414141 esp=00121060 ebp=00000000 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 41414141 ?? ??? |
栈回溯发现什么也没有,也无法切换到上一层栈帧,用immunity debugger
调试发现此时的栈情况为:
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 |
001216D0 00008282 倐.. 001216D4 00121708 . 001216D8 275A273D ='Z' 001216DC 00121700 .. 001216E0 05DB1FF0 ?? 001216E4 00008282 倐.. 001216E8 00000000 .... 001216EC 05E086C4 膯? 001216F0 09D60810 ? 001216F4 6A626F43 Cobj 001216F8 00000064 d... 001216FC 00008282 倐.. 00121700 00000000 .... 00121704 00000000 .... 00121708 00000000 .... 0012170C 41414141 AAAA 00121710 00000000 .... 00121714 00000000 .... 00121718 00000000 .... <= esp 0012171C 00000000 .... 00121720 00000000 .... 00121724 00000000 .... 00121728 00000000 .... 0012172C 00000000 .... |
用alt+e
切换到模块视图,右键选择Analysis all modules
,等待所有模块分析完成再看这段栈:
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 |
001216D0 00008282 倐.. 001216D4 00121708 . 001216D8 275A273D ='Z' MSCOMCTL.275A273D 001216DC 00121700 .. 001216E0 05DB1FF0 ?? 001216E4 00008282 倐.. 001216E8 00000000 .... 001216EC 05E086C4 膯? 001216F0 09D60810 ? 001216F4 6A626F43 Cobj 001216F8 00000064 d... 001216FC 00008282 倐.. 00121700 00000000 .... 00121704 00000000 .... 00121708 00000000 .... 0012170C 41414141 AAAA 00121710 00000000 .... 00121714 00000000 .... 00121718 00000000 .... <= esp 0012171C 00000000 .... 00121720 00000000 .... 00121724 00000000 .... 00121728 00000000 .... 0012172C 00000000 .... |
发现275A273D
是一个属于MSCOMCTL
的地址,很可能就是触发崩溃函数的返回地址。用IDA
加载MSCOMCTL.OCX
,位于sub_ 275A26FA
中:
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 |
.text:275A26FA push ebp .text:275A26FB mov ebp, esp .text:275A26FD sub esp, 14h .text:275A2700 push ebx .text:275A2701 mov ebx, [ebp+bstrString] .text:275A2704 push esi .text:275A2705 push edi .text:275A2706 push 0Ch ; dwBytes .text:275A2708 lea eax, [ebp+var_14] .text:275A270B push ebx ; lpMem .text:275A270C push eax ; int .text:275A270D call sub_275A24A0 .text:275A2712 add esp, 0Ch .text:275A2715 test eax, eax .text:275A2717 jl short loc_275A2785 .text:275A2719 cmp [ebp+var_14], 6A626F43h .text:275A2720 jnz loc_275D2A5F .text:275A2726 cmp [ebp+dwBytes], 8 .text:275A272A jb loc_275D2A5F .text:275A2730 push [ebp+dwBytes] ; dwBytes .text:275A2733 lea eax, [ebp+var_8] .text:275A2736 push ebx ; lpMem .text:275A2737 push eax ; int .text:275A2738 call sub_275A24A0 .text:275A273D mov esi, eax |
这个模块是在加载.doc
文件时才动态加载的,这里可以用windbg
对这个模块设置加载断点,然后运行,打开poc.doc
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
0:007> sxe ld:mscomctl.ocx 0:007> g ModLoad: 27580000 27686000 C:\WINDOWS\system32\MSCOMCTL.OCX eax=00000000 ebx=00000000 ecx=09ef0000 edx=7c92e4f4 esi=00000000 edi=00000000 eip=7c92e4f4 esp=00120184 ebp=00120278 iopl=0 nv up ei ng nz ac pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000296 ntdll!KiFastSystemCallRet: 7c92e4f4 c3 ret 0:000> bp 275A2738 *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINDOWS\system32\MSCOMCTL.OCX - 0:000> g (278.298): Unknown exception - code 000006ba (first chance) (278.48c): Unknown exception - code 000006ba (first chance) Breakpoint 0 hit eax=00121700 ebx=09d60810 ecx=7c93003d edx=01140608 esi=05e57bd4 edi=00000000 eip=275a2738 esp=001216dc ebp=00121708 iopl=0 nv up ei pl nz ac po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212 MSCOMCTL!DllGetClassObject+0xb451: 275a2738 e863fdffff call MSCOMCTL!DllGetClassObject+0xb1b9 (275a24a0) |
在加载模块时会断下来,这时就可以在275A2738
处的call
下断点了,设好断点后继续运行就会断在275A2738
处。
在sub_ 275A26FA
返回时返回到了0x41414141
:
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 |
0:000> g (278.298): Unknown exception - code 000006ba (first chance) (278.48c): Unknown exception - code 000006ba (first chance) Breakpoint 0 hit eax=00121700 ebx=09d60810 ecx=7c93003d edx=01140608 esi=05e57bd4 edi=00000000 eip=275a2738 esp=001216dc ebp=00121708 iopl=0 nv up ei pl nz ac po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212 MSCOMCTL!DllGetClassObject+0xb451: 275a2738 e863fdffff call MSCOMCTL!DllGetClassObject+0xb1b9 (275a24a0) 0:000> t eax=00121700 ebx=09d60810 ecx=7c93003d edx=01140608 esi=05e57bd4 edi=00000000 eip=275a24a0 esp=001216d8 ebp=00121708 iopl=0 nv up ei pl nz ac po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212 MSCOMCTL!DllGetClassObject+0xb1b9: 275a24a0 55 push ebp ... ... 0:000> eax=00000000 ebx=09d60810 ecx=7c93003d edx=01140608 esi=05e57bd4 edi=00000000 eip=275a2789 esp=0012170c ebp=00000000 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 MSCOMCTL!DllGetClassObject+0xb4a2: 275a2789 c20800 ret 8 0:000> eax=00000000 ebx=09d60810 ecx=7c93003d edx=01140608 esi=05e57bd4 edi=00000000 eip=41414141 esp=00121718 ebp=00000000 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 41414141 ?? ??? |
看一下MSCOMCTL!DllGetClassObject+0xb1b9
这个函数:
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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
0:000> u 275a24a0 275A2539 MSCOMCTL!DllGetClassObject+0xb1b9: 275a24a0 55 push ebp 275a24a1 8bec mov ebp,esp 275a24a3 51 push ecx 275a24a4 53 push ebx 275a24a5 8b5d0c mov ebx,dword ptr [ebp+0Ch] 275a24a8 56 push esi 275a24a9 33f6 xor esi,esi 275a24ab 8b03 mov eax,dword ptr [ebx] 275a24ad 57 push edi 275a24ae 56 push esi 275a24af 8d4dfc lea ecx,[ebp-4] 275a24b2 6a04 push 4 275a24b4 51 push ecx 275a24b5 53 push ebx 275a24b6 ff500c call dword ptr [eax+0Ch] 275a24b9 3bc6 cmp eax,esi 275a24bb 7c78 jl MSCOMCTL!DllGetClassObject+0xb24e (275a2535) 275a24bd 8b7d10 mov edi,dword ptr [ebp+10h] 275a24c0 397dfc cmp dword ptr [ebp-4],edi 275a24c3 0f8533150300 jne MSCOMCTL!DllGetClassObject+0x3c715 (275d39fc) 275a24c9 57 push edi 275a24ca 56 push esi 275a24cb ff3520e06227 push dword ptr [MSCOMCTL!DllUnregisterServer+0x2dfe8 (2762e020)] 275a24d1 ff1568115827 call dword ptr [MSCOMCTL+0x1168 (27581168)] 275a24d7 3bc6 cmp eax,esi 275a24d9 89450c mov dword ptr [ebp+0Ch],eax 275a24dc 0f8424150300 je MSCOMCTL!DllGetClassObject+0x3c71f (275d3a06) 275a24e2 8b0b mov ecx,dword ptr [ebx] 275a24e4 56 push esi 275a24e5 57 push edi 275a24e6 50 push eax 275a24e7 53 push ebx 275a24e8 ff510c call dword ptr [ecx+0Ch] 275a24eb 8bf0 mov esi,eax 275a24ed 85f6 test esi,esi 275a24ef 7c31 jl MSCOMCTL!DllGetClassObject+0xb23b (275a2522) 275a24f1 8b750c mov esi,dword ptr [ebp+0Ch] 275a24f4 8bcf mov ecx,edi 275a24f6 8b7d08 mov edi,dword ptr [ebp+8] 275a24f9 8bc1 mov eax,ecx 275a24fb c1e902 shr ecx,2 275a24fe f3a5 rep movs dword ptr es:[edi],dword ptr [esi] 275a2500 8bc8 mov ecx,eax 275a2502 8b4510 mov eax,dword ptr [ebp+10h] 275a2505 83e103 and ecx,3 275a2508 6a00 push 0 275a250a 8d5003 lea edx,[eax+3] 275a250d 83e2fc and edx,0FFFFFFFCh 275a2510 2bd0 sub edx,eax 275a2512 f3a4 rep movs byte ptr es:[edi],byte ptr [esi] 275a2514 8b0b mov ecx,dword ptr [ebx] 275a2516 52 push edx 275a2517 68e03f6327 push offset MSCOMCTL!DllUnregisterServer+0x33fa8 (27633fe0) 275a251c 53 push ebx 275a251d ff510c call dword ptr [ecx+0Ch] 275a2520 8bf0 mov esi,eax 275a2522 ff750c push dword ptr [ebp+0Ch] 275a2525 6a00 push 0 275a2527 ff3520e06227 push dword ptr [MSCOMCTL!DllUnregisterServer+0x2dfe8 (2762e020)] 275a252d ff1574115827 call dword ptr [MSCOMCTL+0x1174 (27581174)] 275a2533 8bc6 mov eax,esi 275a2535 5f pop edi 275a2536 5e pop esi 275a2537 5b pop ebx 275a2538 c9 leave 275a2539 c3 ret |
注意这里有两条rep movs
指令,那么很可能就是这里导致了栈溢出覆盖了sub_275A26FA
的返回地址。再次调试,看看这里是怎么复制的。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
0:000> p eax=00008282 ebx=0a910810 ecx=00008282 edx=00000000 esi=05db8008 edi=00121700 eip=275a24fb esp=001216c4 ebp=001216d4 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 MSCOMCTL!DllGetClassObject+0xb214: 275a24fb c1e902 shr ecx,2 0:000> eax=00008282 ebx=0a910810 ecx=000020a0 edx=00000000 esi=05db8008 edi=00121700 eip=275a24fe esp=001216c4 ebp=001216d4 iopl=0 nv up ei pl nz na pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000207 MSCOMCTL!DllGetClassObject+0xb217: 275a24fe f3a5 rep movs dword ptr es:[edi],dword ptr [esi] |
这里可以知道复制大小在ecx
中,复制是以dword
方式复制的,所以ecx
要除以四,这时用t
命令单步,同时注意观察目标栈上的地址00121700
的内存,复制了几次后发现41414141
被填入了0012170c
处,这时栈底为001216d4
,单步到这个函数返回,栈底变为00121708
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
... 0:000> eax=00000000 ebx=0a910810 ecx=7c93003d edx=01140608 esi=05d80464 edi=00000000 eip=275a2539 esp=001216d8 ebp=00121708 iopl=0 nv up ei ng nz ac pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000296 MSCOMCTL!DllGetClassObject+0xb252: 275a2539 c3 ret 0:000> eax=00000000 ebx=0a910810 ecx=7c93003d edx=01140608 esi=05d80464 edi=00000000 eip=275a273d esp=001216dc ebp=00121708 iopl=0 nv up ei ng nz ac pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000296 MSCOMCTL!DllGetClassObject+0xb456: 275a273d 8bf0 mov esi,eax ... 0:000> eax=00000000 ebx=0a910810 ecx=7c93003d edx=01140608 esi=05d80464 edi=00000000 eip=275a2789 esp=0012170c ebp=00000000 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 MSCOMCTL!DllGetClassObject+0xb4a2: 275a2789 c20800 ret 8 0:000> dd esp 0012170c 41414141 00000000 00000000 00000000 0012171c 00000000 00000000 00000000 00000000 |
这里就知道了,覆盖了sub_275A26FA
的返回地址。
回溯一下edi
的来源,有一句mov edi,[ebp+8]
,也就是将函数的最后一个参数赋给edi
,对应调试:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
0:000> eax=00121700 ebx=0a910810 ecx=7c93003d edx=01140608 esi=05d80464 edi=00000000 eip=275a2737 esp=001216e0 ebp=00121708 iopl=0 nv up ei pl nz ac po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212 MSCOMCTL!DllGetClassObject+0xb450: 275a2737 50 push eax 0:000> p eax=00121700 ebx=0a910810 ecx=7c93003d edx=01140608 esi=05d80464 edi=00000000 eip=275a2738 esp=001216dc ebp=00121708 iopl=0 nv up ei pl nz ac po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212 MSCOMCTL!DllGetClassObject+0xb451: 275a2738 e863fdffff call MSCOMCTL!DllGetClassObject+0xb1b9 (275a24a0) |
eax
的值就是将要赋给edi
的值00121700
,回到sub_275A26FA
发现eax
来自于lea eax,[ebp-14h]
,也就是eax=esp-0x14
,而在275A2738
处的call
之前,esp
又加了0xc
,这样栈上只剩下0x8
的空间,而实际复制的大小为000020a0(dword)
,导致了溢出。