Akamai如何揪出微軟RPC服務中的漏洞?
前日,Akamai研究人員在微軟Windows RPC服務中發現了兩個重要漏洞:嚴重程度分值為4.3的CVE-2022-38034,以及分值為8.8的CVE-2022-38045。這些漏洞可以利用設計上的瑕疵,通過緩存機制繞過MS-RPC安全回調。我們已經確認,所有未安裝補丁的Windows 10和Windows 11計算機都會受到影響。
面對無處不在的安全威脅,就讓 Akamai 安全解決方案為你豎起“防護盾牌”!
隨時隨地,幫助您捕捉每一個安全風險!
這些漏洞已經披露給微軟,而微軟也在10月的“周二補丁日”通過補丁修補了相關問題。漏洞的發現過程得到了Akamai研究人員開發的自動化工具和方法論支持,本文將介紹該漏洞的一些情況以及我們在研究過程中使用的工具(RPC工具包代碼庫)。
背景介紹
MS-RPC 是Windows操作系統的基石之一,自從二十世紀九十年代誕生以來,已經深深扎根在系統的很多功能和組件中。服務管理器?離不開RPC!Lsass?需要RPC!COM?也依賴RPC!甚至針對域控制器執行的一些域操作同樣需要用到RPC。RPC已經如此普遍,很多人都覺得這項技術一定已經進行了大量檢查、記錄和研究。
其實并不然。雖然微軟圍繞RPC的使用提供了很多不錯的文檔,但有關本次漏洞相關主題的內容卻并不多,研究人員對RPC,尤其是其安全性的關注也嚴重不足。這可能是因為RPC(不僅是MS-RPC,但微軟無疑也牽涉其中)實在是太復雜,因此也就更加難以研究和理解。
但我們總是樂于接受挑戰的,因此決定一頭扎進MS-RPC的深海。不光是因為這是個有趣的研究課題,而且因為它會對安全性產生影響,畢竟哪怕到現在,也有很多常見的攻擊技術用到了RPC(簡單列舉幾個,例如通過MS-COM發起的T1021.003、通過MS-TSCH發起的T1053.005,以及通過MS-SCMR發起的T1543.003)。MS-RPC雖然內建了安全機制,但如果存在可被輕松繞過或濫用的漏洞呢?如果能濫用暴露的RPC服務以非用戶希望的方式影響計算機呢?
實際上,我們就發現了一種可以通過緩存繞過某個安全機制的方法,并借此發現了可以濫用的服務,從而能在遠程服務器上提升自己的特權,并且完全不需要滿足其他必要條件(下文將詳細分析)。目前我們可以分享有關這些潛在利用方式的兩個例子:WksSvc和SrvSvc。當披露流程全部結束后,我們還將公布其他漏洞信息的詳情。
本文將專注于RPC服務器的安全回調機制,通過緩存繞過該機制的方法,以及我們如何通過自動化研究方法將Windows服務標記為存在潛在漏洞的。我們的自動化工具以及原始輸出結果可參閱我們的RPC工具包,這些信息已經發布到GitHub代碼庫中。這個代碼庫還提供了指向其他實用參考資源以及我們所依賴的其他研究成果的鏈接。
安全回調
在討論漏洞本身之前,首先有必要對MS-RPC所實現的最基本的安全機制之一進行一個簡單的說明:安全回調(Security callback)。安全回調可以讓RPC服務器開發者對RPC接口的訪問加以限制,從而應用開發者自己的邏輯來允許特定用戶訪問,強制實施身份驗證或設置傳輸類型,以及阻止對特定Opnum(服務器所暴露的函數可以用Opnum來代表,即“操作編號”)的訪問。
每當客戶端調用服務器暴露出的函數時,RPC運行時都會發出這樣的回調。
RPC安全回調
我們的研究主要專注于遠程客戶端-服務器交互。特別提到這一點是因為,RPC運行時在服務器端的代碼實現與ALPC端點和遠程端點(如命名管道)的代碼實現有所差異。
緩存機制
為改善性能并提高利用率,RPC運行時會對安全回調的結果實現緩存。基本上,這意味著在每次調用安全回調之前,運行時會嘗試著先使用緩存的項。讓我們深入了解一下具體的實現吧。
在RPC_INTERFACE::DoSyncSecurityCallback調用安全回調前,首先會檢查是否存在緩存項。為此需要調用OSF_SCALL::FindOrCreateCacheEntry。
OSF_SCALL::FindOrCreateCacheEntry會執行下列操作:
- 從SCALL(一種代表客戶端調用的對象)獲取客戶端的安全上下文。
- 從客戶端的安全上下文中獲取緩存字典。
- 使用接口指針作為字典的鍵,并使用緩存項作為值。
- 如果不存在緩存項,則會創建一個。
RPC運行時內部的緩存過程
每個緩存項都有三個重要字段:接口中的過程(Procedure)數量、一個位圖,以及接口代系(Generation)。
在RPC服務器生命周期內,接口可能會被改變,例如服務器針對現有接口調用RpcServerRegisterIf3后。這又會導致隨后調用RPC_INTERFACE::UpdateRpcInterfaceInformation,從而更新接口并增大接口的代系。這樣,緩存就知道自己需要“重置”,因為緩存項可能來自原先的接口。
緩存機制可以工作在兩種模式下:基于接口(這是默認行為)的模式,以及基于調用的模式。
- 基于接口的緩存
在該模式下,緩存以接口為基礎運行。這意味著從緩存的視角來看,只要位于同一個接口上,對兩個不同函數的兩個調用就沒有任何區別。
為了知道是否可以使用緩存項還是需要調用安全回調,RPC運行時會將緩存項中保存的接口代系與實際的接口代系進行對比。由于緩存項的初始化過程會讓接口代系歸零,因此在首次進行對比時,接口代系必然是不同的,因而總是會調用安全回調。如果回調成功返回,RPC運行時就會更新緩存項的接口代系(從而將其“標記”為一個成功的緩存項,隨后無需再次調用安全回調就可以訪問接口了)。客戶端下次調用相同接口上的函數時將使用緩存項。
- 基于調用的緩存
當RPC接口使用RPC_IF_SEC_CACHE_PER_PROC標志注冊時將使用此模式。在該模式下,緩存會通過一個位圖來追蹤安全回調可以訪問哪些過程。因此,如果客戶端調用Foo函數并且安全回調成功返回,我們就針對Foo有了一個緩存項;如果客戶端調用Bar函數,則將再次調用安全回調。
基于調用的緩存和基于接口的緩存
緩存的相關要求
那么需要滿足哪些條件才能讓緩存正常工作?首先需要澄清一些術語。MS-RPC代表客戶端和服務器之間使用綁定句柄(Binding handle)建立的邏輯連接,客戶端和服務器都可以使用指定的函數來操作綁定數據。
綁定可以進行身份驗證。當服務器(通過調用RpcServerRegisterAuthInfo)注冊身份驗證信息時就會發生這種操作,隨后客戶端可以在綁定上設置身份驗證信息。借此,服務器可以獲得有關客戶端身份的信息。該身份驗證過程將輸出一個為客戶端創建的安全上下文對象。
整個緩存機制均基于這個安全上下文。這意味著如果綁定未經身份驗證,將無法為客戶端創建安全上下文,因而將無法使用緩存。為了讓緩存正常工作,服務器和客戶端都需要注冊并設置身份驗證信息。
但如果服務器不注冊身份驗證信息會怎樣?能否依然使用緩存?這就涉及到多路復用(Multiplexing)。
多路復用
在Windows 10的1703版之前,一個服務可以與其他服務共用同一個Svchost進程。這種行為對MS-RPC的安全性產生了一定影響,因為一些RPC運行時對象是在所有實例之間共享的。例如,在注冊一個端點(如TCP端口7777)后,該端點將可用于訪問同一個進程中運行的所有接口。因此其他本應只進行本地訪問的服務,現在也將可以遠程訪問。微軟也在這里描述了這種行為。
端點能被復用,雖然這一事實已被很多人所了解并有了相關文檔記載,但我們想說的是另一種非常類似的行為:SSPI多路復用。作為身份驗證信息注冊過程的一部分,服務器必須指定要使用的身份驗證服務。身份驗證服務是一種Security Support Provider(SSP),作為一個軟件包,它可以處理從客戶端收到的身份驗證信息。大部分情況下將會使用NTLM SSP、Kerberos SSP或Microsoft Negotiate SSP,從而在Kerberos和NTLM之間選擇最佳選項。
RPC運行時會將身份驗證信息以全局的方式保存。這意味著,如果兩個RPC服務器共用同一個進程,并且其中一個服務器注冊了身份驗證信息,那么另一個服務器也將獲得這些身份驗證信息。這樣,客戶端在訪問任何一個服務器時,就可以對綁定進行身份驗證。從安全的角度來看,如果一個服務器沒有注冊身份驗證信息,此時就不會期待客戶端對綁定進行身份驗證,也不應該進行緩存。然而事實并非如此。
CVE-2022-38045 — Srvsvc
在了解了有關RPC安全回調和緩存的基礎知識后,我們可以看看是否能在真實世界中濫用這一機制。我們選擇了Srvsvc,過去我們已經在其中發現了一個被逐步擊破的漏洞。
Srvsvc暴露了MS-SRVS接口。Server服務(也叫做LanmanServer)是Windows中一項負責管理SMB共享的服務。共享也是一種資源(文件、打印機、目錄樹),可通過Common Internet File System(CIFS)服務器進行網絡訪問。本質上來看,網絡共享可以讓用戶利用網絡上的其他設備執行日常任務。
在研究Srvsvc的安全回調時,我們注意到除了已經發現的漏洞外,該函數可能包含其他漏洞。一起看看安全回調的邏輯:
Srvsvc的安全回調邏輯
如上所示,Srvsvc的安全回調包含下列邏輯:
- 如果遠程客戶端試圖訪問介于64-73(含)范圍內的函數——拒絕訪問。
- 如果非集群賬戶的遠程客戶端試圖訪問介于58-63(含)范圍內的函數——拒絕訪問。
因此從本質上來看,遠程客戶端被禁止訪問接口上的特定函數。從這個范圍檢查可知,受限制的函數都是敏感函數,只能被預期的(本地)進程所調用。
盡管這個檢查試圖阻止對這些函數的遠程訪問,但遠程攻擊者只要濫用緩存即可繞過這一限制。首先,遠程攻擊者可以調用一個不在該范圍內的函數,即可以遠程使用的函數。由于安全回調函數會返回RPC_S_OK,RPC運行時即可將結果成功緩存。又因為該接口并未使用RPC_IF_SEC_CACHE_PER_PROC標記注冊,因此將使用基于接口的緩存。所以,攻擊者下一次調用相同接口上的任意函數時,將直接使用緩存項,進而允許訪問。這意味著攻擊者現在將可以調用自己本不應能訪問的本地函數,這一過程中完全不會調用安全回調。
RPC安全回調的緩存繞路過程
Srvsvc并不注冊身份驗證信息,因此正常情況下,客戶端將無法對綁定進行身份驗證,進而無法啟用緩存。但事實證明,當服務器計算機內存數少于3.5GB時,Srvsvc將與其他服務共用同一個Svchost進程。AD Harvest Sites and Subnets Service和Remote Desktop Configuration Service這兩個服務會注冊身份驗證信息,因此Srvsvc此時就容易受到緩存攻擊了。
在這種特定情況下,攻擊者可以使用Opnum 58–74訪問受限制的函數,而攻擊者利用這些函數的方式之一就是脅迫遠程計算機進行身份驗證。
開始尋寶吧
在了解到濫用安全回調的緩存機制會產生實際的漏洞后,我們決定找出其他可能受到緩存攻擊影響的接口。但如果要手工查找所有接口,這將是一項漫長而艱巨的任務,于是我們打算用自動化的方式來完成。
這種情況下,可以通過兩種方式來查找RPC接口:通過當前正在運行的進程,或通過文件系統。
對于正在運行的進程,我們可以查看已經載入內存的RPC服務器,為此或者在遠程服務器上查詢遠程端點映射器(例如使用Impacket的rpcmap或rpcdump工具),或者在本地進行(使用RpcView或RpcEnum等工具)。不過這種方式會遇到一個問題:會漏掉所有當前尚未加載的端口,并起我們無法查看客戶端端口,因為它們還沒注冊。
或者也可以搜索Windows文件系統,在其中查找文件中編譯的RPC接口。對于每個接口,我們通過分析傳遞給RpcServerRegisterIf的參數來找出注冊信息。這有些類似RpcEnum的做法,但我們查找的是文件系統而非內存。
為了涵蓋并未載入內存的接口,我們的研究最終選擇了文件系統的方法。我們編寫了多個腳本和工具將這一過程自動實現,相關內容均已發布至RPC工具包代碼庫。
為了找到啟用緩存的接口,我們其實并不需要解析RPC接口本身,所需的全部信息都能從RPC服務器的注冊調用中提取。注冊函數可接受RPC接口結構、注冊標記以及安全回調指針。盡管如此,解析RPC接口結構也能提供很多實用信息,例如接口暴露的函數,接口被客戶端還是服務器使用等。雖然我們最關注的是RPC服務器(其中可能存在漏洞),但RPC客戶端也對服務器的調用提供了可供參考的寶貴見解。
RPC服務器接口結構請參閱該文檔,借此我們就不必猜測各種字段了。另外,大小字段和傳輸語法是不變的(實際上可能的傳輸語法有兩種:DCE NDR和NDR64,但我們只是意外發現了DCE NDR)。
PE文件中保存的RPC接口結構代碼片段截圖,框出的內容為大小和傳輸語法
通過(使用Yara或正則表達式)尋找這兩個常量,我們可以很簡單地找到所有RPC接口結構。一旦找到后,即可借助解釋器信息字段來了解服務器到底實現了哪些功能。
清理后的輸出內容范例
但我們還是缺乏有關接口安全回調的信息(如果存在這些信息的話),同時也不知道接口是否會被緩存。為此,我們必須求助可信賴的朋友:反匯編器。每個稱職的反匯編器都會提供xref功能,借此可以在RPC服務器中輕松找到所有接口注冊函數調用。這樣,我們就只需要解析函數調用參數并借此提取接口結構地址(以便將其與我們收集到的RPC服務器數據交叉引用),以及安全回調地址(如果存在)和RPC接口標記。
RPC服務注冊反匯編
我們所公布的清理腳本可以實現上述這一系列操作。您可以在RPC工具包中獲取該腳本,以及在Windows Server 2012和Server 2022上的輸出結果。
到底能有效果嗎?
這些方法和理論聽起來都挺不錯,但真的能獲得結果嗎?
答案是:能。共有超過120個接口同時具備安全回調和緩存,很多都缺乏文檔記載。這本身并不值得恐慌,因為大部分時候,安全回調并不會受到緩存機制如此大的影響。通常來說,安全回調所執行的檢查都是針對不可緩存的值進行的,例如傳輸協議序列(如TCP)或身份驗證級別。任何變更都需要一個新的安全上下文,因為此時需要建立新的連接,這就重置了緩存,并且讓任何可能的緩存繞路措施失效。
但我們通過這種研究方法也發現了一些漏洞。目前只能討論其中一個,因為其他漏洞還沒有走完披露過程。
WksSvc
- CVE-2022-38034 CVSS評分:4.3
WksSvc暴露了MS-WKST接口。該服務負責管理域成員關系、計算機名稱以及到SMB網絡重定向器(如SMB打印服務器)的連接。查看該接口的安全回調我們發現,少數函數的處理方式與其他函數有很大差異。
WksSvc安全回調的一部分,展示了不同函數和不同Opnum之間的差異
當通過本地客戶端調用Opnum介于8-11之間的函數時,也需要進行檢查,這意味著不允許對它們進行遠程調用。但因為使用了緩存,如果首先調用另一個允許遠程調用的函數,然后調用這個受限制的函數,又會發生什么?
您猜對了:由于第一個調用所創建的緩存項,我們將可以用遠程方式調用這個原本受到限制只能本地調用的函數。那么現在又產生了新問題:這些函數是否重要到需要保證它們受到限制,只能通過本地客戶端調用?
暴露的函數包括:NetrUseAdd、NetrUseGetInfo、NetrUseDel以及NetrUseEnum。也許您覺得熟悉,因為它們都能通過netapi32.dll訪問(例如可參閱NetUseAdd)。
這很好,因為我們從中獲得了一條線索,從而可以確定能通過這種攻擊做些什么。也就是說,我們可以將遠程服務器連接到我們自己指定的網絡共享文件夾,甚至將其映射到我們選擇的邏輯驅動器盤符,這與net use的作用極為類似。(巧合?也許未必!)
這樣我們就可以指定兩種攻擊方案:
1.可以要求對我們的共享文件夾進行身份驗證,隨后將其轉發至不同服務器以進行NTML重播攻擊,或將令牌存儲起來以便脫機破解密碼。
要求對我們的惡意文件服務器進行身份驗證,隨后即可在驗證過程中竊取NT哈希
2.或者我們可以用一些有趣或實用的文件偽裝稱成現有的文件服務器(或假裝是全新文件服務器),由于這些文件都在我們控制之下,因此可以用我們認為適合的方式將其變為武器,進而感染目標用戶。
將惡意Web服務器充當中間人攻擊手段或釣魚服務器,向不夠警惕的用戶發送武器化的文檔或惡意軟件
上述兩個場景,以及以遠程方式調用受到限制只能本地調用的函數的能力,足以讓微軟將這個漏洞歸類為EoP分類,并給出4.3分的評分。
但這還不是故事的全部,我們還有一些問題需要注意。
安全上下文
WksSvc下的RPC服務器本身并不進行任何身份驗證注冊。如果該服務獨立運行,將無法進行任何客戶端身份驗證(這樣做會導致RPC_S_UNKNOWN_AUTHN_SERVICE錯誤)。因此我們需要讓該服務與其他服務一起運行,以便同時濫用SSPI多路復用機制。這也使得受影響的Windows版本僅限Windows 10 1703之前的版本,或在內存不足3.5GB的情況下運行的更新版本的Windows。
登錄會話
另一個問題則和網絡映射文件夾的工作方式有關,這類文件夾始終會被限制在創建映射文件夾的用戶的登錄會話中。因為我們最開始需要登錄才能獲得安全綁定和緩存,這意味著我們在目標計算機上將始終創建不同于現有(交互式)會話的另一個登錄會話。就所有意圖和目的而言,這意味著我們的漏洞并不會產生影響。我們所創建的網絡映射只存在于我們那短暫的登錄會話下,并不像普通用戶登錄計算機時創建的網絡映射,我們創建的映射根本不可見。
WinObj截圖,展示了所創建的邏輯盤符只存在于發起攻擊的登錄會話上下文中,并不會出現在交互式會話中
為了克服這個問題,我們又深入挖掘了NetrUseAdd的代碼。結果發現,我們可以向NetrUseAdd傳遞一些標記,借此讓它在Global命名空間中創建映射,這將影響所有用戶。這些標記甚至能在可用的頭文件LMUse.h中找到:
在LMUse.h中看到的全局映射標記
借助這些標記,我們的代碼已經可以成功創建能影響交互式會話的全局映射,隨后就可以利用了。
WinObj和資源管理器的截圖片段,展示了對WksSvc的成功利用:在遠程服務器上創建了一個全局驅動器映射,并使其在資源管理器中對已登錄用戶可見
總結
MS-RPC是一個龐大而復雜的協議,它也承擔了Windows的一些核心功能。雖然開發者可以利用一些安全功能保護自己的RPC服務器,但對安全研究人員來說,這依然是一個有趣的話題,這恰恰是因為它包含了一個可能產生安全影響的漏洞。
盡管如此,有關該話題的公開研究也并不多。本文我們探討了MS-RPC中的一個大型安全機制(安全回調),并發現了以回調結果緩存形式存在的繞過機制。我們還介紹了自己發現有漏洞RPC服務器所采用的研究方法,并通過漏洞的利用演示了我們的發現。
希望本文提供的內容,以及我們的RPC工具包代碼庫能對其他人的研究工作起到一些幫助。
您還有在安全方面想要了解的其他問題嗎~如果有的話,讓我們把評論區留給您!同時歡迎您體驗 Akamai Linode 云計算平臺,助力您一站配置計算、存儲、網絡和容器,現在點擊體驗,還有送100美金用云額度↓↓↓
技術無邊界,互動零距離!如果您想查看和安全有關的更多話題的話,那就來關注 Akamai 吧~