【漏洞分析】Adobe Acrobat和Reader整數溢位漏洞(CVE-2012-0774)
0x00 前言
總體來說坑不多,但是對於windbg沒有watchpoint功能這一點,真的是很坑。
0x01 簡介
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】
0x02 漏洞原理
True Type Font字型檔案中使用預定義的指令集控制字型hinting,當執行到MINDEX指令時,被操作的陣列長度n溢位成超大值,導致陣列寫越界。
MINDEX指令:對size為n的陣列進行迴圈左移一位。
0x03 漏洞分析
執行環境:
版本 | |
---|---|
作業系統 | 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; // [email protected]
_DWORD *v2; // [email protected]
int v3; // [email protected]
unsigned int v4; // [email protected]
int v5; // [email protected]
int result; // [email protected]
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
0x04 小結
- 能初步定位問題出在glyf表,並通過官方文件理解這段資料的意義很重要;
- windbg沒有watchpoint,在觀測65ee622c地址的資料變化時,只能靠人眼和記憶了,所以泉哥的分析用的Immunity Debugger;
- 這種資料是指令集的反彙編程式碼開始比較難看。在想llvm和jit是不是也會有這樣的bug。
0x05 參考文獻
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