MS08-067漏洞原理及詳盡分析過程

2019-06-01 87064人圍觀 ,發現 3 個不明物體 漏洞系統安全

*本文中涉及到的相關漏洞已報送廠商并得到修復,本文僅限技術研究與討論,嚴禁用于非法用途,否則產生的一切后果自行承擔。

在《Metasploit滲透測試魔鬼訓練營》中講過MS08-067的漏洞原理,不過內容十分晦澀難懂難以消化,我反復閱讀鉆研了幾遍并通過實踐分析,對該部分的內容用通俗易懂的語言重新組織一遍,畫了該漏洞溢出的原理圖,就當做分享和學習總結吧。

0×01 MS08-067漏洞原理

MS08-067漏洞是通過MSRPC over SMB通道調用Server服務程序中的NetPathCanonicalize函數時觸發的,而NetPathCanonicalize函數在遠程訪問其他主機時,會調用NetpwPathCanonicalize函數,對遠程訪問的路徑進行規范化,而在NetpwPathCanonicalize函數中存在的邏輯錯誤,造成棧緩沖區可被溢出,而獲得遠程代碼執行(Remote Code Execution)。

所謂路徑規范化,就是將路徑字符串中的【/】轉換為【\】,同時去除相對路徑【.\】和【..\】。如:

**/*/./**   =>  **\*\**
**\*\..\**  =>  **\**

在路徑規范化的操作中,服務程序對路徑字符串的地址空間檢查存在邏輯漏洞。攻擊者通過精心設計輸入路徑,可以在函數去除【..\】字符串時,把路徑字符串中內容復制到路徑串之前的地址空間中(低地址),達到覆蓋函數返回地址,執行任意代碼的目的。

路徑處理流程

NetpwPathCanonicalize函數并沒有直接進行輸入路徑和規范化,而是繼續調用了下級函數CanonicalizePathName來進行路徑整理,將待整理的路徑字符串進行規范化,然后再保存到預先分配的輸出路徑緩沖區buffer中。

路徑處理流程:

1.檢查待整理路徑的第一個字符;

2.調用msvcrt.dll模塊的wcslen函數計算路徑長度;

3.調用msvcrt.dll模塊的wcscat函數把待整理路徑全部復制到新申請的內存中。

4.調用wcscpy函數,去掉待整理路徑中第一個表示父目錄的相對路徑復制到strTemp,如:

\******\..\..\***   =>  \..\***

5.循環調用wcscpy,直到路徑整理完畢。

在這里我們知道了,在規范化復制時要尋找表示父目錄的【..\】字符串及其前面的一個【\】字符串,將這一段去掉并將新路徑復制。

img

如圖,第一次檢查時去掉了第一個相對路徑并復制到緩沖區

但是,當【..\】字符串在路徑字符串的最前面時,那么其前面的一個【\】就在緩沖區外面了,就是在這里產生了向前(低地址)的溢出。

img

緩沖區溢出

需要明確的是,微軟對路徑規范化時的字符串復制可能出現的緩沖區溢出做了初步的防御。

在每次向緩沖區中復制字符串時,無論是用wcsccpy還是wcscat,在復制前總要比較源字符串的長度,保證長度小于某個值(207),否則不會繼續復制,這一策略確保緩沖區不會向高地址溢出,即當前函數返回時不會發生問題。

但是注意,在規范化表示路徑,尋找父目錄的【..\】字符串前面的【\】字符時,程序做了判斷和邊界檢查:如果當前比較字符的地址與源字符串地址相同,就表明整個字符串已經查找完畢,程序就會停止查找。

然而它唯獨漏了一種情況,就是當父目錄相對路徑【..\】字符串在源字符串的開頭時,在開始查找時比較的字符串(【\】到【..\】)位于緩沖區之外,這導致了復制的字符串向低地址的溢出,造成函數wcscpy的返回地址被覆蓋。

img

0×02 漏洞還原分析

實驗環境

靶機:Windows2003 SP0 EN

漏洞組件:netapi32.dll

工具:IDA Pro、OllyDbg

選擇Windows XP SP3 EN系統主機作為分析環境,定位到包含該安全漏洞的系統模塊netapi32.dll(路徑C:\Windows\system32)和調用漏洞服務Server的進程svchost.exe,目標進程命令行為:

C:\Windows\System32\svchost.exe-k netsvcs

用IDA pro打開netapi32.dll,找到漏洞所在的NetpwPathCanonicalize函(每次運行堆棧中的地址會不同,但各函數的地址一樣),如圖在書中提到:

查看該函數流程圖,可以看到,此函數并沒有直接進行輸入路徑的規范化, 而是繼續調用了下級函數CanonicalizePathName

然而在實際操作中并沒有發現CanonicalizePathName這個函數,并且多種資料表明應當是調用CanonPathName函數進行規范化。

IDA分析NetpwPathCanonicalize函數代碼(F5 + 整理 + 主要代碼):

該函數聲明如下:

DWORD NetpwPathCanonicalize(
    LPWSTR PathName, //需要標準化的路徑
    LPWSTR Outbuf, //存儲標準化后的路徑的Buffer
    DWORD OutbufLen, //Buffer長度
    LPWSTR Prefix, //可選參數,當PathName是相對路徑時有用
    LPDWORD PathType, //存儲路徑類型
    DWORD Flags // 保留,為0
 )

動態調試

通過wmic查看命令行參數為svchost.exe -k netsvcs的進程pid:

img

打開OllyDbg,點擊file->attach,附著到svchost.exe進程上:

img

View->Executable modules雙擊netapi32,在cpu指令窗口右鍵選Search for查找exec(label) in current module,找到函數NetpwPathCanonicalize,地址為71C44A3E,在此處設下斷點:

img

追蹤漏洞觸發過程

回到CPU指令窗口運行程序,然后攻擊機Metasploit加載ms08_067_netapi模塊并exploit:

img

NetpwPathCanonicalize中斷

分析環境中的svchost程序會中斷在NetpwPathCanonicalize函數的入口地址處。該函數的傳入參數如下所示:

img

esp            [esp]        * 注釋 *
00ECF924    02248D34    ;指向待整理路徑
00ECF928    022321D8    ;指向輸出路徑buffer
00ECF92C    000003F1    ;輸出buffer的長度
00ECF930    02248FB0    ;指向prefix,值為 \x5C\x00 ,即unicode ‘\’
00ECF934    02248FB4    ;指向路徑類型,值為 0x1001
00ECF938    00000000    ;WORD Flags保留,值為0

CanonicalizePathName中斷

結合IDA pro對NetpwPathCanonicalize的流程分析,在地址處將調用下一級函數CanonPathName,在此地址設下斷點:

img

運行到此斷點,然后跟蹤函數CanonPathName,傳入參數如下所示:

00F0F8FC    00157570    ;指向prefix,值為\x5C\00,即Unicode"\"
00F0F900    001572F4    ;指向待整理路徑
00F0F904    02132E80    ;指向輸出路徑的buffer
00F0F908    000003F9    ;輸出buffer的長度
00F0F90C    00000000    ;WORD Flag保留字,值為0

從上兩個函數的參數傳遞可以看出,函數CanonPathName進行路徑整理,然后再保存到預先分配的輸出路徑緩沖區buffer中。

待整理路徑結構

在OD中查看待整理路徑的結構,路徑是Unicode字符串,以【\x5C\x00】(Unicode字符“\”)開始,【\x00\x00】結束,中間包含一些隨機的大小寫字母,較長一段不可顯示的字符是經過編碼的Shellcode,其中最關鍵的是兩個連在一起的父目錄相對路徑【….\】。

1557343359609

整個待整理路徑形如:

\******\..\..\***

整理路徑前的預操作

在待整理路徑所在內存地址000C0F50處4字節上設內存訪問斷點:

1557343390836

按F9運行,會中斷3次,前兩次分別是檢查待整理路徑的第一個字符和調用wcslen函數,第三次是在調用wcscat函數。分析第三次傳入棧中兩個參數:

1557343410176

第一個是strDestination,指向一段以【\x5c\x00】開頭的內存空間;第二個是strSource,指向上述待整理路徑前兩字節【\x5c\x00】后的內容。

程序把待整理路徑全部復制到strDestination,即0x001572F6處。在此4字節設斷點,類型選擇”Hardware, on access”DWord。

1557343435014

復制路徑到緩沖區

F9繼續運行,第4次中斷在0x77BD4010 ,內存里顯示這里將src的前兩個字符復制到了dest的【\x5C\x00】后面,這是由于這兩個字節設了斷點的原因:

1557343573648

第5次中斷在0x71C44B1C,位于wcscat函數內,內存顯示已將src復制到dest,如圖:

1557343589111

1557343606903

第一次路徑規范化

按F9運行,中斷多次后停在內存0x77bd4d36處,通過??芍颂帉儆趙cscpy函數。此處調用該函數進行第一次路徑規范化。如圖:

1557343631915

當前參數src值為0x00EC6E0,指向【..*】;參數 strDestination 值為0x00ECF4DC,指向temp中的第一個字符【\】。 顯然,這次路徑規范化即把待整理路徑中第一個字符【\】和第一個【..\】相對路徑之間的內容拋棄。

1557343644183

而此時wcscpy源地址src在edx寄存器中,指向【..*】;目的地址dest在ecx寄存器中,指向待整理路徑第一個字符【\】,如圖:

1557343668919

所以,這次字符串復制操作就是去掉第一個表示父目錄的相對路徑,即待整理路徑temp中的第一個【\】和第一個【..\】之間的內容成為無用路徑被拋棄。操作完成后,temp中的路徑字符形如【..*】。

第一次規范化后,待整理路徑形如:

\..\***

由于還有【..\】,還需要進行一次規范化,而這第二次規范化正是玄機所在。

第二次路徑規范化

由于每次路徑規范化都會調用wcscpy函數,接下來刪除0x00ECF4DC的硬件斷點,直接在wcscpy函數的入口地址0x77BD4D28處下斷點。

1557343841212

F9運行后中斷在wcscpy函數入口0x77BD4D28處,調用wcscpy函數傳入的參數:

1557343857034

esp            [esp]        * 注釋 *
00ECF4AC    00ECF494    目的地址,指向的內存區域值為\x5c\x00,即【\】
00ECF4B0    00ECF4E2    源地址,指向第二個相對路徑【\..\】的最后一個斜杠

正常情況下,這次規范化處理會和第一次執行同樣的操作,去除第二個相對路徑【..\】,從而完成第二次的路徑規范化。但這里出現了一個意外的情況,temp的首地址是0x00ECF4DC,而此次字符串復制操作的目的地址dest卻在0x00ECF494,在temp之前,如圖:

1557343903100

同時注意到,棧指針ESP值為0x00ECF4A8,該地址指向wcscpy函數的返回地址0x71C52FD4。ESP到復制目的dest地址0x00ECF494只有0×14字節,于是,函數wcscpy如果繼續執行,將用源字符串src覆蓋wcscpy函數的返回地址。

執行到retn命令,可以看到返回地址變成了0x0100129E,該地址的指令為:

00100129E        FFD6        call esi

執行 call esi(ES=0x00F0F4DE)指令,正好將EIP指向復制盡量的字符串中構造好的第8字節空指令,接著是【\xeb\x62】(jmp 0×62),此jmp指令跳過中間的隨機字符串,指向經過編碼的Shellcode,如圖:

1557343946968

所以這里是由于內存0x00F0F494處的一個【\】(0x5C),使得出現在處理父母了相對路徑【..\】時往前溢出了待處理路徑,從而將字符串覆蓋到函數wcscpy返回地址的位置,跳轉到shellcode造成遠程代碼執行。

正如前面所提到的,當【..\】在源字符串開頭的時候,在開始查找時,比較的字符位于緩沖區之外導致了向前的溢出。

參考

《Metasploit滲透測試魔鬼訓練營》,諸葛建偉。

*本文作者:Dhakkan,轉載請注明來自FreeBuf.COM

發表評論

已有 3 條評論

取消
Loading...

特別推薦

推薦關注

填寫個人信息

姓名
電話
郵箱
公司
行業
職位
css.php jizzz