濫用COM登錄檔結構:劫持及載入技術
一、前言
攻擊者可以通過各種方式利用COM劫持技術實現隱蔽載入及本地持久化,典型的例子包括CLSID遺留(子)鍵的引用、CLISID覆蓋以及連結等。
許多程式及實用工具都可以呼叫COM登錄檔載荷,比如 Rundll32.exe
、 Xwizard.exe
、 Verclsid.exe
、 Mmc.exe
以及 Task Scheduler
(任務計劃程式)。從傳統角度來看,任何程式只要解析不存在且/或未引用的COM類,都有可能會受到“非預期的”載入攻擊的影響(比如劫持攻擊)。
劫持COM伺服器程式(比如MMC)可以衍生出許多有趣的用例。攻擊者可以使用 -Embedding
引數以隱藏方式開啟GUI程式。
可以考慮使用一些防禦手段,比如採用強大的應用白名單策略、監控脫離正常父程序(如 svchost.exe
)的某些命令列用法(如使用 -Embedding
)及登錄檔鍵值(如 TreatAs
、 ScriptletUrl
)的建立操作等。
二、背景介紹
前階段我寫了篇 文章 ,介紹了濫用COM登錄檔結構的一些技巧。在上一篇文章中,我們討論了一些有趣的技術,比如如何尋找被遺棄的登錄檔鍵值、COM劫持、橫向滲透、規避防禦機制、繞過應用白名單以及持久化技術等。在這篇文章中,我們將更進一步,重點關注其他一些劫持方法以及可用於規避的載入技術,主要內容包括:
1、COM劫持技術;
2、用於規避及持久化的CLSID載入技術;
3、濫用COM服務端:MMC(Microsoft Management Console)使用案例;
4、防禦方法。
三、COM劫持技術
為了在沒有註冊的情況下載入和執行COM載荷,攻擊者必須以一定的方式去影響COM登錄檔結構,其中一種方法就是使用COM劫持(COM Hijacking)技術。關於COM劫持這個概念 Mitre ATT&CK Framework 已經給出了非常準確的定義:
COM(Microsoft Component Object Model,Microsoft元件物件模型)是Windows上的一個系統,可以通過作業系統實現軟體元件之間的互動。攻擊者可以使用該系統,通過劫持COM引用和關係在合法軟體中插入惡意程式碼,達成持久化目標。劫持COM物件需要修改Windows登錄檔,替換某個合法系統元件的引用,該操作可能導致該元件無法正常執行。當系統元件通過正常系統呼叫執行時,攻擊者的程式碼就會被執行。攻擊者可能會劫持頻繁使用的物件,以維持一定程度的持久化駐留,但不大會破壞系統內的常見功能,避免系統出現不穩定狀態導致攻擊行為被發現。
以上參考 COM劫持(T1122) ,Mitre ATT&CK
接下來我們重點介紹常見的一些COM劫持技術。
利用被遺棄的COM鍵
InprocServer32
以及 LocalServer32
(此外還包括 InprocServer
和 LocalServer
)的鍵值(key-values)是COM伺服器(即 DLL
、 CPL
、 EXE
以及 OCX
程式)的引用點。當攻擊者 發現 (存在漏洞的)一個引用點後,就可以在適當條件下(比如路徑可寫時)將載荷投放到已被遺棄的PE(Portable Executable)引用路徑上。如果被呼叫時(比如載入器或者程式引用了COM鍵時),由於呼叫方會嘗試例項化CLSID入口點下的COM物件,因此PE載荷就會得到載入機會。前一篇 文章 中我介紹了 VMware vmnetbridge.dll
這個例子,這裡再簡單回顧一下。
在這個例子中,VMware Workstation解除安裝程式會遺留下一些COM鍵(處於未註冊狀態)。執行一個探測指令碼後,我們可以發現 LocalServer32
鍵指向了之前已被移除的一個DLL路徑。攻擊者可以簡單替換這個檔案,劫持COM節點結構,如下圖所示:
圖1. 被遺棄的COM鍵登錄檔路徑
圖2. 被遺棄的COM鍵檔案路徑
圖3. 利用二進位制引用替換法劫持被遺棄的鍵
覆蓋COM鍵
覆蓋COM物件可能是影響COM結構載荷的更為實用的方法。在 HKCU
登錄檔中新增正確的鍵值後,當引用目標COM物件時, HKLM
中的鍵值就會被覆蓋(並且“新增”到 HKCR
中)。在Casey Smith( @subTee )給出的“SqibblyDoo” 樣例 中,攻擊者可以匯入如下 登錄檔檔案 ,使用另一個類標識(CLSID)成功劫持 scripting.dictionary
COM程式標識(ProgID):
圖4. 包含 Scripting.Dictionary
COM覆蓋鍵值的登錄檔檔案
實際上,任何程式或者指令碼只要嘗試例項化 scripting.dictionary
COM程式或嘗試載入被劫持的類標識時,都會呼叫攻擊者佈置的載荷。
連結COM鍵(使用 TreatAs
鍵)
影響COM載荷載入的另一種方法就是使用 TreatAs
鍵,該鍵實際上充當的是另一個(未註冊的)CLSID鍵的快捷方式(或連結)。許多(原生的)Windows程式會引用不存在的CLSID登錄檔節點(注意:我們可以使用 SysInternals 的ProcMon工具來識別這些懸空式引用)。根據具體的載入程式以及CLSID鍵,攻擊者可以使用帶有 TreatAs
引用的被劫持的CLSID節點結構,在CLSID鍵被引用時(如程式或者指令碼啟動時)達到載入目的。實際上攻擊者可以通過以下兩步完成這個任務:
1、劫持程式的未引用的COM CLSID路徑或者帶有 TreatAs
鍵的合法路徑;
2、然後將帶有 TreatAs
鍵的CLSID結構連結到另一個(被劫持的)COM CLSID鍵,後者包含惡意的載入器。
我們來看看Matt Nelson( @enigma0x3 )和Casey Smith( @subTee )給的一個例子。Matt和Casey曾做過名為 Windows Operating System Archaeology 的專題演講,其中提到了如下所示的登錄檔匯入檔案:
圖5. TreatAs
登錄檔檔案
在圖5中,攻擊者建立了2個主要的CLSID節點(如果 HKLM
中存在這些CLSID值則會被覆蓋掉)。一旦 {3734FF83-6764-44B7-A1B9-55F56183CDB0}
這個CLSID鍵(橙色高亮部分)被引用(比如程式載入或者其他呼叫/載入方法), TreatAs
鍵就會充當一個超連結快捷鍵角色,“重定向”到 {00000001-0000-0000-0000-0000FEEDACDC}
這個CLSID鍵(綠色高亮部分),呼叫相應的載荷。當呼叫者/載入者呼叫時,大致的抽象邏輯可以分為以下幾個步驟:
1、直接引用CLSID節點
[呼叫方] -> [CLSID入口點] -> [COM伺服器] -> [載荷(比如 Scrobj.dll Scriptlet
)]
2、使用 TreatAs
連結引用CLSID節點
[呼叫方] -> [第一個CLSID入口點] -> [ TreatAs
鍵應用] -> [第二個CLSID入口點] -> [COM伺服器] -> [載荷(比如 Scrobj.dll Scriptlet
)]
注意:這裡應該著重表揚下TrustedSec的Jason Lang( @curi0usJack ),他在識別和利用這些未引用的COM路徑方面做了許多傑出的工作。Jason在BlackHat 2018的TrustedSec Purple Team培訓課程中詳細介紹了這方面內容。此外,大家也可以參考Adam( @Hexacorn )的一篇 文章 ,裡面介紹了關於劫持TreatAs例項化過程的一些基本知識。
四、用於規避及持久化的CLSID載入技術
現在我們討論下用於規避的COM載入技術。
引用載入器
如前文所述,如果指令碼以及程式嘗試例項化或者呼叫已被劫持COM節點的類以及/或者程式識別符號時,就(很可能)會在執行的某個時刻載入其他載荷。覆蓋或者連結惡意COM節點的操作通常需要考慮如下幾個因素:
1、成功識別並劫持(缺失的)引用,並且不會對程式正常行為造成負面影響(比如造成程式崩潰);
2、可以承擔未知後果的影響,選擇可能不會(或者不大會)影響系統或者使用者體驗的COM節點(比如,沒有任何明顯的線索表明程式或者主機的行為存在異常);
3、此外,也可以嘗試“修補”已劫持的路徑,解決“程式執行流”(注意:這個概念很有意思,超出了本文的討論範圍)。
比如,當我們用Casey Smith的“SquibblyDoo”載荷劫持 scripting.dictionary
COM節點然後執行 WinRm
時,我們可以看到當 scripting.dictionary
被例項化時會出現一些非預期的結果:
圖6. 使用 WinRM
載入被劫持的COM節點
注意:並不是所有被劫持的路徑都會導致(可見的)程式性故障。有許多無縫的、可被劫持的路徑不會對程式執行流造成負面影響,其中某些路徑還可以作為隱蔽的持久化技術來使用。
Rundll32
如前一篇 文章 所述,通過CLSID鍵(或者PROGID)呼叫載荷的一種方法就是在 rundll32
中使用 -sta
(single threaded apartment)引數,這種方法並沒有那麼廣為人知,具體命令為:
rundll32.exe -sta {CLSID}
或者
rundll32.exe -sta ProgID
-sta
引數並沒有詳細的說明文件,但該引數的確可用,並且有被濫用的潛在風險。如下圖所示,我們使用這種方法來實現了前文描述的COM節點直接載入以及通過連結方式( TreatAs
)載入:
圖7. COM節點的直接載入及連結( TreatAs
)載入
我們也可以使用 rundll32
配合ProgID(Program Identifier,程式識別符號)來呼叫我們劫持的COM節點:
圖8. Rundll.exe: -sta
與ProgID配合執行
在使用 AutoRuns
實現本地持久化方面, rundll32
命令無法規避過濾器的篩查,但可以使用隱藏的登錄檔載荷來迷惑人們的雙眼:
圖9. Rundll32 -sta登入啟動項
利用計劃任務實現持久化
幾年以前,Matt Nelson( @enigma0x3 )寫了一篇 文章 ,介紹了利用計劃任務和COM處理程式劫持實現使用者模式下的本地持久化技術。Matt在文章中介紹瞭如何尋找計劃任務中 Action
設定為 Custom Handler
的可疑項。檢視計劃任務對應的XML檔案後,我們可以看到這個 Action
實際上是與“COM處理程式”對應的一個CLSID值。劫持這個CLSID結構後,載荷的利用就非常簡單。當計劃任務執行時(比如系統登入時),惡意載荷就會被執行。
圖10. 計劃任務配置檔案(來源:Matt Nelson的 文章 )
利用Verclsid呼叫載荷
根據微軟的 說明文件 , verclsid.exe
可以“在Windows資源管理器例項化一個COM物件前驗證該物件”,這一點非常有趣。Nick Tyrer( @NickTyrer )在Github上演示了 Verclsid
的一種用法,如下所示:
verclsid.exe /S /C {CLSID}
使用合適的CLSID執行上述命令後,就可以呼叫攻擊者設定的載荷,如下所示:
圖11. 利用CLSID執行Verclsid
利用Xwizard呼叫載荷
根據Nick Tyrer的描述, Xwizard
是載入CLSID節點的另一種方式。 @harr0ey 提供了一種 執行方式 ,不會彈出錯誤資訊:
xwizard.exe RunWizard /taero /u {CLSID}
注意:已經有釣魚惡意軟體攻擊活動中使用了 Verclsid.exe
這個工具,大家可參考這篇 文章 (來自Red Canary)瞭解詳細資訊。
五、濫用COM伺服器
Windows系統中有一些內建程式能夠在特定服務(如遠端主機管理)的上下文環境中充當COM/DCOM伺服器。經過正確的呼叫和例項化後,當使用 -Embedding
引數呼叫DCOM/COM應用時,就可以利用這些應用的公開屬性及方法(這一點需要進一步驗證)。然而這裡存在一個“有趣的”副作用,那就是(許多)具有GUI/可見視窗元件的啟用COM的應用(如 mmc.exe
、 mspaint.exe
、 winword.exe
、 iexplore.exe
等)會以伺服器模式來執行,但卻不呈現GUI元件。我們來看些具體例子:
MMC(Microsoft Management Console)工具的功能和可擴充套件性非常強大,因此可能是Windows系統管理員最喜歡的得力助手。MMC允許(高許可權)使用者新增多個“snap-ins”(管理單元),在本地或者遠端管理Windows系統,然而這個應用也會暴露一些攻擊面,可能被攻擊者濫用。去年年初時候,Matt Nelson( @enigma0x3 )發現MMC對外公開了一種方法,通過該方法攻擊者可以藉助DCOM協議輔助執行遠端命令。Matt在一篇 文章 中詳細介紹了這種技術。
雖然這種方法不像常見的遠端命令執行/橫向滲透技術那樣令人興奮,但MMC可以用來呼叫CLSID載荷,實現規避載入以及通過 Run
登錄檔鍵值實現本地駐留。下面我們可以開始配置MMC控制檯檔案,瞭解具體利用方法。
MMC:CLSID Web地址連結
首先,我們需要建立一個CLSID連結,將我們的配置資訊儲存成控制檯檔案( .msc
檔案)。我們可以開啟MMC,通過“Add/Remove Snap-In”視窗來設定載荷。為了簡單起見,我們選擇“the Link to Web Address”(指向Web地址的連結)這個snap-in來打開向導,在“Path or URL”文字框中輸入被劫持的/引用的CLSID鍵,如下圖所示:
圖12. 新增MMC Snap-In:Web地址連結
接下來,為這個Snap-In設定一個名稱,然後選擇“Finish”,如下圖所示:
圖13. 新增MMC Snap-In:設定名稱
經過這些操作後,“Console Root”節點下就會建立我們設定的“test”項。只要選擇“test”選單項,就會呼叫相應的CLSID連結。
圖14. MMC Snap-In:在選中時啟動CLSID載荷
MMC:MSC檔案載入
建立並啟用我們的載荷配置後,我們可以將控制檯儲存為 test.msc
。確保相應的Snap-In標籤(如 test
)處於選中狀態以保持當前控制檯狀態。如果沒有選中,我們的載荷就無法在控制檯檔案開啟時被呼叫。
為了進一步確認這個條件,我們可以使用文字編輯器開啟這個控制檯檔案,驗證配置資訊以及CLSID指標的值是否正確:
圖15. MMC XML配置檔案
儲存好控制檯檔案後,我們可以通過命令列啟動msc檔案,通過 -Embedding
標誌(注意:大小寫敏感)以隱蔽的方式呼叫CLSID載荷:
mmc.exe -Embedding c:pathtotest.msc
圖16. 利用 -Embedding
引數實現MMC隱蔽啟動
利用MMC實現本地持久化
在利用 AutoRuns
實現本地持久化方面,由於 mmc.exe
是經過微軟簽名的二進位制程式,因此可以規避預設的過濾器,如下圖所示:
圖17. MMC AutoRuns Run登錄檔鍵值:過濾器處理結果
移除過濾器後,我們可以看到對應的啟動項:
圖18. MMC AutoRuns Run登錄檔鍵值:不使用過濾器的處理結果
在登入時,由於我們劫持了登錄檔鍵以及引用,所以系統會執行我們的載荷:
圖19. MMC Run登錄檔鍵值:登入時執行
綜合考慮後, mmc.exe
可能不是最實用的利用物件,然而如果其他COM程式以類似方式來呼叫,可能會具備更高的實用性。
六、防禦策略
1、在完美的場景中,經過正確配置的應用程式白名單(AWL)解決方案與程式碼完整性保護機制結合起來後可能會阻止(許多)這類載荷的執行;
2、可以監控某些有趣的COM應用的使用情況以及 Run
登錄檔鍵值。 Embedding
引數可能是比較有趣的一個特徵,但正常的DCOM遠端管理和本地例項化過程中可能也會使用該引數。對COM應用的正常呼叫/例項化行為應該源自於Service Host( svchost.exe
)程序,來自其他父程序的呼叫可能都值得懷疑;
3、可以監控程序建立事件,比如感興趣命令列操作以及CLSID呼叫程式的使用;
4、評估新建立的登錄檔鍵值,特別要注意包含 TreatAs
以及/或者 ScriptletURL
鍵值的新增內容。
七、他人研究成果
1、James Forshaw( @tiraniddo )在“ COM In 60 Seconds ”中詳細介紹了COM的每一步工作流程(現在我仍在重複觀看這個視訊)。如果您不熟悉James的研究成果,我強烈推薦大家儘快去學習一下;
2、PhilipTsukerman( @PhilipTsukerman )在“ New lateral movement techniques abuse DCOM technology ”這篇文章中為我們介紹了COM技術的入門知識,也很好概述了DCOM橫向滲透技術;
3、Rob Maslen( @rbmaslen )在“ COM and the PowerThief ”視訊中介紹了COM與Internet Explorer互動的背景知識,此外我們還可以參考Rob開發的 PowerThIEf 工具來濫用正在執行的IE例項。