首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>漏洞检测>文章内容
Adobe Reader 'CoolType.dll' TTF字体溢出漏洞分析
来源:http://riusksk.blogbus.com 作者:riusksk 发布时间:2011-05-17  
作者:Nicolas Joly
译者:riusksk(泉哥:http://riusksk.blogbus.com)
 
         本文旨在与大家分享一些关于最近Adobe Acrobat/Reader 0-Day exploit(CVE-2010-2883)的技术细节。在VUPEN组织中,我们分析了大量的漏洞和0day,并且针对各类程序和操作系统编写出相当完善的exploit代码。近几月来,我们编写了许多关于Adobe Reader漏洞的利用代码,并且均可绕过DEP保护。
         那为何本0day exploit会如此有趣呢,以致我们还需著文一篇呢?因为它使用了一些令人难忘的奇淫异技,以及一些非常手段以此绕过DEP和ASLR保护,这在我们平时是很少见的。也许部分人已经知晓,在本漏洞中,经过恶意构造的PDF文件可利用”CoolType.dll”中的非安全函数”strcat()”导致溢出漏洞的发生。当PDF文件以特制表段来嵌入字体时,即可以此触发漏洞。
 
.text:0803DCF9 push ebp
.text:0803DCFA sub esp, 104h
.text:0803DD00 lea ebp, [esp-4]
.text:0803DD04 mov eax, dword_8230FB8
.text:0803DD09 xor eax, ebp
.text:0803DD0B mov [ebp+108h+var_4], eax
.text:0803DD11 push 4Ch
.text:0803DD13 mov eax, offset loc_8184A54
.text:0803DD18 call __EH_prolog3_catch                       // set up an SE handler
.text:0803DD1D mov eax, [ebp+108h+arg_C]
.text:0803DD23 mov edi, [ebp+108h+arg_0]
.text:0803DD29 mov ebx, [ebp+108h+arg_4]
.text:0803DD2F mov [ebp+108h+var_130], edi
.text:0803DD32 mov [ebp+108h+var_138], eax
 
当字体文件中的SING表段被找到后,程序执行以下指令:
 
.text:0803DD74 push offset aSing ; "SING"
.text:0803DD79 push edi ; int
.text:0803DD7A lea ecx, [ebp+108h+var_12C]
.text:0803DD7D call sub_8021B06
...
.text:0803DD9F loc_803DD9F:
.text:0803DD9F add eax, 10h
.text:0803DDA2 push eax                                          // long string following the SING table
.text:0803DDA3 lea eax, [ebp+108h+Dest]
.text:0803DDA6 push eax                                          // ~256 bytes stack buffer
.text:0803DDA7 mov [ebp+108h+Dest], 0
.text:0803DDAB call strcat                                        // insecure!
 
为了利用此漏洞,通常黑客都是通过覆写返回地址或者SE handler,但这里它可能就行不通了。因为它存在一个stack cookie,从而阻止返回地址被利用,而当进入一个设置了异常处理例程的函数后,其栈情况如下:
 
|      SE     |
|  NEXT SE
 |
|     DEST  | <-- vulnerable buffer
|       ...    
 |
|  COOKIE |
|      EBP   
 |
| RET ADD |
 
如上所示,如果你覆写了返回地址,那么cookie也会被改写,进而阻止恶意代码的运行。而如果你继续覆写下去直到触发异常,那么你就可以步过cookie,然后将控制权交由SE handler处理。显然,这种解决方法并没有什么特别之处。还有另一种方法,就是覆盖函数中的参数或者变量。这里攻击者也正好是使用这种方法,当他覆盖了栈空间后,在BIB.dll中出现首次异常,因为下一个调用函数使用了这一个覆盖的参数:
 
.text:0803DDB0 pop ecx
.text:0803DDB1 pop ecx
.text:0803DDB2 lea eax, [ebp+108h+Dest]
.text:0803DDB5 push eax
.text:0803DDB6 mov ecx, ebx               // ebx actually points to arg_4, which is overwritten
.text:0803DDB8 call sub_8001243
 
然后:
 
.text:070013F7 lea eax, [ecx+1Ch]         // ecx = [arg_4]
.text:070013FA mov [ebp+var_8], eax
.text:070013FD mov eax, [ebp+var_8]
.text:07001400 lock dec dword ptr [eax] // first crash here
 
若指向了一个无效地址,那么首次异常将会在0x07001400地址触发,进而执行SE handler,最终导致Adobe Acrobat/Reader崩溃。因此必须设置一个有效指针,至少得允许程序可以在内存中任意递减一个dword字节,这也着实有效(例如CVE-2008-4812)。但即便如此,也很难编写出一个可以绕过DEP和ASLR的exploit。不过sub_8016BDE给我们带来了希望,它将两个指针压入栈中作为参数:
 
.text:0803DEA9 loc_803DEA9:
.text:0803DEA9
.text:0803DEA9 lea eax, [ebp+108h+var_124]
.text:0803DEAC push eax
.text:0803DEAD push ebx
.text:0803DEAE push edi                     // ebx and edi point to arg_4 and arg_0
.text:0803DEAF call sub_8016BDE
 
上面这段代码实际上是以arg_0为参数来调用sub_8016BDE,而sub_8016BDE将返回0或者一个指针。如果返回0,那么程序将会跳到地址0x080172CE,然后退出函数。但如果是返回一个指针,那么sub_801BB21(以arg_0作为其中的一个参数)将被调用。
 
.text:08016C2B push edi
.text:08016C2C mov [ebp+664h+var_668], ebx
.text:08016C2F mov [ebp+664h+var_694], ebx
.text:08016C32 mov [ebp+664h+var_678], ebx
.text:08016C35 call sub_801BB1C       // return 0 or a pointer
.text:08016C3A cmp eax, ebx
.text:08016C3C pop ecx
.text:08016C3D mov [ebp+664h+var_67C], eax
.text:08016C40 jz loc_80172CE
.text:08016C46 push 1
.text:08016C48 push ebx
.text:08016C49 push ebx
.text:08016C4A lea eax, [ebp+664h+var_678]
.text:08016C4D push eax
.text:08016C4E lea eax, [ebp+664h+var_694]
.text:08016C51 push eax
.text:08016C52 push edi
.text:08016C53 push [ebp+664h+var_67C]
.text:08016C56 call sub_801BB21        // this call must be reached
 
函数sub_801BB1C执行后:
 
.text:0801BA57 mov eax, dword_823A728
.text:0801BA5C test eax, eax               // the attacker does not control this pointer
.text:0801BA5E jz short locret_801BA73
.text:0801BA60 mov ecx, [esp+arg_0] // however ecx may point to a controlled dword
.text:0801BA64 mov ecx, [ecx+4]
.text:0801BA67
.text:0801BA67 loc_801BA67:
.text:0801BA67 cmp ecx, [eax+4]
.text:0801BA6A jz short locret_801BA73
.text:0801BA6C mov eax, [eax+8]
.text:0801BA6F test eax, eax
.text:0801BA71 jnz short loc_801BA67
.text:0801BA73
.text:0801BA73 locret_801BA73:
.text:0801BA73
.text:0801BA73 retn
 
这里ECX必须等于[eax+4],以便使函数能够返回除NULL以外的值,那么eax+4 必须指向哪个值呢?
 
0x0000006c
0x0000006b
0x00000070
0x0000006f
0x0000006d
 
由于strcat要被利用,因此null字节是不能使用的!此处令arg_0 + 4指向0x0000006D,这意味着此值是不可随意更改的,以便限制拷入栈中的字节数。这也正是exploit作者没有覆盖整个栈空间,而只覆盖部分空间的原因所在。最后进入sub_801BB21和sub_808B116:
 
.text:0808B2E3 mov eax, [edi+3Ch] // edi = arg_0, but edi + 3Ch points to a stack pointer,
                                                     // itself pointing to a controlled value

.text:0808B2E6 cmp eax, ebx
.text:0808B2E8 mov [esi+2F4h], eax
.text:0808B2EE mov [esi+2F8h], ebx
.text:0808B2F4 mov [ebp+var_4], ebx
.text:0808B2F7 jnz short loc_808B300
.text:0808B2F9
.text:0808B2F9 loc_808B2F9:
.text:0808B2F9 xor al, al
.text:0808B2FB jmp loc_808B594
.text:0808B300
.text:0808B300 loc_808B300:
.text:0808B300 lea ecx, [ebp+var_4]
.text:0808B303 push ecx
.text:0808B304 push ebx
.text:0808B305 push 3
.text:0808B307 push eax
.text:0808B308 call dword ptr [eax] // EIP is redirected here
 
故事到此就可以结束了,但关于ROP技术还是比较少见的。取icucnv36.dll上的地址并不能实现各版本的通用性(至少在9.2.0版本以上),并且不能绕过ASLR。不过有位exploit作者对同一恶意pdf文件进行了改进,他在上面提及的dll文件上(阅读器版本>= 9.20)使用了ROP技术,借此达到攻击目的。这一DLL确实有趣,他并不是使用了函数VirtualAlloc,VirtualProctect,HeapCreate,WriteMemory,甚至连LoadLibrary也没有,这个利用起来有点复杂。他是通过查找并使用了以下函数:
 
4A84903C CreateFileA                // create the file iso88591
4A849038 CreateFileMappingA    // attrib RWE
4A849030 MapViewOfFile            // load this file in memory with RWE flags
4A849170 memcpy                    // copy the payload
 
攻击者是想利用ROP模块进行堆喷射,而其后用shellcode填充。他先在磁盘上创建一个文件(iso88591),然后以RWE属性将其加载到内存中,接着将payload复制到内存,最后执行shellcode。这一exploit先将ESP指向欲喷射的地址:
 
.text:4A80CB38 add ebp, 794h
.text:4A80CB3E leave
.text:4A80CB3F retn
 
返回后来到:
 
.text:4A82A714 pop esp             // esp = 0x08852030
.text:4A82A715 retn
 
0x08852030实际指向一块由同一ROP地址所覆盖的空间,以实现栈喷射:
 
.text:4A801064 retn
 
接着返回到ROP地址,然后将所创建的文件映射到一块可执行的内存页,该地址pop入eax中,然后以下列指令实现调用:
 
.text:4A80B692 jmp dword ptr [eax]
 
现在你可以注意到动态参数已被写入栈中:
 
.text:4A80A8A6 and dword ptr [2*ebx + esp], edi 
.text:4A80A8A9 jnz short loc_4A80A8AE
...
.text:4A80A8AE loc_4A80A8AE:
.text:4A80A8AE cmp al, 2Fh
.text:4A80A8B0 jz short loc_4A80A8AB
.text:4A80A8B2 cmp al, 41h
.text:4A80A8B4 jl short loc_4A80A8BA
...
.text:4A80A8C8 loc_4A80A8C8:
.text:4A80A8C8
.text:4A80A8C8 xor al, al
.text:4A80A8CA retn
 
最后它调用memcpy,然后跳到payload执行任意代码,即使开启了DEP和ASLR,亦均可无视。
         至于此漏洞是通过fuzzing还是静态分析挖掘到,这就不得而知了。但很显然,攻击者对此exploit的巧妙设计,足以表明作者对Acrobat,LiveCycle,Javascript和ROP技术熟知的深厚功底,并对调试器的运用也是相当娴熟。
         事实上,这是一个典型的案例,对于同一DLL文件,同一个exploit文件,攻击者依然能够在在不同版本的程序、操作系统(windows XP,Vista,7)上执行成功,即使开启了各类安全机制,依然能够凑效。
注意,存在同类安全问题的DLL文件也存在于微软的主产品中……

 
[推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论:
  热点文章
·MS07-014调试手记
·udp_sendmsg空指针漏洞分析
·一段对perl 木马的分析
·CVE-2010-4258漏洞分析
·小心我“DIR”溢出你!
·袁哥写的漏洞研究方法总结
·利用异常处理执行shellcode实例
·注入点检测新方法
·PHPBB<+2.0.10 漏洞说明
·水晶论坛(WDB)安全性分析
·Apache mod_ssl buffer over分析
·RPC漏洞的通用分析方法
  相关文章
·Win32k.sys键盘布局文件提权漏洞
·Exim "string_vforat()" 溢出漏
·注入点检测新方法
·CVE-2010-4258漏洞分析
·Hack.lu之mealtime中的反调试技
·MS07-014调试手记
·对一款国家级内容过滤系统Dos安
·RPC漏洞的通用分析方法
·udp_sendmsg空指针漏洞分析
·mb_ereg(i)_replace()代码注射漏
·preg_match(_all)的变量初始化问
·intval()使用不当导致安全漏洞的
  推荐广告
CopyRight © 2002-2018 VFocuS.Net All Rights Reserved