漏洞概述
VMware Tools沒有正確的檢查客戶端請求的授權,導致包含一個本地許可權提升漏洞,可以使虛擬機器中的計算機賬號由非管理員許可權提升到管理員許可權。
影響範圍
Windows:
vm-tools:12.x.y,11.x.y 和10.x.y
Linux:
open-vm-tools:12.x.y,11.x.y和10.x.y
vm-tools:10.x.y
復現環境
作業系統:
Win7 sp1 32位作業系統,VMware Tools V11.3.5
分析工具:
IDA、OD、openssl、sigxml、procexp.exe
分析過程
根據官方公告,該提權漏洞是由VMware Tools導致的。VMware Tools是VMware客戶機(guest)中安裝的一套工具,可以提高虛擬機器中安裝的客戶機作業系統效能並改善虛擬機器管理。一般情況下,為了方便虛擬機器中的客戶機和真實主機(host)之間的互動,都會選擇安裝該工具。
既然是提權漏洞,應該和VMware Tools的高許可權程式有關。先使用程式管理工具procexp.exe檢視該工具安裝後的常駐程式,可以看到與VMware相關的程式,有普通程式vmtoolsd.exe,服務程式VGAuthService.exe、vm3dservice.exe和vmtoolsd.exe,其中服務程式均具有高許可權,如下圖所示:
同時,VMware開源了針對Linux系統的open-vm-tools工具的程式碼,可以看到,在補丁檔案open-vm-tools/vgauth/serviceImpl/proto.c中,增加了對公共管道請求的安全檢查,只允許SessionRequest型別的請求透過,初步說明該提權漏洞與請求授權相關。如下圖所示:
根據補丁檔案proto.c程式碼,發現與服務程式VGAuthService.exe相關,該程式的服務名稱為VGAuthService,顯示名稱為VMware Alias Manager and Ticket Service。首先了解下VGAuthService.exe的大致功能,直接執行檢視幫助,該程式的功能是針對VMware的產品,提供SAML令牌和票據身份驗證。vm-tools安裝後,該程式預設被安裝為服務程式,如下圖所示:
使用IDA開啟VGAuthService.exe進行反編譯,然後定位到補丁附近的程式碼。發現補丁程式碼是在一個名為Proto_SecurityCheckRequest(來自開原始碼)的函式內部,該函式負責檢查客戶端請求的安全性。根據請求的型別,分別進行安全檢查,檢查透過後再呼叫對應的處理函式,處理完請求後返回結果,如下圖所示:
那麼究竟是什麼請求導致了提權漏洞?
直接檢視VGAuthService.exe的匯入表和字串,審計是否有提權相關的函式呼叫或者字串。經過查詢,發現許可權相關的系統函式LsaLogonUser和字串“SeTcbPrivilege”,如下圖所示:
LsaLogonUser函式能夠在不需要計算機賬號密碼的情況下,登入指定賬號,登入成功後返回該賬號的令牌(token),當然呼叫該函式的程式需要SeTcbPrivilege許可權,該服務程式也擁有此許可權。這似乎和提權漏洞密切相關,如果能夠控制登入的賬號,用管理員的賬號登入,再建立指定程式,那麼建立的程式將擁有管理員許可權。
遺憾的是,該程式裡並沒有建立程式相關的函式呼叫。參考open-vm-tools的開原始碼以及逆向分析,發現該服務程式會將登入成功後的令牌複製給與自己通訊的程式,如下圖所示:
這似乎給提權又增加了一絲希望,那麼剩下的問題是如何與這個服務程式程式通訊,以及是否能控制LsaLogonUser函式的登入賬號。
首先分析下如何與這個服務程式通訊。可以從程式碼中看到,該程式中使用了管道“\\.\pipe\vgauth-service”進行通訊,並且沒有許可權限制,開原始碼中稱之為公共通道(public channel),與之相反的還有私有通道(private channel)。任何程式均可連線這個公共通道,連線成功後可以傳送資料到該服務程式,也可以收到該服務程式返回的資料,如下圖所示:
那麼接下來分析如何控制LsaLogonUser函式登入的計算機賬號。分析後發現,這個計算機賬號來自於請求的資料中,是可以控制的。這個請求的名字為ValidateSamlBToken,對應的處理函式為ServiceProtoValidateSamlBearerToken。
為了控制LsaLogonUser函式登入的計算機賬號,需要控制傳送的請求資料,也就需要知道請求的資料格式。從處理請求的函式一步步倒著分析,找到讀取和解析請求的函式,如下圖所示:
從字串比較函式中可以看到請求中的合法關鍵字,進一步分析發現,這些關鍵字需要組合成XML格式的請求資料。比如需要呼叫處理函式ServiceProtoValidateSamlBearerToken,請求的資料格式如下:
<?xml version="1.0" encoding="UTF-8" ?>
<request>
<sequenceNumber>【任意數字】</sequenceNumber>
<requestName>ValidateSamlBToken</requestName>
<samlToken>【samlToken資料】</samlToken>
<userName>【計算機使用者賬號】</userName>
<validateOnly>【是否只驗證,不返回令牌】</validateOnly>
</request>
其中request表示包含請求資料,sequenceNumber表示請求的序號,無校驗,可以是任意數字;requestName表示請求的名稱,不同的請求名稱將呼叫不同的處理函式;剩下欄位是請求的引數資訊,不同的請求名稱可能需要不同的引數。示例中的userName表示請求的計算機賬號,也就是可能傳遞給LsaLogonUser函式的賬號;validateOnly表示是否只驗證,不返回Token,比如需要使用認證成功後的令牌,則需要設定該引數為1;samlToken表示認證需要的SAML格式的資料。
如果要獲取到返回的令牌,該認證必須要驗證透過,要想驗證透過則必須要保證SAML資料正確,而且計算機賬號必須是存在的。那麼問題來了,傳遞什麼樣的SAML資料,才能透過這個認證,獲取到返回的令牌資料?
那什麼是SAML?
SAML是安全斷言標記語言(Security Assertion Markup Language),是一個基於XML的開源標準資料格式,用於交換身份驗證和授權資料,經常應用於WEB系統的單點登入功能。詳細的介紹和資料格式等問題讀者可以自行搜尋,這裡主要分析該服務程式驗證需要的一些SAML資料。
驗證SAML資料的相關函式為SAML_VerifyBearerTokenAndChain。在該函式中,先使用函式VerifySAMLToken驗證SAML格式的正確性,然後使用函式ServiceVerifyAndCheckTrustCertChainForSubject對證書和Subject的認證,如下圖所示:
在函式VerifySAMLToken中,驗證SAML格式的正確性。首先要滿足SAML格式要求,比如需要有Subject,Conditions等關鍵字,還要有表示有效時間NotBefore,NotOnOrAfter關鍵字,如下圖所示:
還需要有X509證書以及簽名資料,X509證書可以藉助開源工具openssl生成自簽名的證書,但簽名資料的計算可難住了筆者。在查閱了大量資料和嘗試後,終於使用開源的signxml完成了SAML的簽名計算,透過了該驗證函式。一個有效的SAML資料如下圖所示:
在函式ServiceVerifyAndCheckTrustCertChainForSubject中,會驗證請求的計算機賬號是否存在,存在後,再讀取預設配置情況下的證書儲存檔案C:\ProgramData\VMware\VMware VGAuth\aliasStore\user-【計算機賬號】.xml或者C:\ProgramData\VMware\VMware VGAuth\aliasStore\mapping.xml的內容,然後和請求的x509證書和Subject欄位進行比較,如果相同,則透過驗證;否則驗證失敗,如下圖所示:
如果VerifySAMLToken和ServiceVerifyAndCheckTrustCertChainForSubject均透過了驗證,則進入WinToken_GenerateTokenForUser使用LsaLogonUser登入請求的計算機賬號,最後把登入成功的令牌複製給客戶端程式,並將令牌資料作為請求的回應訊息傳送給客戶端程式,如下圖所示:
到現在為止,已經把可能產生提權漏洞的請求ValidateSamlBToken對應的處理函式ServiceProtoValidateSamlBearerToken分析完畢,是不是就可以利用漏洞了呢?
其實還有一個問題沒有解決,那就是上面提到的儲存x509證書和Subject資料的兩個檔案user-【計算機賬號】.xml和mapping.xml是如何來的。如果沒有這兩個檔案,認證是會失敗的,必然也不會呼叫LsaLogonUser。那怎麼才能產生這兩個檔案?經過交叉引用分析,這兩個檔案可以由另外一個請求AddAlias產生,其對應的處理函式為ServiceAliasAddAlias。這個請求的資料格式如下:
<?xml version="1.0" encoding="UTF-8" ?>
<request>
<sequenceNumber>【任意數字】</sequenceNumber>
<requestName>AddAlias</requestName>
<userName>【計算機使用者賬號】</userName>
<addMappedLink>【是否生成xml檔案,需要,則設定為1】</addMappedLink>
<pemCert>【x509證書】</pemCert>
<aliasInfo>
<subject>【subject名字,需要與驗證請求一致】</subject>
<comment>【任意字元】</comment>
</aliasInfo>
</request>
在這個請求的處理函式ServiceAliasAddAlias中,首先會檢查請求的計算機使用者賬號是否存在,如果存在,則再驗證證書格式是否正確,正確後再將證書和Subject資料寫入user-【計算機賬號】.xml和mapping.xml檔案中儲存,以便認證時使用,如下圖所示:
到現在為止,可以透過AddAlias請求新增證書檔案user-【計算機賬號】.xml和mapping.xml檔案,然後再傳送ValidateSamlBToken請求,認證剛才新增的證書檔案,認證成功後使用LsaLogonUser登入,最後獲取登入成功後的令牌,完成漏洞利用。
但是還忽略了一個問題,那就是請求中的計算機賬號可以任意指定?
雖然請求中的計算機賬號是可以控制的,但是別忘了在最開始分析的時候,補丁附近還有Proto_SecurityCheckRequest函式負責檢查請求的安全性。在這個函式中,會檢查連線是否來自公共通道,也就是是否來自管道“\\.\pipe\vgauth-service”,這正是現在使用的管道,如下圖所示:
如果是,則預設認為該連線是不安全的,並設定該管道的擁有者計算機賬號為system,然後會增加額外的安全檢查,在AddAlias請求的時候,如果請求的計算機賬號名不是system,則會請求失敗。也就是說目前只能新增system賬號的證書資料,但是認證的時候使用LsaLogonUser登入system賬號會失敗,查詢一番後發現不能使用system賬號登入,導致漏洞利用失敗。
那麼怎麼利用這個漏洞呢,還有哪些程式碼沒分析清楚,可以導致提權漏洞的呢?
未完待續,敬請期待。
補丁連結
https://www.vmware.com/security/advisories/VMSA-2022-0024.html
參考連結
https://github.com/vmware/open-vm-tools/blob/CVE-2022-31676.patch/README.md
https://www.vmware.com/security/advisories/VMSA-2022-0024.html
點選瞭解更多