作者:啟明星辰ADLab
公眾號:https://mp.weixin.qq.com/s/ODmXAZKz5JVitjzXpUdz9g

1 背景

VMware Workstation是一款主流的虛擬機軟件,近期啟明星辰ADLab安全研究員在使用VMware虛擬機的過程中遇到虛擬機異常崩潰的問題,當從7zip中直接將文件拖拽到VMware虛擬機中,會造成虛擬機異常關閉。目前已測試過VMware 15.5.0、15.5.2、15.5.5 以及7zip 19.0、20.02等版本。本文將通過對VMware和7zip程序進行跟蹤分析,最終定位虛擬機異常關閉原因。

2 VMware端調試分析

使用WinDbg -I指令將WinDbg設置為即時調試器,VMware-vmx.exe程序崩潰后自動彈出WinDbg。堆棧信息如下:

img

調試信息顯示stack buffer overrun異常,最初推斷可能是緩沖區溢出漏洞。

img

通過查詢資料后發現,從Windows 8開始,Windows設計了一個新的中斷INT 29H,用以快速拋出失敗,在sdk中被聲明為fastfail, fastfail內部函數不會返回。

體系結構 指令 代碼參數的位置
x86 int 0x29 ecx
x64 int 0x29 rcx
ARM 操作碼 0xDEFB r0

在上圖中,程序終止于int 29h,而它的參數為0xa,對應FAST_FAIL_GUARD_ICALL_CHECK_FAILURE,由此推斷問題可能出現在CFG的檢查過程中。

img

從函數調用棧中vmware_vmx+0x58b21地址向上追溯,動態調試程序,比較程序正常運行與異常崩潰的函數調用區別,定位到與程序崩潰相關的函數sub_1400965A0。

使用Windbg Attach vmware-vmx.exe程序,在sub_1400965A0函數設置斷點,開始動態調試。從7z打開的壓縮文件中拖拽cdp.pcapng的文件,程序在斷點處停下。通過動態調試可知該函數中calloc分配了三個堆空間,分別用于存放:主機臨時文件路徑temp_path、目標文件名file_name以及VMware中的緩存目錄名vm_cache_dir_name。

img

但是打開主機Temp目錄下卻沒有發現該文件,于是初步斷定這是程序崩潰原因。繼續往下看,3個文件相關參數全都傳入了sub_140579b30函數。

img

進入函數sub_140579b30,定位temp_path參數的處理。其中,sub_14057FF90函數對傳入的temp_path進行了逐一遍歷,sub_1405B2080函數對傳入的temp_path進行了非法性檢查。下面重點分析sub_140576460函數。

img

sub_140576460函數將路徑參數temp_path傳入了sub_14049DA50。

img

首先,函數sub_14049DA50通過sub_140477C70對字符串進行了處理。 然后,調用wstat64獲取相應路徑的文件狀態,如果成功獲取則保存到一個結構體中,否則返回0xffffffff。由于Temp目錄下并未發現備份文件,導致獲取狀態失敗,從而返回0xffffffff。

img

img

返回0xffffffff后,重新回到sub_140579b30函數中,程序跳出while循環到達如下位置,輸出錯誤信息并跳轉至sub_140572A70。

img

從sub_140572A70最終執行到sub_1400960C0,到達如下位置將vmware_vmx+0xb1ed90處的值賦給了rsi,即為0。

img

繼續往下執行,將rsi中0值賦值到rax中,然后調用0x7ff8fab0c510處,即ntdll!LdrpDispatchUserCallTarget。

img

此處與靜態下的過程有一點不同,靜態下該處調用如下:

img

? 如果按照靜態過程執行,應當到達sub_1407C7650,即如下位置:

img

在ntdll.dll被加載之前,該處數據依舊為上圖所示地址:

img

? 后來在ntdll.dll中實施CFG(ControlFlow Guard)保護機制,將vmware_vmx+0x7c9668地址處數據進行了改寫,從而執行到ntdll!LdrpDispatchUserCallTarget中。

img

在ntdll!LdrpDispatchUserCallTarget函數中,取r11+r10*8處的值賦值給r11時出現了問題,該地址為空,就造成了空指針引用, 從而執行了int 29h,造成異常。然而,即使沒有CFG機制,程序也會在執行“jmp rax”處崩潰,通過下圖可以看出,CFG機制僅僅是在原本程序跳轉指令前添加了一些檢查。

imgimg

至此,VMware崩潰的原因基本分析清楚了。另一個疑問是,為什么7zip已經在系統Temp下生成了文件,并且VMware也已經獲取到了路徑參數,卻在移動前自動刪除了文件呢。這就需要從7zip中尋找答案。

3 7zip端調試分析

由上一節分析可知,Vmware crash原因是Temp目錄下文件被刪除。閱讀7zip源碼,鎖定了CPP/Windows/FileDir.cpp中的文件刪除函數。

img

使用WinDbg加載7zip,然后在Remove函數位置進行下斷,程序運行后進行拖拽操作,在Remove函數中斷后對應的調用堆棧如下所示。

img

堆棧中7zFM+0x5b212地址位于函數CPanel::OnDrag中,該函數為鼠標拖拽操作函數。當檢測到對7zip打開的目錄進行操作時,便會在Temp目錄下生成一個以7zE開頭的隨機命名文件夾。

img

然后,將該文件夾設置為目標目錄,并且設置了一些數據及IpDropSourse結構體。

img

繼續往下可以看到一個DoDragDrop函數,該函數功能是進行OLE拖放相關操作,通過檢測光標的行為分別調用一些方法并返回對應的數值。

img

然后根據DoDragDrop函數的返回值來判斷光標的拖拽是否有效,從而執行對應的操作。

img

img

從7zip中拖拽文件到虛擬機,由于無法獲知文件拖拽的目標路徑,因此DoDragDrop會返回DRAGDROP_S_CANCEL(0x40101),不會執行拷貝操作的分支,而是直接將Temp目錄下生成的臨時目錄刪除。

img

4 小結

7zip壓縮包中文件拖拽操作會觸發DoDragDrop函數調用,該函數會獲取文件數據及光標停止的位置。但是將文件拖拽到VMware窗口時,DoDragDrop函數不能獲取準確的目標路徑,因此無法將文件拷貝到目標位置,從而直接刪除臨時文件,最終導致VMware無法獲取文件狀態造成崩潰。

5 參考

[1]https://0cch.com/2016/12/13/int29h/

[2]https://docs.microsoft.com/en-us/windows/win32/api/ole2/nf-ole2-dodragdrop

[3]https://github.com/kornelski/7z/tree/20e38032e62bd6bb3a176d51bce0558b16dd51e2


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1291/