cve-2017-11882 poc分析
目錄
CVE-2017-11882 poc分析
思路:由樣本poc出發,尋找漏洞觸發點
0x00 工具&實驗環境
- 系統:windows 7 x64
- 除錯工具:windbg,OD吾愛破解專用版,
- 其他工具:process Monitor,pchunter
- office 2016
- 樣本獲取:http://blog.51cto.com/chenxinjie/2092755
0x01 分析行為
第一步:觀察poc行為
開啟11882.rtf (樣本檔案)後,彈出一個計算器,如下圖所示:
ok,既然彈出了計算器,那麼我就用windbg附加到Word程式用bp命令下那幾個函式的斷點嘛(CreateProcess系列、WinExec、ShellExecute系列),然後再把11882.rtf脫進被附加偵錯程式的Word程式。
但是結果出乎我意料,計算器都彈出來了,windbg卻還是BUSY狀態(沒有觸發斷點)。我的第一反應就是,難道windbg出bug了?於是我再三檢查,查閱可以彈出計算器的函式,試了幾次,都沒有斷下來。於是,我請教了一位搞逆向很厲害的樹老哥
第二步:找出計算器被彈出的地方
樹老哥 是這樣做的:
首先他開啟pchunter檢視計算器程序的程序資訊,結果如下圖:
發現有什麼不對勁的地方了嗎?calc的父程序居然不是WINWORD.EXE!(calc.exe的父程序id不等於WINWORD.EXE的程序ID),那就說明計算器不是由WINWORD.EXE程序開啟的。那麼根據calc的父程序ID查詢,得出calc是由程序ID為2440的cmd.exe建立的。而cmd.exe的父程序ID是2476,但是當前程序列表中並沒有程序ID是2476的程序資訊。說明那個程序ID為2476的程序是個一秒男,放出了cmd.exe就沒了。
那麼怎麼去找到是哪個程序建立了cmd.exe呢?這個時候就可以上程序監控神器:Process Monitor了。Process Monitor 是windows下高階實時監聽工具,用於監視檔案系統、登錄檔、程序和執行緒的活動。
下面是具體操作步驟:
- 首先開啟process monitor開始監控,雙擊開啟11882.rtf樣本檔案,待彈出計算器程式後,停止process monitor的監控(不關監控的話,會記錄很多其他資訊,不利於分析)。
開啟pchuntor檢視cmd.exe的父程序id,得到cmd.exe的父程序id為428
再在Process Monitor中的記錄大量記錄資訊進行PID過濾,得到是EQNEDT32.EXE這個程式建立的cmd.exe。它的路徑也可以在下圖中得到:
- 點中任意一個條目,ctrl+p可以得到EQNEDT32.EXE的父程序ID
ok,同理使用Process Monitor的過濾功能,得到原來是svchsot.exe建立的EQNEDIT32.EXE。
在看看winword.exe中的程序相關資訊,發現WINWORD.EXE是通過呼叫系統服務啟動的公式編輯器EQNEDT32.EXE(可以選中下圖中選中那項,再Ctrl+P檢視這一條記錄的棧資訊)
根據大佬解釋,這是一種叫做decom的呼叫方法(後臺呼叫com元件)。
好了,既然已經找到了彈出計算器的程序是EQNEDT32.EXE,那麼我們就開啟這個程式,然後用windbg附加它,bp 那幾個函式,再開啟11882.rtf樣本檔案,看看能不能斷下來。嘿嘿斷下來了,可以看到執行的命令引數為:cmd.exe /c calc.exe &一堆亂碼
好,下面進行棧回溯,看看是哪兒出了問題。
0x02 除錯定位漏洞觸發點
檢視棧回溯資訊如下:
0:000> kb 4 ChildEBP RetAddr Args to Child 0018f1d0 00430c18 0018f354 00000000 0018f1f0 kernel32!WinExec WARNING: Stack unwind information not available. Following frames may be wrong. 0018f214 004218e4 0018f354 0018f5e4 0018f7e4 eqnedt32!MFEnumFunc+0x241b 0018f304 004214e2 0018f354 72ed005a 00000001 eqnedt32!FMDFontListEnum+0x650 0018f330 0043b466 0018f354 72ed005a 0018f5e4 eqnedt32!FMDFontListEnum+0x24e
可以定位到返回位置為0x00430c18,IDA 檢視該位置處的程式碼如下:
.text:00430C0C push 1 ; uCmdShow .text:00430C0E mov eax, [ebp+lpCmdLine] .text:00430C11 push eax ; lpCmdLine .text:00430C12 call ds:WinExec ; 呼叫的它 .text:00430C18 cmp eax, 20h .text:00430C1B jnb loc_430C43
那麼是從哪兒執行到call ds:WinExec的呢?只有看棧的資訊(或者使用ctrl+f8或ctrl+f7的方法,不建議使用)。很明顯棧被破壞了,只看得到最近的一個返回地址是0x004218e4,IDA檢視該位置處的程式碼如下:
.text:004218DE push eax ; lpString1 .text:004218DF call sub_4115A7 ;呼叫的它 .text:004218E4 add esp, 4 .text:004218E7 test eax, eax .text:004218E9 jz loc_421919
好,使用OD來附加(因為windbg不好儲存斷點記錄,也不好及時的看堆疊的資訊,所以現在換OD上)。先開啟EQNEDT32.EXE,用OD附加後在0x4218DF處下斷。開啟11882.rtf樣本poc檔案,發現斷到了0x4218DF處。
然後單步步入,看看執行到call ds:WinExec的呼叫順序是啥子樣子的。有耐心的分析出來是這樣的:
sub_4115A7--->sub_41160F--->ret--->call ds:WinExec
Tip:我在進入了sub_41160F後(已經使用了bp WinExec函式下斷),使用Ctrl+F8,讓其自動單步步過找下一個call的時候,發現其實就沒有下一個call了。
意思是:當自動單步步過停止的時候,按esc鍵先是回到call ds:WinExec處,再按一下esc鍵,就回到了sub_41160F函式的最後0x00411874 處了,而該處是一條ret指令。
所以我在這條ret指令處下了斷點,重新除錯,發現斷到這個ret指令的時候,棧頂的值為0x00430c12,也就是call ds:WinExec指令的地址。
所以判斷應該是棧溢位,覆蓋了函式的返回地址。
那麼是哪兒把sub_41160F的返回地址給覆蓋成了0x430c12了呢?先不管,先看看進入sub_41160F函式的時候棧的情況:可以發現剛進入的時候,返回地址是沒有出問題的
繼續單步調,發現到了這兒,返回地址就馬上從正確的0x004115d8變為了,0x00430c12。
0x03 分析漏洞成因
下面來分析一下這個sub_41160F函式:
int __cdecl sub_41160F(char *a1, char *a2, int a3)
{
int result; // eax
char v4; // [esp+Ch] [ebp-88h]
char v5; // [esp+30h] [ebp-64h]
__int16 v6; // [esp+51h] [ebp-43h]
char *v7; // [esp+58h] [ebp-3Ch]
int v8; // [esp+5Ch] [ebp-38h]
__int16 v9; // [esp+60h] [ebp-34h]
int v10; // [esp+64h] [ebp-30h]
__int16 v11; // [esp+68h] [ebp-2Ch]
char v12; // [esp+6Ch] [ebp-28h]
int v13; // [esp+90h] [ebp-4h]
LOWORD(v13) = -1;
LOWORD(v8) = -1;
v9 = strlen(a1);
strcpy(&v12, a1); //這兒造成的 :覆蓋返回地址
_strupr(&v12);
/*
.....省略一部分
*/
return result;
}
堆疊圖:
strcpy(&v12,a1) 太明顯不過的棧溢位了,對棧上進行字串拷貝未做長度檢測,如果a1所指向的字串的長度大於或等於48個位元組,就可以完全覆蓋掉返回地址。除錯的時候發現a1所指向的記憶體為下圖所示:
的確如此,((DWORD*)a1)[11] = 0x00430c12 就是call ds:WinExec的地址。
當然,讀取a1的過程我也分析了下:分析思路是 根據棧回溯,結合OD,IDA除錯查詢。是在sub_43b418中呼叫sub_4164fa讀取的a1,讀取終止條件是一直讀到\0結束。
_BYTE *__cdecl sub_4164FA(_BYTE *a1)
{
char *v1; // ST0C_4
_BYTE *result; // eax
do
{
v1 = a1++;
*v1 = sub_416352();//從一塊固定記憶體塊中讀取
}
while ( *v1 );//讀到\0結束
result = a1;
*a1 = 0;
return result;
}
所以關鍵就是 看怎麼才能構造個樣本,讓我們執行到這個地方,公式編輯器是將樣本的哪個地方載入到了那個固定記憶體塊中,如果可以找到,那麼就可以構造樣本了。
經過回溯棧,找關鍵call 的方式,我發現 好像並不是公式編輯器解析的文字文件。
全是ole32的rpc*呼叫。等於說,我分析不動了。那就先暫時分析到這兒,等我功力上去了,再來搞。
0x04 總結
微軟和Intel處理器的成功很大一部分原因是因為他們的產品始終都盡最大努力向下相容。但是這樣也造成了極大的安全隱患。比如這個公式編輯器,超級超級老了,不支援ASLR,DEP等漏洞緩解措施。但是為了保持向下相容,儘管都office 2016了,微軟還是將它保留了下來。
所以,很多人都會選擇去挖那些微軟為了相容性而保留下來的軟體的漏洞。我估計不止office軟體,像伺服器上的軟體比如:SQL Server系列的軟體 肯定也有很多。
怎麼去挖呢???來個高人指點指點我吧。