作者:0xcc
原文鏈接:https://mp.weixin.qq.com/s/TrSb4hMD6QUVyCth3IaBbg

這篇文章是上一次 realworld ctf 論壇上的議題《Bifr?st 揭秘:VMware Fusion REST API 漏洞分析》。本來去年這時候就該動筆寫一下,正好當時 InfiltrateCon 的主辦方看到了這個議題,邀請了投稿,我就想著講完再寫。沒料到四月份的會議因為疫情一直拖到現在,最后只能改成線上。

http://infiltratecon.com/conference/briefings/bifrost-demystified-case-study-of-a-vmware-fusion-rce.html

VMware Fusion 在去五月修復了這個編號為 CVE-2019-5514 漏洞。與常規的虛擬機安全問題,即通過 guest 攻擊 host 的方式不同,這是一個遠程代碼執行漏洞。它從 host 的瀏覽器遠程觸發,在 guest 里執行任意代碼。PoC 極度簡單,卻需要花不少功夫逆向才能分析明白。

圖片

除此之外我還(重新)發現了一種特殊配置下,不需要漏洞即可逃逸至 host 執行任意命令的方法。RWCTF 舉辦時還在和廠商溝通,所以我保留了這一部分沒講。這兩部分串聯起來之后,便是一個完整的 RCE 鏈條。 VM Fusion 11 引入了一個新功能,在 mac 桌面右上角添加了一個快捷菜單,可以操作虛擬機的開關機、快照等狀態。當 guest 是 Windows 系統時,甚至可以將其“開始”菜單映射出來,在客戶機里直接運行(任意?)程序。

這個功能引起了我的注意,事實上也找到了嚴重的問題。

經過簡單的分析發現,這個菜單界面是一個 Electron 應用。而在后臺有一個 go 語言 amsrv 進程開啟了一個 HTTP 服務,通過 WebSocket 和 HTTP 協議與 Electron 界面通信,然后再由 amsrv 作為代理的角色操縱 VMware Fusion 剩余的組件。這個 http 服務的架構有些多余,畢竟 Electron 本身可以實現很多 native 的功能。筆者估計是因為 nodejs 嵌入 C 的庫比 go 麻煩。

圖片

問題出在 HTTP 和 WebSocket 的鑒權上。開發者應該是認為 localhost 的應用沒有做訪問控制的必要,然而 WebSocket 默認支持跨域訪問,也就是任何一個瀏覽器都可以與之通信。更神奇的是 HTTP 協議的部分還開啟了 CORS,不限制請求來源。簡單復現一下彈計算器的命令,然后在 Wireshark 對 loopback 抓包,便得到了一個 PoC:

const ws = new WebSocket(`ws://127.0.0.1:8698/ws`)
ws.onopen = () => {
  ws.send(JSON.stringify({
    name: 'menu.onAction',
    object: '11 22 33 44 55 66 77 88-99 aa bb cc dd ee ff 00',
    userInfo: {
      action: 'launchGuestApp:',
      vmUUID: '11 22 33 44 55 66 77 88-99 aa bb cc dd ee ff 00',
      representedObject: 'calculator:'
    }
  }))
}
ws.onmessage = msg => {
  console.log(JSON.parse(msg.data))
  ws.close()
}

顯然,其中的 vmUUID 字段是虛擬機的唯一標識符。但經過一番分析發現,這個字段保存在本地的一個 plist 文件里,Electron 通過解析對應的文件獲取,而遠程攻擊者自然沒有這個條件。這個格式也不能被簡單的爆破。這個漏洞似乎不能利用,加上我一開始對逆向 go 沒有耐心,于是就在網上公開了。

然而一段時間過后,我突然收到一條國外網友的私信說,他找到了利用的方法,讓我非常震驚。

圖片

https://theevilbit.github.io/posts/vmware_fusion_11_guest_vm_rce_cve-2019-5514/

他在 WebSocket 協議里找到了一個隱藏的參數 selectedIndex,可以完全取代 vmUUID。這個整型的參數可以遍歷,有微博網友稱,測試時把自己所有的虛擬機全部打開挨個彈了一遍 cmd,當場大驚失色。

這件事說明,為了負責任地披露,在完全搞清楚一個漏洞的可利用性之前,不要隨便地公開討論。

這也勾起了我的好奇心,于是我把手上的 binary 又打開梳理了一遍。

Redress 工具簡單查看了一下 amsrv,其實這個程序并不是真正的服務端,而是一個類似守護進程的角色。服務端實現是在另一個叫 vmrest 的程序。在 VMware 官網上可以找到這個 vmrest 的文檔,標題叫《Use the VMware Workstation Pro REST API Service》。但這個程序的幫助信息里卻提示有一個 -D 的命令開關可以以 internal 模式運行,說明事情沒這么簡單。

Redress 提示這個程序用到了 web 框架 gorilla。以此為線索搜索 github_com_gorilla_mux__Router_HandleFunc 的交叉引用,找到了所有的后端 API 接口:

圖片

WebSocket 后端的處理非常簡單,在對 JSON 內容進行一些解碼和重新序列化的操作和,幾乎遠洋通過 Mach Message 轉發給下一個進程,也就是 VMware Fusion 主界面。我寫了一端簡單的 frida 腳本攔截 CFMessagePortSendRequest 函數調用,打印所有的進程間消息,也證實了這一點。

這一階段的進程間通信主要靠 VMIPCServer 和 VMIPCClient 類實現。顧名思義,這一對 class 借鑒了 client/server 的角色,封裝了基于消息的接口。在消息接收端有一個 VMIPCCommon 單例,其中的 observerTable 注冊了所有的消息接收端。這是一個 NSDictionary 鍵值對,key 是指向具體 handler 類實例的指針,值則是一個 VMIPCObserverEntry 對象,記錄了 WebSocket 協議當中的 name 字段和具體 handler 類處理方法的 selector 的對應關系:

圖片

回到彈計算器的 PoC 上。根據 observerTable 的映射關系,這個消息會觸發 -[PLVMStartMenuProxy onMenuAction:] 方法。最終消息來到 -[PLVMStartMenuManager onStartMenuPerformAction:withInfo:],在這個函數里居然是優先檢查 selectedIndex 參數,如果不存在,再嘗試將另一個可選的 vmUUID 參數轉換成 selectedIndex。這也就解釋了一開始被我漏掉的 PoC 的現象。而為了搞清楚這一步,我們已經逆了至少三個程序。

@interface DUIVMActionController : DUIActionController <DUISettingsCDROMOpenPanelDelegate>
- (void)togglePause:(id)arg1;
- (void)installVirtualPrinter:(id)arg1;
- (void)toggleToolsInstall:(id)arg1;
- (void)onSendKey:(id)arg1;
- (void)sendCtrlAltDel:(id)arg1;
...

除了啟動客戶機程序之外,以上的方法也是對 WebSocket 開放的。

接下來便是主界面和 vmx 進程的通信。VMware Fusion 的每一個虛擬機都用一個獨立的 vmx 進程執行,即使界面崩潰了,也不會影響到 vmx 的穩定性;反之亦然。

這個階段的通信使用一個叫 vmdb 的機制。

這是一個類似鍵值對數據庫的集中化狀態管理,既支持數據的存儲也提供跨進程傳遞數據的能力。一個 key 類似文件系統的路徑,類似這樣的字符串:

vmx/vigor/ields/Audio/

vmdb 支持的基本數據類型有整形、字符串、二進制等。既然叫做 db,它還提供了類似 SQL 的查詢機制,但實際上只支持 SELECT WHERE 語句。首先用 Vmdb_ParseQuery 從“SQL”創建一個查詢,接著用 Vmdb_ExecuteQuery 函數執行,并用 Vmdb_NextResult 遍歷結果集。這個 db 還支持事件處理,可以用 Vmdb_RegisterCallback 在特定的鍵上添加監聽函數處理狀態變化。

與常見的虛擬機漏洞不同,這一次攻擊載荷是反向傳遞的——從 host 到 guest。常規的漏洞利用一個叫 RPCI 的“后門”通信接口來調用宿主的功能,而與之對等的是 TCLO。兩者其實區別不大,僅僅是 Message_Open 時傳入的 magic number 不同。命令的格式也是函數名、空格,然后緊跟參數的 buffer。

在 Windows 上,VMware Tools 有兩個進程,一個具有 SYSTEM 權限,一個普通用戶權限。用來彈計算器的命令叫做 unity.shell.open,最后來到 GHIPlatformShellCommandRun 函數。

這個函數并不完全等同于 ShellExecute,它還內置了一些特殊 URL 的處理。

  • x-vmware-share:// 打開共享目錄
  • x-vmware-menuitem://{computer,documents,network,control-panel,printers,search,run} 開始菜單
  • x-vmware-metroapp-execpath:// 執行 UWP 應用

如果字符串不滿足以上 URL,就會進入這個分支。只有命令包含一個“.”符號,才會觸發支持命令行參數的邏輯:

圖片

比如 cmd /c calc 必須寫成 cmd.exe /c calc,否則沒有反應。這時候可以使用 Powershell 下載逃逸的 payload 完成整個鏈路。

對于非 Windows 虛擬機,例如 Linux,unity.shell.open 早在 2008 年的一個 commit 便被移除掉了。不過前文提到,有一個命令可以模擬鍵盤輸入,而且這個命令并不需要客戶機上安裝了 VMTools。這就是 onSendKey: 方法。在 guest 沒有被鎖屏的情況下,仍然可以通過模擬按鍵的方式打開終端,回車執行任意命令。

官方在 2019 年五月初推出的 11.0.3 修復了這個問題,在 HTTP 協議中加入了隨機 token 的驗證;而 WebSocket 則要求 Origin: 滿足 file:// 域。

在 VMware 的安全公告 VMSA-2019-0005 當中, 除了這個嚴重級別的遠程代碼執行,還有 Pwn2Own 2019 上 Fluoroacetate 用到的幾個 VMware Workstation 逃逸漏洞,同樣影響 Fusion。

此外在逆向 VMTools 時,我重新發現了一個已經被公開討論過的特性,可以在特殊的虛擬機配置環境下無需漏洞逃逸到宿主機。

圖片

一旦勾選了這個“在 Mac 打開 Windows 的文件和鏈接”,便可使用 VMTool 內置的 VMwareHostOpen.exe 調用這一功能。這個選項顯然極大削弱了 guest 和宿主之間的隔離性。經過一番搜索我發現 ZDI 在 2017 年已經在 DerbyCon 上公開講過,只不過沒有分析實現細節。

這個命令會轉化成一條 RPCI 命令 ghi.guest.shell.action,參數為序列化的 xdr_GHIShellAction。它一共有兩個成員,actionURI 永遠是 x-vmware-action:///run,而 targetURI 則是希望打開的地址。

在這個函數里特別針對 file:/// 做了過濾,不做任何操作,有可能是為了安全考慮。但其他任意的 URL,例如 dict:// 是允許的。當 URL 的 sheme 是 x-vmware-share:// 時,會轉換為宿主的地址,然后打開對應文件。

在客戶機開啟了任意一個可寫的共享目錄之后,攻擊載荷可以寫入一個可執行文件(例如 .command),內容是一個 shell 腳本。由于 HGFS 需要盡可能消除不同操作系統下的表現差異,在 mac 端默認便給足文件權限,包括可執行。這時候相當于宿主機雙擊打開文件,便會觸發腳本命令。這便有了我們開頭的動畫。

$name = "calc.command";$writable = ls "\\vmware-host\Shared Folders" | Where-Object { $acl = Get-Acl $_.FullName; $acl.Access | Where-Object { $_.IdentityReference -eq 'Everyone' }} | Select-Object -first 1;
$output = Join-Path $writable.FullName -ChildPath $name;
$content = '#!/bin/sh
open -a Calculator
killall Terminal'
[IO.File]::WriteAllLines($output, $content);
& "C:\Program Files\VMware\VMware Tools\VMwareHostOpen.exe" "--url" "x-vmware-share://$($writable.Name)/$($name)";

VMware 官方認為這不是一個安全問題,畢竟需要兩個條件:

1.允許打開 URL

2.開啟至少一個可寫的共享目錄

然而我們再想一想,這兩個條件都和虛擬機本身的配置有關。仍然有一種場景存在風險,那就是從網上下載一個虛擬機鏡像然后雙擊啟動——所有的配置自然都是攻擊者可控的。

通過這個案例的分析可以看到,炫酷的 Web 技術雖然極大提升了開發效率,卻把本不該出現的安全問題引入到桌面端產品中。VMware 一個看上去很小的功能卻分了很多層次的調用,結構復雜卻能保證架構的清晰。當然最大的教訓還是,在確保分析完全之前不要隨便低估一個漏洞的可利用性。


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