偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

尋找VMware Workstation渲染器中的漏洞

云計(jì)算 虛擬化
有趣的是,早在2006-2009年間,就有針對(duì)D&D和C&P的漏洞而完成虛擬機(jī)逃逸了。然而在2015年Kostya Kortchinsky和lokihardt又在D&D和C&P中發(fā)現(xiàn)了類(lèi)似的漏洞。從此,研究員們開(kāi)始對(duì)這些代碼更加深入的研究。

[[214684]]

背景

一月中旬,ZDI宣布了2017年比賽的規(guī)則,其中包括了攻破VMware,完成虛擬機(jī)逃逸的隊(duì)伍會(huì)獲得相當(dāng)高額的獎(jiǎng)金。VMware已經(jīng)不是一個(gè)新目標(biāo)了。在2016年,VMware就被確定為攻擊目標(biāo)。

作為攻擊目標(biāo),VMware已經(jīng)經(jīng)歷過(guò)各種各樣的攻擊,攻擊點(diǎn)很多。

有趣的是,早在2006-2009年間,就有針對(duì)D&D和C&P的漏洞而完成虛擬機(jī)逃逸了。然而在2015年Kostya Kortchinsky和lokihardt又在D&D和C&P中發(fā)現(xiàn)了類(lèi)似的漏洞。從此,研究員們開(kāi)始對(duì)這些代碼更加深入的研究。

從我們旁觀(guān)者的角度,這一現(xiàn)象是令人深思的。我們?cè)谙?,VMware的漏洞一共有多少?其中又有哪些能被我們發(fā)現(xiàn)?

雖然一系列的漏洞被曝光,但是在2016年的Pwn2Own上,沒(méi)有一支隊(duì)伍能夠成功完成虛擬機(jī)逃逸。雖然像VMware這樣的傳統(tǒng)桌面軟件不是我們的研究領(lǐng)域。但我們還是對(duì)尋找VMware中的漏洞非常感興趣。

我們決定面對(duì)這個(gè)挑戰(zhàn),看看挖掘VMware中的漏洞到底有多困難。我們定了一個(gè)計(jì)劃,用一個(gè)月的業(yè)余時(shí)間來(lái)尋找漏洞。雖然我們沒(méi)能在Pwn2Own前完成,但我們確實(shí)發(fā)現(xiàn)了一些高危漏洞,并且嘗試通過(guò)這些漏洞找到VMware中可利用的攻擊點(diǎn)。

攻擊面

之前并不了解VMware的細(xì)節(jié),我們開(kāi)始不清楚實(shí)施攻擊應(yīng)該從何處著手。關(guān)注指令模擬的內(nèi)部細(xì)節(jié)會(huì)有幫助么?有些CPU支持VT,又有多少指令是被模擬的?為了避免與他人撞洞,除了打印和像D&D或C&P的主機(jī)客戶(hù)機(jī)交互外,還剩下什么呢?

下文是我們的研究成果,正如Pwn2Own規(guī)定的,所有的漏洞都要能被虛擬機(jī)里的普通用戶(hù)所利用。

VMWare模塊

在VMware的各種模塊中,GUI是最不受關(guān)注的部分。VMware在主機(jī)和虛擬機(jī)端都有內(nèi)核模塊(至少有vmnet/VMCI),thnuclnt(負(fù)責(zé)虛擬打印),vmnet-dhcpd,vmnet-natd,vmnet-netifup,vmware-authdlaucher,vmnet-bridge,vmware-usbarbitrator,vmware-hostd,還有虛擬機(jī)端最重要的vmware-tools。

幾乎所有的這些模塊都是作為特權(quán)進(jìn)程運(yùn)行,這使得他們成為被研究者分析的對(duì)象。虛擬打印已經(jīng)被攻擊多次了。

vmnet-dhcpd吸引了我們的注意,因?yàn)樗詒oot模式運(yùn)行并且是從ISC-DHCPD演變而來(lái)。更令人感興趣的是,vmware-dhcpd基于isc-dhcp2。我們開(kāi)始把它作為攻擊目標(biāo)。

然而,當(dāng)我們發(fā)現(xiàn)公開(kāi)的漏洞后(CVE-2011-2749,CVE-2011-2748)我們就放棄了這一想法。VMware為了防止漏洞,已經(jīng)在最新的isc-dhcp中修補(bǔ)了漏洞。

于是我們決定在QEMU和AFL對(duì)vmware-dhcpd的一些小補(bǔ)丁進(jìn)行fuzz測(cè)試。一個(gè)月的fuzzing并沒(méi)有顯示出任何漏洞。vmware-hostd也是一個(gè)令人感興趣的進(jìn)程,它作為一個(gè)web服務(wù)器,用于虛擬機(jī)共享,而且可以從虛擬機(jī)內(nèi)部訪(fǎng)問(wèn)到。然而,我們還是決定把精力投入研究VMware的核心組件。

vmware-vmx是最主要的虛擬機(jī)監(jiān)管模塊,在主機(jī)上作為root/系統(tǒng)進(jìn)程運(yùn)行,擁有一些令人感興趣的特性。事實(shí)上,它有兩個(gè)版本,vmware-vmx和vmware-vmx-debug。

如果VMware的設(shè)置中調(diào)試選項(xiàng)被啟用,那么使用的就是后者。這一點(diǎn)很重要,因?yàn)楫?dāng)我們進(jìn)行逆向工程時(shí),從擁有很多調(diào)試信息的版本開(kāi)始總會(huì)簡(jiǎn)單許多。或許這不是最適合的方法,但卻很有效。后面我們會(huì)講到。

RPC/RPCI

你可曾經(jīng)想過(guò)VM和主機(jī)之間的文件拖放功能是如何實(shí)現(xiàn)的?RPC在其中發(fā)揮了重要的作用。VMware內(nèi)部在0x5658端口上提供了一個(gè)接口作為“后門(mén)”。通過(guò)這個(gè)端口,虛擬機(jī)可以通過(guò)I/O指令來(lái)和主機(jī)進(jìn)行通信。

通過(guò)寄存器傳遞一個(gè)VMware可識(shí)別的魔數(shù),VMware會(huì)自動(dòng)解析附加的參數(shù)。I/O指令通常都是特權(quán)指令,但這個(gè)“后門(mén)”接口是個(gè)例外。這種例外是很少的。當(dāng)執(zhí)行一個(gè)后門(mén)I/O指令時(shí),VMware會(huì)進(jìn)行一系列的判斷,判斷該I/O指令是否來(lái)自擁有特權(quán)的虛擬機(jī)。

在這個(gè)“后門(mén)”接口的上層,VMware使用了RPC服務(wù)在主機(jī)和客戶(hù)機(jī)之間交換數(shù)據(jù)。在客戶(hù)機(jī)端,vmware-toolsd執(zhí)行“后門(mén)”命令的同時(shí),使用了RPC服務(wù)。

這就是為什么之后在安裝了vmware-toolsd的客戶(hù)機(jī)上,你才能使用像拖放文件這樣的功能。內(nèi)核驅(qū)動(dòng)和用戶(hù)空間功能的結(jié)合利用實(shí)現(xiàn)了這一功能。

在最初的“后門(mén)”接口中只能通過(guò)寄存器來(lái)傳遞數(shù)據(jù),面臨大量數(shù)據(jù)的傳輸時(shí),速度會(huì)變得很慢。為了解決這個(gè)問(wèn)題,VMware引入了另一個(gè)端口(0x5659)來(lái)實(shí)現(xiàn)高帶寬的“后門(mén)”。實(shí)際上這個(gè)端口是被RPC使用。

通過(guò)傳遞一個(gè)數(shù)據(jù)指針,vmware-vmx不用重復(fù)的調(diào)用IN指令,直接調(diào)用read/write API就可以完成數(shù)據(jù)的傳輸,Derek曾經(jīng)就在這個(gè)功能里發(fā)現(xiàn)了一個(gè)非常有趣的漏洞。

RPC接口提供了以下的功能:

  • 打開(kāi)通道
  • 發(fā)送命令長(zhǎng)度
  • 發(fā)送數(shù)據(jù)
  • 接受回復(fù)的長(zhǎng)度
  • 接受數(shù)據(jù)
  • 結(jié)束互動(dòng)
  • 關(guān)閉通道

你可能會(huì)想如何防止進(jìn)程擾亂RPC的交互,建立一個(gè)通道時(shí),VMware會(huì)生產(chǎn)兩個(gè)cookie值,用它們來(lái)發(fā)送和接受數(shù)據(jù)。顯然,這兩個(gè)cookie是以安全的方式生成的。由于這兩個(gè)cookie就是兩個(gè)32位的無(wú)符號(hào)整數(shù),不能用memcmp和其他方式來(lái)比較它們。

在上層,VMware還用RPC命令來(lái)處理DnD,CnP,Unity和其他的事件。有些命令只能在虛擬機(jī)特權(quán)用戶(hù)下執(zhí)行。在虛擬機(jī)端。vmware-tool或open-vm-tools提供了rpctool用來(lái)和API交互。保存和獲取虛擬機(jī)信息的一個(gè)簡(jiǎn)單的例子如下:

  1. rpctool 'info-set guestinfo.foobar baz' 
  2. rpctool 'info-get guestinfo.foobar' -> baz 

在vmware-vmx中保存信息并隨后提取出來(lái)。數(shù)據(jù)的儲(chǔ)存方式的細(xì)節(jié)不在本文的討論范圍內(nèi)。VMware內(nèi)部使用了VMDB,這是一個(gè)關(guān)鍵詞存儲(chǔ)的數(shù)據(jù)庫(kù),有為特定數(shù)據(jù)提供回調(diào)函數(shù)的功能。

然而,能在非特權(quán)虛擬機(jī)中調(diào)用的RPC命令數(shù)量有限。我們并不能提供一個(gè)完整的RPC命令列表,因?yàn)檫@和版本以及操作系統(tǒng)相關(guān)。最簡(jiǎn)單獲取命令列表的方式是從內(nèi)存中把命令列表dump下來(lái)。

令人欣慰的是,Linux版本的vmware-vmx提供了符號(hào),我們可以輕松的獲取到它。

最令人感興趣的攻擊點(diǎn)就是D&D,C&P和Unity了。然而我們并沒(méi)有研究它,原因有二。第一,lokihardt已經(jīng)在Pwnfest中成功利用它了。更重要的是,在Pwn2Own2016中,不允許使用Unity和虛擬打印中的漏洞。

由于這潛在的風(fēng)險(xiǎn),我們預(yù)計(jì)2017年VMware和ZDI會(huì)對(duì)與隔離設(shè)置無(wú)關(guān)的虛擬機(jī)逃逸更感興趣。雖然Pwn2Own 2017并沒(méi)給出比賽規(guī)則的細(xì)節(jié),但我們不愿意承擔(dān)著潛在的風(fēng)險(xiǎn)。最終,我們決定不挖RPC中的漏洞。

盡管如此,值得一提的是RPC中可以被攻擊利用的點(diǎn)很多,因?yàn)樗峁┝瞬倏囟褍?nèi)存的功能。

外圍設(shè)備的虛擬化

還有沒(méi)有其他的攻擊點(diǎn)呢?VMware的核心代碼實(shí)現(xiàn)了指令的虛擬化,同時(shí)也要為客戶(hù)機(jī)提供各種各樣的虛擬的外圍設(shè)備。這些設(shè)備包括了網(wǎng)絡(luò)、USB、藍(lán)牙、硬盤(pán)、圖像接口等等。

用戶(hù)空間服務(wù),虛擬機(jī)內(nèi)核驅(qū)動(dòng),和vmware-vmx一起來(lái)給虛擬化設(shè)備提供服務(wù)。例如,VMware在虛擬機(jī)內(nèi)部提供了SVGA圖形卡適配器,作為PCI顯示設(shè)備驅(qū)動(dòng)。

在Linux上,修改vmwgfx內(nèi)核模塊的X代碼,來(lái)建立一個(gè)vmware-vmx中SVGA3D/2D的接口層。我們認(rèn)為,在現(xiàn)代操作系統(tǒng)中,默認(rèn)開(kāi)啟的虛擬化的外圍設(shè)備是一個(gè)范圍很大的攻擊面。所以我們?cè)趯ふ夷J(rèn)啟用的,具有廣大攻擊面,并且能夠fuzz的模塊。最后我們選擇了圖形接口。

尋找渲染器中的漏洞

由于比賽平臺(tái)是Windows10上的VMware Workstation,我們決定在Windows而不是Linux上研究圖形接口。值得一提的是,Gallium的svga代碼中關(guān)于VMware圖形驅(qū)動(dòng)的開(kāi)源實(shí)現(xiàn)給了我們很大幫助,幫助我們分析vmware-vmx的相關(guān)部分。同樣的,微軟的圖形設(shè)備驅(qū)動(dòng)例程也對(duì)我們理解Windows驅(qū)動(dòng)的工作方式有很大幫助。

其他人曾經(jīng)攻擊過(guò)SVGA命令,我們決定深入研究,在這復(fù)雜的模塊的特定的功能中尋找漏洞:GPU渲染器的翻譯模塊。選擇渲染器字節(jié)碼而不是SVGA命令的一個(gè)重要原因是:渲染器字節(jié)碼可以從虛擬機(jī)內(nèi)部提供。

在linux和Mac上,渲染器是以O(shè)penGL實(shí)現(xiàn)。在Windows上,以Direct3D實(shí)現(xiàn)。因?yàn)閂Mware要支持不同的虛擬機(jī)操作系統(tǒng),各種渲染器的代碼都要被翻譯成主機(jī)上的渲染器行為。我們認(rèn)為,在這樣高度復(fù)雜的模塊中,隨之而來(lái)的是各種各樣的漏洞。

我們最初的分析是基于VMware Workstation 12.5.3的。

架構(gòu)

VMware中有兩種GPU的實(shí)現(xiàn)。一種是VGPU9(對(duì)應(yīng)DirectX 9.0),在Linux虛擬機(jī)和舊版本W(wǎng)indows虛擬機(jī)上使用。另一種是VGPU 10,在Windows10上使用。

對(duì)于3D加速圖形接口,VMware在Windows10虛擬機(jī)上使用WDDM(微軟顯示驅(qū)動(dòng)模型)驅(qū)動(dòng)。這個(gè)驅(qū)動(dòng)由用戶(hù)部分和內(nèi)核部分組成。用戶(hù)部分是vm3dum64_10.dll,內(nèi)核部分是vm3dp.sys。當(dāng)使用Direct 3D渲染器時(shí),字節(jié)碼要經(jīng)歷多次的翻譯。

由于VMware提供了虛擬3D支持,這些字節(jié)碼不能直接使用。它們會(huì)被進(jìn)一步的翻譯,Direct 3D API需要使用對(duì)應(yīng)的渲染器實(shí)現(xiàn)。因此,用戶(hù)空間驅(qū)動(dòng)實(shí)現(xiàn)了保存在D3D10DDI_DEVICEFUNC結(jié)構(gòu)中回調(diào)函數(shù)。它們把字節(jié)碼翻譯成對(duì)應(yīng)的API。

在這種情況下,VMWare SVGA3D定義了API,設(shè)置了渲染器。處理渲染器字節(jié)碼時(shí),用戶(hù)空間驅(qū)動(dòng)會(huì)調(diào)用內(nèi)核驅(qū)動(dòng)提供的pfnRenderCB回調(diào)函數(shù)。

任何需要GPU渲染器的Windows程序都要使用Windows D3D11 API。這些API負(fù)責(zé)翻譯文件中的渲染器字節(jié)碼,設(shè)置為不同種類(lèi)的渲染器。大致的翻譯過(guò)程如下圖。

這個(gè)過(guò)程包含了很多其他的細(xì)節(jié),涉及到的D3D11 API數(shù)量也很多。有興趣的讀者可以查看微軟提供的Direct3D11實(shí)例,并用Windbg來(lái)跟蹤調(diào)試它。(使用Windbg的wt命令)

  1. 0:000> x /D /f Tutorial03!i* 
  2.  A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 
  3.   
  4. 00000000`00da1900 Tutorial03!InitDevice (void) 
  5. 00000000`00da28f0 Tutorial03!InitWindow (struct HINSTANCE__ *, int
  6. 00000000`00da3630 Tutorial03!invoke_main (void) 
  7. 00000000`00da3620 Tutorial03!initialize_environment (void) 
  8. 00000000`00da4680 Tutorial03!is_potentially_valid_image_base (void *) 
  9. 00000000`00da637a Tutorial03!IsDebuggerPresent (<no parameter info>) 
  10. 00000000`00da63c8 Tutorial03!InitializeSListHead (<no parameter info>) 
  11. 00000000`00da63aa Tutorial03!IsProcessorFeaturePresent (<no parameter info>) 
  12. 0:000> bp Tutorial03!InitDevice 
  13. 0:000> g 
  14. Breakpoint 0 hit 
  15. Tutorial03!InitDevice: 
  16. 00da1900 55              push    ebp 
  17. 0:000:x86> wt -l 8 
  18. Tracing Tutorial03!InitDevice to return address 00da2dfe 
  19.   259     0 [  0] Tutorial03!InitDevice 
  20.   100     0 [  1]   USER32!GetClientRect 
  21. ... 

構(gòu)造渲染器的輸入數(shù)據(jù)

在和VMware的渲染器交互時(shí),了解渲染器的原理是很重要的。

編寫(xiě)DirectX的渲染器,需要使用高層渲染語(yǔ)言(HLSL)。用D3D11 API或者fxc.exe程序把它編譯成字節(jié)碼。根據(jù)渲染器模型的不同,HLSL提供了不同種類(lèi)的渲染器特征。

HLSL編譯結(jié)果是以渲染器模型的匯編字節(jié)碼的形式給出的。VMware目前在內(nèi)部支持SM3和SM4,但不支持SM5和SM6。這對(duì)我們?cè)谀嫦騰mware-vmx中的翻譯單元是很重要的。

不幸的是,在windows平臺(tái)上,除了用HLSL外沒(méi)有其他生成渲染器字節(jié)碼的工具了。因此,構(gòu)造精確的輸入來(lái)觸發(fā)漏洞就顯得很有難度了。CSO文件還需要修復(fù)校驗(yàn)值。檢查校驗(yàn)值的函數(shù)是D3D11_3SDKLayers!DXBCVerifyHash

為了能給VMware提供任意的渲染器字節(jié)碼輸入,我們使用了強(qiáng)大的Frida工具來(lái)hook和修改渲染器字節(jié)碼。當(dāng)vm3dum64_10.dll把編譯好的字節(jié)碼放入內(nèi)存后,我們就改變成我們想輸入的任意字節(jié)碼。通過(guò)逆向工程,我們確定了相應(yīng)的memmove()位置并且hook了它。

下面是我們Frida代碼的一部分。

  1. var vm3d_base = Module.findBaseAddress("vm3dum64_10.dll"); 
  2. console.log("base address: " + vm3d_base); 
  3.   
  4. function ida2win(addr) { 
  5.     var idaBase = ptr('0x180000000'); 
  6.     var off = ptr(addr).sub(idaBase); 
  7.     var res = vm3d_base.add(off); 
  8.     console.log("translated " + ptr(addr) + " -> " + res); 
  9.     return res; 
  10.   
  11. function start() { 
  12.     var memmove_addr = ida2win(0x180012840); 
  13.     var setShader_return = ida2win(0x180009bf4); 
  14.   
  15.     Interceptor.attach(memmove_addr, { 
  16.         onLeave : function (retval) { 
  17.             if (!this.hit) { 
  18.                 return
  19.             } 
  20.             Memory.writeU32(this.dest_addr.add(...), ...); 
  21.             .... 
  22.         }, 
  23.         onEnter : function (args) { 
  24.             var shaderType = Memory.readU8(args[1].add(2)); 
  25.             if (!this.returnAddress.compare(setShader_return)) { 
  26.                 if (shaderType != 1) { return; } 
  27.                 this.dest_addr = args[0]; 
  28.                 this.src_addr = args[1]; 
  29.                 this.len = args[2].toInt32(); 
  30.                 this.hit = 1; 
  31.             ... 
  32.     }); 

上面的代碼使用了Frida的劫持了vm3dum64_10中的memmove()的控制流。每當(dāng)代碼進(jìn)入memmove()時(shí),返回值和setShader()進(jìn)行比較。相同的話(huà),就在退出memmove()前修改內(nèi)存中的字節(jié)碼。

在我們的研究過(guò)程中,值得注意的是,我們了解到Marco Grassi和Peter Hlavaty展示過(guò)渲染器的fuzzing。其中提到VMware提供了一個(gè)渲染器的工具包和一些實(shí)例。這就是他們進(jìn)行fuzzing的基礎(chǔ),他們的研究成果可以在這里找到。

尋找漏洞

VMware是一個(gè)巨大的軟件,我們不知道如何從vmware-vmx中識(shí)別出渲染器的翻譯函數(shù)。只有兩種途徑:一種是直接識(shí)別渲染器的翻譯單元。第二種是通過(guò)SVGA3D命令處理函數(shù),通常是下面幾種:DXDDefine,DXBindShader,DefineSurface。

二進(jìn)制文件中查找字符串是相對(duì)簡(jiǎn)單的,下圖就是SVGA3d命令中使用的字符串。

用這些字符串并不直接找到對(duì)應(yīng)的處理函數(shù),但是,通過(guò)X引用可以找到內(nèi)存中另一張表。

用字符串表中的偏移把他們標(biāo)注出來(lái),就能找到直接的處理函數(shù)。由于它們最終用來(lái)控制渲染器的操作,跟著這些函數(shù)就能找到解析和翻譯的代碼。在內(nèi)部的實(shí)現(xiàn)中,內(nèi)核驅(qū)動(dòng)和vmware-vmx是以先進(jìn)先出的數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)的,用來(lái)把SVGA3D命令壓入堆中傳遞給監(jiān)管器。然后這些模塊取出數(shù)據(jù)并進(jìn)一步處理。

有兩種辦法能直接找到渲染器的代碼。第一種,使用vmware-vmx-debug中的字符串,能直接找到解析和翻譯的代碼。我們開(kāi)始跟隨了字符串“shaderParseSM4.c”和“shaderTransSM4.c”的交叉引用。但是審計(jì)debug版本的代碼漏洞有一個(gè)巨大的缺陷,debug版本有很多檢查函數(shù),這在發(fā)行版中是沒(méi)有的。

我們不清楚這是不是VMware設(shè)計(jì)上的缺陷,在審計(jì)vmware-vmx的代碼的過(guò)程中。在debug版本中,解析模塊和翻譯模塊中有著大量的嚴(yán)格的安全檢查。在發(fā)行版本中就沒(méi)有。

于是,我們利用在debug版本中搜索到的立即數(shù)參數(shù)來(lái)在非debug版本中定位,這大大的增強(qiáng)了IDA代碼的可讀性。多虧了mesa驅(qū)動(dòng)程序的幫助,我們才能知道我們需要搜索的是什么。

比如,mesa驅(qū)動(dòng)程序中關(guān)于VGPU10的定義對(duì)我們的分析有著很大的幫助。

當(dāng)vmware-vmx需要把虛擬機(jī)的渲染器代碼轉(zhuǎn)化為主機(jī)的渲染器代碼,它會(huì)首先解析虛擬機(jī)內(nèi)部庫(kù)函數(shù)打包好的渲染器字節(jié)碼。由于缺少底層的渲染器字節(jié)碼的資料,逆向這個(gè)解析函數(shù),并且構(gòu)造各種輸入,花費(fèi)了我們大量的時(shí)間。

最初的解析過(guò)程比較簡(jiǎn)單,ParserSM4()函數(shù)只是保存了參數(shù)。

parser解析字節(jié)碼時(shí),和其他的parser相似。渲染器代碼的長(zhǎng)度告訴parser應(yīng)該何時(shí)停止解析。每個(gè)字節(jié)碼都有一個(gè)種類(lèi),一個(gè)指令長(zhǎng)度,和一個(gè)值。具體的說(shuō),每個(gè)字節(jié)碼頭部的0:10位確定字節(jié)碼的種類(lèi),11:23位來(lái)編碼字節(jié)碼的數(shù)據(jù),30:24位來(lái)記錄字節(jié)碼的數(shù)據(jù)長(zhǎng)度,第31位記錄字節(jié)碼是否擴(kuò)展(通常情況下沒(méi)有)

由于大部分的字節(jié)碼包括的值都是一個(gè)字節(jié)長(zhǎng)度,parser都是把這個(gè)字節(jié)的值復(fù)制到未知的數(shù)據(jù)結(jié)構(gòu)中,上圖中的VGPU10_OPCODE_CUSTOMDATA是一個(gè)例外。因?yàn)樗艘粋€(gè)緩沖區(qū),dcl_immediateConstantBuffer有描述。

就像上面提到的,我們并不清楚內(nèi)部使用的數(shù)據(jù)結(jié)構(gòu)。但是,這對(duì)尋找翻譯單元中的漏洞無(wú)關(guān)緊要,因?yàn)閿?shù)據(jù)結(jié)構(gòu)中使用的偏移是一樣的。因此,如果我們知道了輸入的字節(jié)碼是什么,再來(lái)審計(jì)TransSM4的二進(jìn)制代碼就很方便了。

總體來(lái)說(shuō),這還是一個(gè)很耗費(fèi)時(shí)間的步驟。第一,我們開(kāi)始不了解渲染器和VMware的圖形接口虛擬化的知識(shí),尋找關(guān)鍵點(diǎn)就花了不少時(shí)間。第二,缺少直接生成sm4字節(jié)碼的工具,我們只能用Frida來(lái)動(dòng)態(tài)hook函數(shù)中的字節(jié)碼。

最后,了解SM4指令的細(xì)節(jié)和原理也是個(gè)巨大的工程。除了調(diào)試器外,還有一些能幫助我們進(jìn)行逆向工程的。vmware-vmx的debug版本中的ASSERT斷言能幫我們了解運(yùn)行錯(cuò)誤。

ParseSM4()函數(shù)提供了一個(gè)渲染器的反匯編函數(shù),能夠用來(lái)提取渲染器字節(jié)碼,記錄在VMware的log日志中。

成果

現(xiàn)在我們來(lái)看看在人工逆向后我們發(fā)現(xiàn)的一些成果,2017年3月17號(hào),在Pwn2Own,我們把這些漏洞和Poc提交給了ZDI。

1、翻譯dcl_immediateConstantBuffer字節(jié)碼時(shí)存在堆溢出

解析一個(gè)名為 VGPU10_OPCODE_CUSTOMDATA 的 token時(shí)(定義了一個(gè)緩沖區(qū)),執(zhí)行了下面的偽代碼:

  1. case VGPU10_OPCODE_CUSTOMDATA: 
  2.   v41 = v23 >> 11; 
  3.   *(_DWORD *)(_out_p_16_ptr + op_idx + 16) = v41; 
  4.   if ( (_DWORD)v41 == VGPU10_CUSTOMDATA_DCL_IMMEDIATE_CONSTANT_BUFFER ) 
  5.   { 
  6.     *(_DWORD *)(_out_p_16_ptr + op_idx + 32) = insn_l; 
  7.     custom_data_alloc = (void *)mksMemMgr_alloc(v41, 0x10009u, 4LL * (unsigned int)insn_l);// int overflow safe 
  8.     *(_QWORD *)(_out_p_16_ptr + op_idx + 24) = custom_data_alloc; 
  9.     memcpy(custom_data_alloc, bc_tmp_ptr, 4LL * *(unsigned int *)(_out_p_16_ptr + op_idx + 32)); 
  10.     v37 = 0; 
  11.     insn_start = (int *)bc_tmp_ptr; 
  12.   } 

這時(shí)insn_l表示一個(gè)在用戶(hù)數(shù)據(jù)指令中編碼的32位的常數(shù),一般渲染器指令不會(huì)用到32位長(zhǎng)度的值,所以這是一個(gè)比較特殊的情況。這個(gè)數(shù)表示了用戶(hù)數(shù)據(jù)塊長(zhǎng)度。代碼中沒(méi)有對(duì)這個(gè)長(zhǎng)度做任何限制。

mksMemMgr_alloc在內(nèi)部調(diào)用了calloc,分配了一個(gè)長(zhǎng)度為159384的堆。calloc函數(shù)是由msvcr90.dll提供的。我們發(fā)現(xiàn)msvcr90.dll總是被映射到4G內(nèi)存的最底端。

Windows 10上的calloc函數(shù)通過(guò)RtlAllocateHeap在NT堆中分配內(nèi)存。我們會(huì)在outbuf中使用這塊內(nèi)存,這塊內(nèi)存是完全被攻擊者控制的。

分配完這塊內(nèi)存后,翻譯階段就結(jié)束了。遇到VGPU10_OPCODE_COSTOMDATA這個(gè)token。memcpy會(huì)被調(diào)用,而沒(méi)有經(jīng)過(guò)進(jìn)一步的安全檢查。

  1. result = memcpy(outbuf + 106228, custom_data_alloc, 4 * len); 

custom_data_alloc是我們?cè)谏厦娴膒arsing步驟中分配的緩沖區(qū)。這使我們能夠把精心設(shè)計(jì)好的數(shù)據(jù)寫(xiě)入到相鄰堆塊的頭部中。這些相鄰的堆塊是之前解析過(guò)的字節(jié)碼,它們也被分配這一個(gè)內(nèi)存區(qū)域。

2、翻譯dcl_indexableTemp字節(jié)碼時(shí)存在堆越界寫(xiě)入漏洞

在處理dcl_indexabletemp指令時(shí),渲染器解析模塊會(huì)調(diào)用下面的偽代碼

  1. case VGPU10_OPCODE_DCL_INDEXABLE_TEMP: 
  2.   *(_DWORD *)(_out_p_16_ptr + op_idx + 16) = *insn_start;// index 
  3.   *(_DWORD *)(_out_p_16_ptr + op_idx + 20) = insn_start[1];// index + value for array write operation in Trans 
  4.   bc_tmp_ptr = insn_start + 3; 
  5.   *(_DWORD *)(_out_p_16_ptr + op_idx + 24) = insn_start[2]; 

在上面的偽代碼中,指令的一部分被寫(xiě)到了op_idx中,這些值會(huì)在后面的翻譯模塊中用到。在解析過(guò)程中,沒(méi)有對(duì)這些值的任何限制。

下面的代碼表示了翻譯過(guò)程

  1. case VGPU10_OPCODE_DCL_INDEXABLE_TEMP: 
  2.     v87 = *(_DWORD *)(bytecode_ptr + op_idx + 24); 
  3.   
  4.     svga3d_dcl_indexable_temp((__int64)__out, 
  5.     *(_DWORD *)(bytecode_ptr + op_idx + 16),// idx 
  6.     *(_DWORD *)(bytecode_ptr + op_idx + 20),// val 
  7.     (1 << v87) - 1);                        // val2 

我們可以看到,在調(diào)用svga3d_dcl_indexable_temp()時(shí),使用了相同的偏移值(20,16,24)。idx和val是被攻擊者直接控制的。第4個(gè)參數(shù)是由上面的第三個(gè)雙字運(yùn)算得出((1<<val2)-1)

進(jìn)入svga3d_dcl_indexable_temp()函數(shù)

  1. __int64 __fastcall svga3d_dcl_indexable_temp(__int64 a1, unsigned int idx, int val, char val2) 
  2.   __int64 result; // rax@5 
  3.   const char *v5; // rcx@7 
  4.   const char *v6; // rsi@7 
  5.   signed __int64 v7; // rdx@7 
  6.   *(_DWORD *)(a1 + 8LL * idx + 0x1ED80) = val; 
  7.   *(_BYTE *)(a1 + 8LL * idx + 0x1ED84) = val2; 
  8.   *(_BYTE *)(a1 + 8LL * idx + 0x1ED85) = 1; 
  9.   result = idx; 
  10.   return result; 

在上面的代碼中,a1是翻譯過(guò)程中使用的堆塊,和我們前面討論過(guò)的用戶(hù)數(shù)據(jù)塊是一樣的。以0x1ed80為基址,我們可以向任意偏移寫(xiě)入一個(gè)32位的dword值。

綜上,這個(gè)漏洞能讓我們?cè)谙惹疤岬降亩呀Y(jié)構(gòu)中向任意地址寫(xiě)入一個(gè)雙字值。還能夠?qū)懭雰蓚€(gè)字節(jié),由val來(lái)控制(剩下的兩個(gè)字節(jié)為0)。

3、翻譯dcl_resource字節(jié)碼時(shí)存在棧越界寫(xiě)入漏洞

翻譯過(guò)程中處理dcl_resource指令時(shí),下述代碼會(huì)被執(zhí)行:

  1. int hitme[128]; // [rsp+1620h] [rbp-258h]@196 
  2.  int v144; // [rsp+1820h] [rbp-58h]@204 
  3.  char v145; // [rsp+1824h] [rbp-54h]@303 
  4.  bool v146; // [rsp+1830h] [rbp-48h]@14 
  5.  char v147; // [rsp+1831h] [rbp-47h]@14 
  6.  int v148; // [rsp+1880h] [rbp+8h]@1 
  7.  __int64 v149; // [rsp+1890h] [rbp+18h]@1 
  8.  __int64 v150; // [rsp+1898h] [rbp+20h]@14 
  9.  ... 
  10.      case VGPU10_OPCODE_DCL_RESOURCE: 
  11.   
  12.        v87 = sub_1403C2200(*(_DWORD *)(v14 + 32)); 
  13.        v88 = sub_1403C2200(*(_DWORD *)(v14 + 28)); 
  14.        v89 = sub_1403C2200(*(_DWORD *)(v14 + 24)); 
  15.        v90 = sub_1403C2200(*(_DWORD *)(v14 + 20)); 
  16.        sub_1402FCF10(&v107, (__int64)outptr, *(_DWORD *)(v14 + 80), v86, v90, v89, v88, v87); 
  17.        v11 = 0i64; 
  18.        hitme[(unsigned __int64)*(unsigned int *)(v14 + 80)] = *(_DWORD *)(v14 + 16); 

我們沒(méi)有跟入研究sub_1403c2200()函數(shù)的細(xì)節(jié),這個(gè)函數(shù)無(wú)關(guān)緊要,因?yàn)樗鼘?duì)棧的結(jié)構(gòu)沒(méi)有影響。偏移(v14+80)又是完全受輸入的渲染器字節(jié)碼控制的。但是被寫(xiě)入的值是受到一定的限制。只能是0-31。

這意味著我們可以寫(xiě)入很多對(duì)齊的雙字。這里我們用了復(fù)數(shù)形式,因?yàn)檫@個(gè)漏洞可以被觸發(fā)多次,向hitme開(kāi)始到4G的地址寫(xiě)入0-31。

這個(gè)漏洞的可利用性跟VMware的版本和操作系統(tǒng)有關(guān)。很明顯,在不同的版本或操作系統(tǒng)中,棧的布局是不一樣的。

4、不安全的內(nèi)存映射導(dǎo)致繞過(guò)DEP

在vmware-vmx監(jiān)管進(jìn)程啟動(dòng)時(shí),創(chuàng)建了一些內(nèi)存映射。令人驚訝的時(shí),其中一塊內(nèi)存映射是以讀,寫(xiě),可執(zhí)行的權(quán)限創(chuàng)建的。在整個(gè)進(jìn)程的生命周期中都是如此。這樣的內(nèi)存映射只有一塊。這里創(chuàng)建的內(nèi)存映射是vmware-vmx進(jìn)程data區(qū)段的第一個(gè)頁(yè)。

  1. 7ff7`36b53000  7ff7`36b54000  0`00001000 MEM_IMAGE  MEM_COMMIT  PAGE_EXECUTE_READWRITE   Image [vmware_vmx; "C:\Program Files (x86)\VMware\VMware Workstation\x64\vmware-vmx.exe"
  2.   
  3. 0:018> dq 7ff7`36b53000 L 0n1000/8 
  4. 00007ff7`36b53000  ffffffff`ffffffff 00000001`fffffffe 
  5. 00007ff7`36b53010  00009f56`1b68b8ce ffff60a9`e4974731 
  6. 00007ff7`36b53020  00007ff7`36780a18 00007ff7`36780a08 
  7. 00007ff7`36b53030  00007ff7`367809f8 00007ff7`367809e8 
  8. 00007ff7`36b53040  00007ff7`367809d8 00000000`00000000 
  9. 00007ff7`36b53050  00007ff7`36780990 00007ff7`36780940 
  10. 00007ff7`36b53060  00007ff7`367808f0 00007ff7`367808a0 
  11. 00007ff7`36b53070  00007ff7`36780860 00007ff7`36780820 
  12. 00007ff7`36b53080  00007ff7`367807f0 00007ff7`367807a0 
  13. 00007ff7`36b53090  00007ff7`36780750 00007ff7`36780700 

顯然,這大大的降低了虛擬機(jī)逃逸的漏洞,因?yàn)樗峁┝艘粋€(gè)完美的執(zhí)行shellcode的區(qū)域。

  1. data:0000000140B33000 _data           segment para public 'DATA' use64 
  2. ... 
  3. 0000000140B33000  FF FF FF FF FF FF FF FF  FE FF FF FF 01 00 00 00  ................ 
  4. 0000000140B33010  32 A2 DF 2D 99 2B 00 00  CD 5D 20 D2 66 D4 FF FF  2..-.+...] .f... 
  5. 0000000140B33020  18 0A 76 40 01 00 00 00  08 0A 76 40 01 00 00 00  ..v@......v@.... 
  6. 0000000140B33030  F8 09 76 40 01 00 00 00  E8 09 76 40 01 00 00 00  ..v@......v@.... 
  7. 0000000140B33040  D8 09 76 40 01 00 00 00  00 00 00 00 00 00 00 00  ..v@............ 
  8. 0000000140B33050  90 09 76 40 01 00 00 00  40 09 76 40 01 00 00 00  ..v@....@.v@.... 
  9. 0000000140B33060  F0 08 76 40 01 00 00 00  A0 08 76 40 01 00 00 00  ..v@......v@.... 
  10. 0000000140B33070  60 08 76 40 01 00 00 00  20 08 76 40 01 00 00 00  `.v@.... .v@.... 
  11. 0000000140B33080  F0 07 76 40 01 00 00 00  A0 07 76 40 01 00 00 00  ..v@......v@.... 
  12. 0000000140B33090  50 07 76 40 01 00 00 00  00 07 76 40 01 00 00 00  P.v@......v@.... 

如圖所示,內(nèi)存是以讀,寫(xiě),可執(zhí)行的方式分配的。Windbg中的dump只是想說(shuō)明它是和IDA中的data區(qū)段是相符的。

總結(jié)

前兩個(gè)漏洞是12.5.3版本中的0day漏洞,即使在比賽后,12.5.4版本還沒(méi)有修復(fù)這些漏洞。

在12.5.4版本發(fā)布后不久,VMWare又發(fā)布了VMSA-2017-0006修補(bǔ)了這兩個(gè)堆相關(guān)的漏洞。版本更新中的細(xì)節(jié)描述很模糊,我們并不知道這些漏洞是否被真正修補(bǔ)上了。

同樣的,vmware-vmx的調(diào)試版本有著產(chǎn)品版本中沒(méi)有的錯(cuò)誤檢查機(jī)制。根據(jù)ZDI的說(shuō)法,這和其他人提交的漏洞并不沖突,VMSA-2017-006只提及了ZDI的報(bào)告。

結(jié)果就是,我們不知道這些漏洞有沒(méi)有CVE ID,有沒(méi)有其他的研究員發(fā)現(xiàn)了這些漏洞。

值得注意的是,ASSERT斷言同樣影響了其他的SM4指令。我們確信,直到12.5.5版本,至少dcl_indexRange和dcl_constantBuffer有著相似的堆越界寫(xiě)入漏洞。

dcl_resource漏洞在12.5.5版本中沒(méi)有被修補(bǔ)。

目前我們認(rèn)為最初補(bǔ)丁是針對(duì)內(nèi)部代碼的重構(gòu),而不是針對(duì)我們提交的漏洞的。因?yàn)樵赿ebug版本中的修補(bǔ)和發(fā)行版一樣。使用了assert斷言而不是錯(cuò)誤處理函數(shù)。因此,我們依舊可以用這些漏洞來(lái)攻破VMware。

文中涉及的漏洞的PoC可以在https://github.com/comsecuris/vgpu_shader_pocs上找到。

其他

在這篇文章結(jié)束之前,我們還想說(shuō)說(shuō)我們工作中的一些發(fā)現(xiàn),希望對(duì)你們有幫助。有以下幾點(diǎn):

不同環(huán)境下逆向工程的難度

當(dāng)我們逆向分析vmware-vmx時(shí),Linux版本中一些奇怪的內(nèi)嵌函數(shù)特性使得逆向的難度大大提高(相比Windows和Mac)。比較后,我們發(fā)現(xiàn)竟然是Windows中的vwmare-vmx最適合逆向分析。

Linux版本中vmware-vmx的符號(hào)信息對(duì)逆向幫助很大。

設(shè)置

VMware為和渲染器的交互功能提供了很有用的設(shè)置選項(xiàng)。我們發(fā)現(xiàn)了mks.dx11.dumpShaders,mks.shim.dumpShaders和mks.gl.dumpShaders很有用。類(lèi)似的設(shè)置還有很多。

PIE

在linux中,如果去掉vmware-vmx ELF文件中的PIE選項(xiàng),vmware-vmx就不能正常工作了。在Mac中,使用change_macho_flage.py腳本可以成功處理vmware-vmx的重定位。這會(huì)讓調(diào)試變得更加方便。

二進(jìn)制翻譯模塊

完成上述的分析后,我們還在思考vmware-vmx中模擬x86指令的代碼在哪里。我們開(kāi)始認(rèn)為會(huì)很容易發(fā)現(xiàn)這部分代碼,然而,到目前為止,我們還找到相關(guān)的代碼。一種可能是硬件的虛擬化。然而,根據(jù)設(shè)置和架構(gòu),VMware是可以運(yùn)行在多種模式下的。這部分代碼肯定在某個(gè)位置。

  1. binwalk vmware-vmx.exe 
  2.   
  3. DECIMAL       HEXADECIMAL     DESCRIPTION 
  4. -------------------------------------------------------------------------------- 
  5. 0             0x0             Microsoft executable, portable (PE) 
  6. ... 
  7. 13126548      0xC84B94        ELF, 64-bit LSB relocatable, AMD x86-64, version 1 (SYSV) 
  8. 13126612      0xC84BD4        ELF, 64-bit LSB relocatable, AMD x86-64, version 1 (SYSV) 
  9. 14073118      0xD6BD1E        Unix path: /build/mts/release/bora-4638234/bora/vmcore/lock/semaVMM.c 
  10. 14256073      0xD987C9        Sega MegaDrive/Genesis raw ROM dump, Name"tSBASE""E_TABLE_VA"
  11. 14283364      0xD9F264        Sega MegaDrive/Genesis raw ROM dump, Name"ncCRC32B64""FromMPN"
  12. 14942628      0xE401A4        ELF, 64-bit LSB relocatable, AMD x86-64, version 1 (SYSV) 
  13. 14949876      0xE41DF4        ELF, 64-bit LSB relocatable, AMD x86-64, version 1 (SYSV) 
  14. 14954108      0xE42E7C        ELF, 64-bit LSB relocatable, AMD x86-64, version 1 (SYSV) 
  15. 14960892      0xE448FC        ELF, 64-bit LSB relocatable, AMD x86-64, version 1 (SYSV) 
  16. 14991124      0xE4BF14        ELF, 64-bit LSB relocatable, AMD x86-64, version 1 (SYSV) 

binwalk分析ELF的結(jié)果看起來(lái)很奇怪,肯定有一些錯(cuò)誤。我們暫時(shí)忽略這些錯(cuò)誤。我們注意到內(nèi)存中有個(gè)ELF頭。使用binwalk工具(通常不會(huì)用binwalk來(lái)分析PE或ELF文件),我們發(fā)現(xiàn)了一些有趣的事情。

一個(gè)最大ELF文件看起來(lái)很有意思,因?yàn)樗艘粋€(gè)巨大的函數(shù),更重要的事,它還帶有符號(hào)。

出乎我們的意料,這個(gè)內(nèi)嵌的ELF帶有x86反匯編的翻譯單元。我們對(duì)他的工作方式很好奇,但我們并沒(méi)有深入研究,畢竟這不是我們的目標(biāo),但這是一個(gè)很有趣的研究方向。

結(jié)語(yǔ)

很遺憾,在Pwn2Own上,我們沒(méi)能完成最初設(shè)定好的目標(biāo),實(shí)現(xiàn)完整的虛擬機(jī)逃逸。但是,能在我們計(jì)劃的時(shí)間內(nèi)完成,我們還是很滿(mǎn)意的。我們相信VMware不僅是一個(gè)漏洞挖掘的有趣的目標(biāo),而且VMware雖然實(shí)現(xiàn)了虛擬機(jī)的監(jiān)視功能,它與傳統(tǒng)的桌面程序差別并不大。

基于我們對(duì)攻擊點(diǎn)的發(fā)掘和探測(cè),我們相信VMware作為一個(gè)高度復(fù)雜且被廣泛使用的軟件,其中還有很多沒(méi)被挖掘利用的攻擊點(diǎn)。例如,我們僅僅分析了渲染器翻譯單元的表面結(jié)構(gòu)。

渲染器功能的內(nèi)部的復(fù)雜實(shí)現(xiàn)還有待分析。與此類(lèi)似,VMware的其他組件也被攻擊過(guò)。看完我們分析完的代碼和過(guò)去VMware提出的安全建議,最近的安全防御由被動(dòng)變成了主動(dòng)。

除了核心組件之外,還有很多值得研究的組件。比如vmware-hostd(支持SSL的web服務(wù)器)。我們希望能進(jìn)一步研究虛擬機(jī)的安全問(wèn)題,也歡迎其他人也來(lái)研究。

責(zé)任編輯:武曉燕 來(lái)源: 看雪社區(qū)
相關(guān)推薦

2009-07-16 10:11:06

渲染器RendererSwing組件

2009-07-16 10:26:49

渲染器接口Swing

2010-08-13 11:02:27

Flex渲染器

2009-07-15 13:48:26

Swing模型和渲染器

2014-06-18 10:34:41

Android字體渲染器OpenGL ES

2009-10-12 14:12:40

VMware Work

2009-08-21 17:20:09

VMware Work

2022-04-18 08:09:44

渲染器DOM掛載Vue.js

2012-12-20 09:57:14

VMwareWorkstation

2010-08-13 11:21:31

Flex渲染器

2011-09-20 09:48:52

虛擬化VMware Work

2009-11-04 21:06:06

2009-04-03 13:43:02

Vmware虛擬機(jī)Nehalem

2009-08-13 10:24:10

VMware WorkLinux系統(tǒng)虛擬機(jī)

2009-09-07 08:10:56

VMware Work

2012-12-12 16:07:46

VMwareWorkstation

2011-11-15 10:59:33

虛擬化VMware WorkGUI

2022-04-07 18:51:29

VMware漏洞網(wǎng)絡(luò)攻擊

2009-09-03 13:53:03

VMware WorkRHEL 5紅帽

2010-05-31 15:02:29

VMWare Work
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)