一、前言
在研究繞過UAC(用戶賬戶控制)的新型技術時,我發現了一種新的繞過方法。雖然微軟并不認為UAC屬于安全邊界范疇,但我們依然將這個問題反饋給微軟,也愿意在此處與大家分享。我們已經在Windows 10 Build 17134上測試過這種方法。在深入分析繞過方法之前,本文首先將簡要回顧一下UAC的背景知識,以便幫助大家了解UAC的內部工作原理。
二、背景知識
當隸屬于Administrators組的用戶想執行需要高權限的某個進程時,系統就會彈出UAC提示窗口,確認用戶提升進程權限。然而,Windows系統中并非所有的特權可執行程序都會彈出UAC窗口,某些例外情況下并不會彈出該窗口,而會“自動提升”目標可執行文件的權限,這樣就能繞過UAC機制(許多人肯定會感到非常驚訝)。
系統對這類受信任的可執行文件做了其他一些安全檢查,以確保這些文件的確可信,不會被攻擊者濫用。之前的UAC繞過技術中廣泛利用了這種方法,本文的利用思路也不例外。然而,為了成功繞過UAC,我們需要在攻擊過程中跳過一些“坑”。如果我們的可執行文件想實現“自動提權”,就必須遵循某些強制性條件。為了分析整個過程,這里我將給大家展示appinfo.dll(處理權限提升的AIS服務,屬于UAC的核心組件之一)中的一些反匯編代碼片段。
條件1:autoElevate為True
當出現程序權限提升情況時,系統就會對AIS(appinfo.dll)執行RPC調用,將目標可執行文件的路徑作為調用參數。隨后,該服務會映射目標可執行文件的內容以便后續讀取,系統會嘗試讀取可執行文件的manifest信息,解析autoElevate字段(如果該字段存在)的值。

圖1. 讀取可執行文件的Manifest信息解析可能存在的autoElevate值
如果該字段存在并且值為True,那么系統會認為這是一個可以自動提升權限的可執行文件,隨后執行權限提升,繞過UAC提示框(前提是該文件已通過另一個限制條件,下文會提到這個問題)。然而,這種autoElevate規則依然存在一個例外情況。無論manifest的具體內容是什么,如果文件名匹配某個白名單中的EXE名稱,系統也會將其當成具備“自動提升權限的”可執行文件。如下圖所示,代碼中在manifest檢查過程后有一個bsearch調用,檢查文件名是否匹配白名單可執行文件名列表。如果文件名滿足條件,那么就會自動提升權限,無視manifest數據。

圖2. bsearch調用測試可執行文件名是否匹配自動提升權限的exe文件名
硬編碼的白名單文件名部分列表如下:
cttunesvr.exe
inetmgr.exe
migsetup.exe
mmc.exe
oobe.exe
pkgmgr.exe
provisionshare.exe
provisionstorage.exe
spinstall.exe
winsat.exe’
條件2:經過簽名
如果UAC請求所對應的二進制文件已配置為“自動提升權限”,那么系統就會使用wintrust!WTGetSignatureInfo來檢查文件的簽名。這意味著攻擊者無法簡單地構造manifest信息或者可執行文件名來實現自動權限提升,因為攻擊者的文件很可能沒有經過正確的簽名處理,并且很有可能無法滿足第3個條件(即從可信目錄中執行)。
條件3:從可信目錄中執行
實現自動權限提升的第3個條件:目標可執行文件位于“可信目錄”中,比如C:\Windows\System32。如圖3所示,AIS會檢查權限提升請求所對應的文件路徑,在本例中,“可信目錄”為C:\Windows\System32。

圖3. 檢查可信路徑
既然本文的名字為“如何通過模擬可信目錄繞過UAC”,大家應該能猜到我們下文的內容了。
三、繞過UAC
在背景知識中我們提到過,如果滿足如下條件,則可以實現權限自動提升(UAC繞過):
1、配置為權限自動提升;
2、經過正確簽名;
3、從可信目錄(C:\Windows\System32)中執行。
在檢查可信目錄時,Appinfo.dll(AIS)會使用RtlPrefixUnicodeString這個API來檢查目標可執行文件路徑是否以C:\Windows\System32\作為前綴。這是非常可靠的檢查過程,因為系統會檢查目標可執行文件的標準路徑。為了繞過這個檢查步驟,我構造了一個目錄:C:\Windows \(請注意Windows后面跟著一個空格符)。當然這個路徑并不能繞過RtlPrefixUnicodeString,并且由于Windows不允許在目錄名末尾附加一個空格符,因此這并不是一個有效的目錄名(或者至少不是一個“友好的”目錄名)。然而,如果我們使用CreateDirectory API,然后在待創建的目錄名前加上\\?\,那么我們就可以繞過系統的一些命名規則,將目錄創建請求直接發送給文件系統。

圖4. 調用API
這將導致系統中出現一個尷尬的目錄,能夠與真正的C:\Windows\目錄和諧共存(然而我們不能在Windows資源管理器中對這個目錄做任何操作)。

圖5. 目錄刪除請求無法成功,也無法通過重命名來刪除末尾的空格符
現在我們已經創建了一個C:\Windows \目錄,我們可以在該目錄中創建一個system32目錄,然后將C:\Windows\System32目錄中經過簽名的、能夠自動提升權限的可執行應用拷貝到該目錄中。這里我選擇拷貝winSAT.exe(這是位于自動提升權限白名單中的一個Windows可執行文件)。當我們嘗試運行C:\Windows \System32\winSAT.exe時,appinfo.dll在檢查可信目錄時會先調用如下API(如圖6所示)。這一點非常關鍵,這也是我們為什么能繞過UAC的原因所在。
圖6. API調用過程
當請求權限提升過程將這個尷尬的目錄發送到AIS時,該路徑會傳遞給GetLongPathNameW函數,該函數會將該路徑轉換回C:\Windows\System32\winSAT.exe(刪除了空格符)。非常完美,現在這個路徑已經變成了可信目錄(可以通過RtlPrefixUnicodeString的檢查)。更加完美的是,當完成可信目錄檢查后,后續檢查(以及最終的權限提升請求)依然會使用原始的文件名(帶有空格符)。這樣我們就能通過其他所有檢查,最終讓appinfo.dll執行我們復制的winSAT.exe,自動提升權限(因為該文件已經過正確簽名,并且處于自動提升權限的白名單中)。
為了通過這種方法真正執行攻擊者的代碼,我將一個偽造的WINMM.dll(該dll會被winSAT.exe加載)釋放到了C:\Windows \System32\中,通過本地dll劫持技術執行我們的代碼。完整的流程如下圖所示。

圖7. 完整利用過程
完整代碼可以訪問Github下載。
|