来源:http://bbs.ichunqiu.com/thread-8849-1-1.html?from=ch
首先我需要纠正一下@nancheal同学,我的ID是k0shl,并非k0s1
,发这贴的原因是上午看到了nancheal发的一次失败的分析之后,发现他原帖中存在的一些细节上的问题,和对于这个漏洞的疑惑,我也受到了泉哥的《漏洞战争》签名赠书,还没来得及看,所以对泉哥的分析并不是很了解,网上说搜索了一下也只搜到泉哥关于这个漏洞的补丁对比的内容。昨天和nancheal同学在微信上有过短暂的交流,也不是很深入,上午看完帖子后,我自己进行了一下调试,结合nancheal的分析来完成对这个漏洞的分析。
另外蛋总让我强行参加原创奖励活动,也借此机会了却一桩心事吧。。
首先我的个人建议是nancheal同学以及刚刚入门和准备入门的同学都先不要调试《漏洞战争》这本书上的漏洞,首先CVE级别漏洞本身都很复杂,哪怕08年以后的漏洞都涉及到一些较为高级的调试技巧,书上的实例可能调试步骤比较详细,但是调试过程中难免会碰到一些细节会和书上不同,比如malloc申请堆空间的时候,申请下来堆空间每次地址都不一样,因此建议刚入门或者想入门的同学,先从基础的做起,《0day安全:软件漏洞分析技术》这本书就是为《漏洞战争》准备的基础书籍,极力推荐。
另外就算在对《漏洞战争》中的实例调试时,还是需要从原理入手,灵活运用所学,不一定是要完全按照书上的调试内容,更多的应该把书作为实践的佐证。
其次我要纠正一下nancheal在帖子[原创]漏洞战争之cve-2010-2883 一次失败的分析中存在的误区。
1、dll的读写权限,这个我在昨天和nancheal在微信上讨论时已经指出,实际上,dll不具备w(写)权限也很正常,有R权限就已经很不错了,其中熟悉PE结构的同学知道.text段是代码段,拥有执行权限,.data段用于存放变量,实际上,这个漏洞原理和dll中是否具备写权限关系不大,可能会对将来exp执行有影响,但是这里就分析来说影响并不大。
2、泉哥为什么要用内存访问断点,这里要普及两个概念,一个是内存写入断点和内存访问断点,这两个断点在漏洞分析调试中经常会被用到,在申请了一片内存空间后,可能会向这片内存空间中存入一些数值,这些数值可能是我们的payload,这时候我们可以通过对这片内存的起始地址(某指针)下内存访问断点,这样,当后续指令流在调用到这个内存起始地址(也就是调用到某指针)的时候,就会命中断点,这样就能快速定位到发生调用的位置。
而内存写入断点则是,比如我们malloc开辟了一片内存空间,在程序执行到某个位置的时候,会向这片内存区域拷贝我们的payload,这时,我们可以在malloc之后对这片内存区域的起始地址下内存写入断点,这之后,如果程序执行到某处,会对这个地址写入payload时候就会发生中断,命中断点。
用C的方法来解释这个过程就是
[AppleScript]纯文本查看复制代码
1
2
3/*0*/char*ichunqiu=(char*)malloc(250);
/*1*/ichunqiu="I love AK";
/*2*/char*k0shl=ichunqiu;
当执行0语句的时候,对ichunqiu这个指针地址下内存访问断点和内存写入断点。当执行到1语句的时候,会因为内存写入断点而中断,当执行到2语句的时候,会因为内存访问断点而中断。
3、关于nancheal提出的其他dll,不知道他最后命中的是不是BIB.dll,这个也是Adobe Reader下的一个dll,实际上是在CoolType.dll下发生溢出,而在BIB.dll中造成的影响。
好了,基本的原理就是这样,下面进入我们的分析。
这里调试器我选用:Windbg
测试环境:windows xp sp3
测试软件:Adobe Reader 8.0
PoC选用泉哥提供的PoC里的msf样本。
根据漏洞描述,这个漏洞是在处理Sing字体解析的时候会发生溢出,在实际分析之后,实际上这里是由于溢出引发的某指针被覆盖,从而从CoolType.dll中调用BIB.dll某函数时,某函数重要指针被覆盖,从而导致了程序进入SEH异常处理模块,之后通过溢出覆盖SEH指针达到执行任意代码的目的。关于补丁对比,百度指直接搜索CVE-2010-2883就能看到kanxue泉哥的文章,其他也有转载,不再多提。
根据nancheal同学分析中的描述,我们可以定位到函数
[C]纯文本查看复制代码
1
char__cdecl sub_803BC7B(inta1,inta2,inta3,inta4)
这个函数中会对SING字体格式进行解析,具体的IDA伪代码我不全发了,比如
[C]纯文本查看复制代码
1
sub_8020619(a1,"SING");
会对SING进行判断等等,这里不多说了,关注到函数中有一处调用loc块,这个在nancheal的分析中也能看到。
[Asm]纯文本查看复制代码
1
2
3
4
5
6
7.text:0803BD21 loc_803BD21:; CODE XREF: sub_803BC7B+9C�j
.text:0803BD21addeax, 10h
.text:0803BD24pusheax; char *
.text:0803BD25leaeax, [ebp+108h+var_108]
.text:0803BD28pusheax; char *
.text:0803BD29mov[ebp+108h+var_108], 0
.text:0803BD2Dcallstrcat
通过Windbg,在这个块0803BD21地址下断点进行跟踪。
[Asm]纯文本查看复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
300:000> p
eax=086de160ebx=0012e584ecx=00000000edx=00000200esi=00000000edi=0012e690
eip=0803bd24esp=0012e3ecebp=0012e454 iopl=0 nv up ei pl nz na pe nc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000206
CoolType+0x3bd24:
0803bd24 50pusheax
0:000> p
eax=086de160ebx=0012e584ecx=00000000edx=00000200esi=00000000edi=0012e690
eip=0803bd25esp=0012e3e8ebp=0012e454 iopl=0 nv up ei pl nz na pe nc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000206
CoolType+0x3bd25:
0803bd25 8d4500leaeax,[ebp]
0:000> p
eax=0012e454ebx=0012e584ecx=00000000edx=00000200esi=00000000edi=0012e690
eip=0803bd28esp=0012e3e8ebp=0012e454 iopl=0 nv up ei pl nz na pe nc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000206
CoolType+0x3bd28:
0803bd28 50pusheax
0:000> p
eax=0012e454ebx=0012e584ecx=00000000edx=00000200esi=00000000edi=0012e690
eip=0803bd29esp=0012e3e4ebp=0012e454 iopl=0 nv up ei pl nz na pe nc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000206
CoolType+0x3bd29:
0803bd29 c6450000movbyteptr[ebp],0ss:0023:0012e454=54
0:000> p
eax=0012e454ebx=0012e584ecx=00000000edx=00000200esi=00000000edi=0012e690
eip=0803bd2desp=0012e3e4ebp=0012e454 iopl=0 nv up ei pl nz na pe nc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000206
CoolType+0x3bd2d:
0803bd2d e86c5b0100callCoolType!CTInit+0xd4aa (0805189e)
可以看到,在0803bd2d位置调用了strcat函数,实际上实现的是对第二次push eax的地址进行字符串拼接,拼接的内容是第一次push eax的内容,可以来看一下这两个内容。这个内容不多介绍了,在nancheal的文章里也有,其实第一次push eax的内容就是畸形字符串的内容,而第二次就是准备拷贝进的内容。
我们关注到eax的地址是0012e454,也就是说,这个0012e454在执行完毕后,会拼接上畸形字符串,我们直接步过call调用。并再次查看地址。
[Asm]纯文本查看复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
300:000> t
eax=0012e454ebx=0012e584ecx=0012e584edx=0000006cesi=00000000edi=0012e690
eip=080011ccesp=0012e3e4ebp=0012e454 iopl=0 nv up ei pl zr na pe nc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000246
CoolType+0x11cc:
080011cc 56pushesi
0:000> p
eax=0012e454ebx=0012e584ecx=0012e584edx=0000006cesi=00000000edi=0012e690
eip=080011cdesp=0012e3e0ebp=0012e454 iopl=0 nv up ei pl zr na pe nc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000246
CoolType+0x11cd:
080011cd 57pushedi
0:000>ddesp
0012e3e0 00000000 0803bd3f 0012e454 4af0349b
0012e3f0 00000004 0012e64c 00000000 4af034d3
0012e400 0012e66c 0012e64c 00000000 0012e3fc
0012e410 0012e4b0 081608b9 00000000 08085528
0012e420 080497d5 0012e678 000026ec 0012e690
0012e430 086cef58 00001ddf 00000000 00000000
0012e440 00b38120 0012e3ec 0012e684 0816ebd7
0012e450 00000002 e6516698 e78b53ab 4a82a714
0:000>dd0012e454
0012e454 e6516698 e78b53ab 4a82a714 0c0c0c0c
0012e464 37120a16 36e78c7a 03a9dc3f cbcfe1a1
0012e474 c591787b 5ff78c8b 902fc83d 1e35d340
0012e484 5f450b24 0a616d64 6c9e5b1d eb6af62e
0012e494 cc3efb89 2b1a8365 1b6890d3 daed63fe
0012e4a4 2841ca39 b36b9a86 d5c751cc 0f2c2ad9
0012e4b4 b451ef61 5e4c3415 26f3b9cd 487189ce
0012e4c4 4f37251f 905d28ad 57ba53b8 7d86e71c
可以看到,已经覆盖上畸形字符串了,实际上,去看一下泉哥的补丁对比可以发现,adobe修补这个漏洞,也是在strcat之前进行了一次对字体内容的判断,控制长度防止了溢出。
这里拷贝上畸形字符串后单步跟踪,发现这里strcat后会调用一处函数。
[Asm]纯文本查看复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
320:000> p
eax=0012e454ebx=0012e584ecx=0012e584edx=0000006cesi=00000000edi=0012e690
eip=080011d2esp=0012e3d8ebp=0012e454 iopl=0 nv up ei pl zr na pe nc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000246
CoolType+0x11d2:
080011d2 8bf1movesi,ecx
0:000> p
eax=0012e454ebx=0012e584ecx=0012e584edx=0000006cesi=0012e584edi=0012e690
eip=080011d4esp=0012e3d8ebp=0012e454 iopl=0 nv up ei pl zr na pe nc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000246
CoolType+0x11d4:
***ERROR: Symbol file couldnotbe found. Defaulted toexportsymbolsforC:\Program Files\Adobe\Reader 8.0
\Reader\BIB.dll -
080011d4 ff155ce52008calldwordptr[CoolType!CTCleanup+0xcdcc0 (0820e55c)]ds:0023:0820e55c=07005143
0:000>ddesp
0012e3d8 0012e454 0012e690 00000000 0803bd3f
0012e3e8 0012e454 4af0349b 00000004 0012e64c
0012e3f8 00000000 4af034d3 0012e66c 0012e64c
0012e408 00000000 0012e3fc 0012e4b0 081608b9
0012e418 00000000 08085528 080497d5 0012e678
0012e428 000026ec 0012e690 086cef58 00001ddf
0012e438 00000000 00000000 00b38120 0012e3ec
0012e448 0012e684 0816ebd7 00000002 e6516698
0:000>dd0012e454
0012e454 e6516698 e78b53ab 4a82a714 0c0c0c0c
0012e464 37120a16 36e78c7a 03a9dc3f cbcfe1a1
0012e474 c591787b 5ff78c8b 902fc83d 1e35d340
0012e484 5f450b24 0a616d64 6c9e5b1d eb6af62e
0012e494 cc3efb89 2b1a8365 1b6890d3 daed63fe
0012e4a4 2841ca39 b36b9a86 d5c751cc 0f2c2ad9
0012e4b4 b451ef61 5e4c3415 26f3b9cd 487189ce
0012e4c4 4f37251f 905d28ad 57ba53b8 7d86e71c
可以看到,调用这处函数的时候,参数就是我们的畸形字符串,关于函数调用的参数,通过esp就能看到,这个是基本,网上都能够搜到,我不再解释了,在call这个函数之前,我们要重点关注一个寄存器ecx,可以看到ecx的值是0012e584,ecx存放的起始就是this指针,那么这个值和我们刚才strcat的值0012e454是不是离得很近,而由于没有进行长度检查,导致this指针原本的值,会被0012e454的值覆盖!这个地方很关键,也是漏洞最根本的原因!来看一下这个值
[Asm]纯文本查看复制代码
1
2
3
4
5
6
7
8
90:000>ddebx
0012e584 4a8a08c6 5cc9c74d a53c982e 151b9907
0012e594 cdb55d52 1a101055 b03f839c 343c1b59
0012e5a4 553cc3ea a31efcba 695dc2d0 e680dffb
0012e5b4 bf0194b8 0960a1af 201ff4e3 d5253c21
0012e5c4 11c0be21 85c00d4c 043ecff4 05bb3e03
0012e5d4 d22783c6 77ba1c97 3d582536 9210a51f
0012e5e4 e85a280e 17662139 e2ad85c3 c9f86c5e
0012e5f4 40c7f4b1 5fdd9565 afe3c638 abe6f453
正是我们畸形字符串的一部分,由于溢出的发生,导致this指针被覆盖了,那么这会造成什么后果呢。,先通过IDA可以看一下这一块的伪代码。
[C]纯文本查看复制代码
1
2
3
4
5
6
7if( v18 )
{
if( !(*(_DWORD *)v18 & 0xFFFF) || (*(_DWORD *)v18 & 0xFFFF) == 256 )
{
v24 = 0;
strcat(&v24, (constchar*)(v18 + 16));
sub_80011CC((int*)a2, (int)&v24);
这里执行完strcat后,会调用sub_80011cc,其中会调用到两个参数a2和v24,而a2就是我们的this指针,而v24则是strcat后的畸形字符串(已经不重要了,关键的this指针已经被覆盖),关于sub_80011cc函数通过IDA可以看到下面的伪代码。
[C]纯文本查看复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13int*__thiscall sub_80011CC(int*this,inta2)
{
int*v2;// esi@1
intv3;// edi@1
v2 =this;
v3 = dword_820E55C(a2);
if( *v2 )
dword_820E560(*v2);
*v2 = v3;
v2[1] = dword_820E564(v3);
returnv2;
}
两者对证,可以发现this指针就是之前提到的a2,a2已经被覆盖了,随后this指针会交给v2变量,可以看一下这个过程。
[Asm]纯文本查看复制代码
01
02
03
04
05
06
07
08
09
10
11
120:000> p
eax=0012e454ebx=0012e584ecx=0012e584edx=0000006cesi=00000000edi=0012e690
eip=080011ceesp=0012e3dcebp=0012e454 iopl=0 nv up ei pl zr na pe nc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000246
CoolType+0x11ce:
080011ce ff74240cpushdwordptr[esp+0Ch]ss:0023:0012e3e8=0012e454
0:000> p
eax=0012e454ebx=0012e584ecx=0012e584edx=0000006cesi=00000000edi=0012e690
eip=080011d2esp=0012e3d8ebp=0012e454 iopl=0 nv up ei pl zr na pe nc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000246
CoolType+0x11d2:
080011d2 8bf1movesi,ecx
这里执行了一处拷贝操作,拷贝的就是ecx地址,交给esi指针寄存器,随后观察esi的值。
[Asm]纯文本查看复制代码
1
2
3
4
5
6
7
8
90:000>ddesi
0012e584 4a8a08c6 5cc9c74d a53c982e 151b9907
0012e594 cdb55d52 1a101055 b03f839c 343c1b59
0012e5a4 553cc3ea a31efcba 695dc2d0 e680dffb
0012e5b4 bf0194b8 0960a1af 201ff4e3 d5253c21
0012e5c4 11c0be21 85c00d4c 043ecff4 05bb3e03
0012e5d4 d22783c6 77ba1c97 3d582536 9210a51f
0012e5e4 e85a280e 17662139 e2ad85c3 c9f86c5e
0012e5f4 40c7f4b1 5fdd9565 afe3c638 abe6f453
已经是畸形字符串了,这点很关键,随后esi地址中存放的值(本来应该是一处指针)会交给eax
[Asm]纯文本查看复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
200:000> p
eax=086ede74ebx=0012e584ecx=07005175edx=07016aa0esi=0012e584edi=0012e690
eip=080011daesp=0012e3d8ebp=0012e454 iopl=0 nv up ei pl nz na po nc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000202
CoolType+0x11da:
080011da 8bf8movedi,eax
0:000> p
eax=086ede74ebx=0012e584ecx=07005175edx=07016aa0esi=0012e584edi=086ede74
eip=080011dcesp=0012e3d8ebp=0012e454 iopl=0 nv up ei pl nz na po nc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000202
CoolType+0x11dc:
080011dc 8b06moveax,dwordptr[esi]ds:0023:0012e584=4a8a08c6
0:000> p
eax=4a8a08c6ebx=0012e584ecx=07005175edx=07016aa0esi=0012e584edi=086ede74
eip=080011deesp=0012e3d8ebp=0012e454 iopl=0 nv up ei pl nz na po nc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000202
CoolType+0x11de:
080011de 85c0testeax,eax
0:000> reax
eax=4a8a08c6
可以看到,eax现在已经是一个畸形的地址了,之后会有一个函数调用eax,在上面伪代码中的内容就是
[C]纯文本查看复制代码
1
2if( *v2 )
dword_820E560(*v2);
这个dword_820E560是BIB.dll中的一个函数
[Asm]纯文本查看复制代码
0:000> p
eax=4a8a08c6ebx=0012e584ecx=0012e454edx=07016aa0esi=0012e584edi=086ede74
eip=080011e3esp=0012e3dcebp=0012e454 iopl=0 nv up ei pl nz na pe nc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000206
CoolType+0x11e3:
080011e3 50pusheax
0:000> p
eax=4a8a08c6ebx=0012e584ecx=0012e454edx=07016aa0esi=0012e584edi=086ede74
eip=080011e4esp=0012e3d8ebp=0012e454 iopl=0 nv up ei pl nz na pe nc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000206
CoolType+0x11e4:
080011e4 ff1560e52008calldwordptr[CoolType!CTCleanup+0xcdcc4 (0820e560)]
这个地方会把eax作为参数入栈,之后再BIB.dll函数中被调用
[Asm]纯文本查看复制代码
0:000> p
eax=4a8a08c6ebx=0012e584ecx=0012e454edx=07016aa0esi=0012e584edi=086ede74
eip=080011e4esp=0012e3d8ebp=0012e454 iopl=0 nv up ei pl nz na pe nc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000206
CoolType+0x11e4:
080011e4 ff1560e52008calldwordptr[CoolType!CTCleanup+0xcdcc4 (0820e560)]ds:0023:0820e560=0700518d
0:000> t
eax=4a8a08c6ebx=0012e584ecx=0012e454edx=07016aa0esi=0012e584edi=086ede74
eip=0700518desp=0012e3d4ebp=0012e454 iopl=0 nv up ei pl nz na pe nc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000206
BIB!BIBInitialize4+0x1820:
0700518d 8b4c2404movecx,dwordptr[esp+4]ss:0023:0012e3d8=4a8a08c6
0:000> p
eax=4a8a08c6ebx=0012e584ecx=4a8a08c6edx=07016aa0esi=0012e584edi=086ede74
eip=07005191esp=0012e3d4ebp=0012e454 iopl=0 nv up ei pl nz na pe nc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000206
BIB!BIBInitialize4+0x1824:
07005191 e91bc2ffffjmpBIB+0x13b1 (070013b1)
0:000> p
eax=4a8a08c6ebx=0012e584ecx=4a8a08c6edx=07016aa0esi=0012e584edi=086ede74
eip=070013b1esp=0012e3d4ebp=0012e454 iopl=0 nv up ei pl nz na pe nc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000206
BIB+0x13b1:
070013b1 ff491cdecdwordptr[ecx+1Ch]ds:0023:4a8a08e2=????????
最后可以看到,在函数中会引用到这个指针中的值,而此时指针已经被覆盖,导致程序出现异常,到达这步继续只执行,会进入SEH异常处理模块。
[Asm]纯文本查看复制代码
0:000> p
(b9c.e04): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
Thisexception may be expectedandhandled.
eax=4a8a08c6ebx=0012e584ecx=4a8a08c6edx=07016aa0esi=0012e584edi=086ede74
eip=070013b1esp=0012e3d4ebp=0012e454 iopl=0 nv up ei pl nz na pe nc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00010206
BIB+0x13b1:
070013b1 ff491cdecdwordptr[ecx+1Ch]ds:0023:4a8a08e2=????????
0:000> p
eax=4a8a08c6ebx=0012e584ecx=0012e108edx=07016aa0esi=0012e584edi=086ede74
eip=7c92e460esp=0012e0e4ebp=0012e454 iopl=0 nv up ei pl nz na pe nc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000206
ntdll!KiUserExceptionDispatcher+0x4:
7c92e460 8b1c24movebx,dwordptr[esp]ss:0023:0012e0e4=0012e0ec
可以看到,已经调用了KiUserExceptionDispatcher,典型的try catch结构造成的SEH异常处理,之后再通过这种方法覆盖SEH指针,就可以完成利用了。