总体来说坑不多,但是对于windbg没有watchpoint功能这一点,真的是很坑。
Adobe Acrobat和Reader在True Type Font (TTF)处理的实现上存在整数溢出漏洞,攻击者可利用此漏洞执行任意代码。
受影响软件版本:
Adobe Reader 9.4.[0-5]
Adobe Reader 9.3.[0-4]
Adobe Reader 9.2
Adobe Reader 9.1.[0-3]
更多详情,请参考【bid-52951】
True Type Font字体文件中使用预定义的指令集控制字体hinting,当执行到MINDEX指令时,被操作的数组长度n溢出成超大值,导致数组写越界。
MINDEX指令:对size为n的数组进行循环左移一位。
运行环境:
版本 | |
---|---|
操作系统 | windows 7 sp1 32bit |
调试器 | windbg 6.12 32 bit |
漏洞软件 | AdbeRdr940_zh_CN.exe |
文件查看器 | 010editor |
反编译工具 | IDA |
poc 如下图所示,问题数值n是由多个值经过计算得到的,无法在poc文件中直接看到,这里展示的计算前的输入数据。
需要说明的是漏洞出发的关键数据猜测是fuzz出来的,所以,010editor在解析到SimpleGlyph[10]的数据时报异常,没有显示出来。途中蓝色选中的数据就在这片黑色领域中。
报错信息如下:
windbg不用开page heap,因为不是堆溢出。运行poc,查看报错:
eax=65ee622c ebx=00000000 ecx=65eef000 edx=3fffdc8a esi=65eef004 edi=00004141
eip=65cb79ce esp=0016cd9c ebp=0016ce30 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Adobe\Reader 9.0\Reader\CoolType.dll -
CoolType+0x79ce:
65cb79ce 8919 mov dword ptr [ecx],ebx ds:0023:65eef000=00000000
写入的目标地址是65eef000
查看内存属性
0:000> !address 65eef000
Failed to map Heaps (error 80004005)
Usage: Image
Allocation Base: 65cb0000
Base Address: 65eef000
End Address: 65f0f000
Region Size: 00020000
Type: 01000000 MEM_IMAGE
State: 00001000 MEM_COMMIT
Protect: 00000002 PAGE_READONLY
More info: lmv m CoolType
More info: !lmi CoolType
More info: ln 0x65eef000
目标地址Protect属性是PAGE_READONLY
,表示只读。向只读地址写入数据,估计是写越界了。
回溯函数调用栈
0:000> kb
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
0016ce30 65cbade0 0c6fcbb8 65ee5a28 0c6fce16 CoolType+0x79ce
0016ce60 65cb4e44 0c6fcbb8 65ee5a28 0c6fce16 CoolType+0xade0
0016cea0 65cb587c 0c6fca38 0c6fcbb8 65ee5a28 CoolType+0x4e44
0016cf44 65cb5c36 05eb6aa4 05eb6bfc 05eb6bb4 CoolType+0x587c
0016cfa0 65cb5cc8 05eb6aa4 05eb6bfc 05eb6bb4 CoolType+0x5c36
0016cff0 65cb3a69 05eb6aa4 05eb6bfc 05eb6bb4 CoolType+0x5cc8
0016d058 65cb3b36 0016d15c 0016d08c 00000001 CoolType+0x3a69
0016d1b8 65ccbb43 098df390 00000000 0016d204 CoolType+0x3b36
00000000 00000000 00000000 00000000 00000000 CoolType+0x1bb43
查看当前函数 CoolType+0x79ce
int __cdecl sub_800798B(int a1)
{
unsigned int v1; // edi@2
_DWORD *v2; // eax@3
int v3; // edx@3
unsigned int v4; // ecx@3
int v5; // edi@5
int result; // eax@8
if ( (unsigned int)(dword_82323E0 - 4) < *(_DWORD *)dword_82323EC
|| (v1 = *(_DWORD *)(dword_82323EC + 340), dword_82323E0 - 4 >= v1)
|| (v2 = (_DWORD *)(dword_82323E0 - 4),
v3 = *(_DWORD *)(dword_82323E0 - 4),
v4 = dword_82323E0 - 4 - 4 * *(_DWORD *)(dword_82323E0 - 4),
v4 < *(_DWORD *)dword_82323EC)
|| v4 >= v1 )
{
result = dword_8232438;
dword_8232434 = 4368;
}
else
{
v5 = *(_DWORD *)v4;
if ( v3 > 0 )
{
do
{
--v3;
*(_DWORD *)v4 = *(_DWORD *)(v4 + 4); //在此处崩溃
v4 += 4;
}
while ( v3 );
--v2;
}
*v2 = v5;
dword_82323E0 = (int)(v2 + 1);
result = a1;
}
return result;
}
该函数是MINDEX指令的实现-size为n的数组做循环左移一位,在内存中找数组边界时,n也就是代码中的v3溢出成超大值,导致写越界。
sub_800798B
函数之前已经写了一篇比较详细文章做说明【传送门】。
65cb798b a1e023ee65 mov eax,dword ptr [CoolType!CTCleanup+0xe3ad6 (65ee23e0)] // 函数入口,这里下断点
65cb7990 8b0dec23ee65 mov ecx,dword ptr [CoolType!CTCleanup+0xe3ae2 (65ee23ec)]
65cb7996 53 push ebx
65cb7997 56 push esi
65cb7998 8b31 mov esi,dword ptr [ecx]
65cb799a 8d50fc lea edx,[eax-4]
65cb799d 3bd6 cmp edx,esi
65cb799f 57 push edi
65cb79a0 7245 jb CoolType+0x79e7 (65cb79e7)
65cb79a2 8bb954010000 mov edi,dword ptr [ecx+154h]
65cb79a8 3bd7 cmp edx,edi
65cb79aa 733b jae CoolType+0x79e7 (65cb79e7)
65cb79ac 83c0fc add eax,0FFFFFFFCh
65cb79af 8b10 mov edx,dword ptr [eax]
65cb79b1 8bda mov ebx,edx
65cb79b3 c1e302 shl ebx,2
65cb79b6 8bc8 mov ecx,eax
65cb79b8 2bcb sub ecx,ebx
65cb79ba 3bce cmp ecx,esi
65cb79bc 7229 jb CoolType+0x79e7 (65cb79e7)
65cb79be 3bcf cmp ecx,edi
65cb79c0 7325 jae CoolType+0x79e7 (65cb79e7)
65cb79c2 85d2 test edx,edx
65cb79c4 8b39 mov edi,dword ptr [ecx]
65cb79c6 7e0f jle CoolType+0x79d7 (65cb79d7)
65cb79c8 4a dec edx //数组大小n自减,也就是反汇编中的v3自减操作
65cb79c9 8d7104 lea esi,[ecx+4]
65cb79cc 8b1e mov ebx,dword ptr [esi]
65cb79ce 8919 mov dword ptr [ecx],ebx ds:0023:65eef000=00000000
65cb79d0 8bce mov ecx,esi
65cb79d2 75f4 jne CoolType+0x79c8 (65cb79c8)
65cb79d4 83e804 sub eax,4
65cb79d7 8938 mov dword ptr [eax],edi
65cb79d9 83c004 add eax,4
65cb79dc a3e023ee65 mov dword ptr [CoolType!CTCleanup+0xe3ad6 (65ee23e0)],eax
65cb79e1 8b442410 mov eax,dword ptr [esp+10h]
65cb79e5 eb0f jmp CoolType+0x79f6 (65cb79f6)
在函数入口出下断点
0:000>bp 65cb798b
可以看到这个值n在进入sub_800798B
函数不久v3改变成0x40000001,并开始do-while循环,有人见过0x40000001这么大的数组吗?显然这是一个bug。
跟进v3变量,在存储地址65ee622c下写断点
0:000> ba w4 65ee622c
追踪到v3的值的计算过程
0x3FFF0003 + 0x7FFF + 0x7FFF = 0x40000001
根据这段输入定位到poc.pdf中的关键数据位置
41 41 41 41 41 41 00 03 00 00 00 40 42 41 02 7F FF 7F FF 63 60 41 04 FF E8 00 00 00 00 00 00 43 B0 01 61 42 43 78 41 02 7F FF 7F FF 60 60
http://pwdme.cc/2017/11/05/cve-2012-0774/
https://developer.apple.com/fonts/TrueType-Reference-Manual/RM07/appendixA.html
https://docs.microsoft.com/en-us/typography/opentype/spec/tt_instructions
https://android.googlesource.com/platform/external/freetype/+/f720f0dbcf012d6c984dbbefa0875ef9840458c6/src/truetype/ttinterp.c