如何利用CVE-2017-8715:PowerShell模塊清單文件繞過安全補丁
譯者:shan66
預估稿費:180RMB
投稿方式:發送郵件至linwei#http://360.cn,或登陸網頁版在線投稿
前言
最近,我和Matt Graeber(@mattifestation)一直在鑽研繞過Device Guard上下文中用戶模式代碼完整性(UMCI)檢測的方法。在這個過程中,我們發布了一系列的CVE,與此同時,微軟也通過不斷改進約束語言模式(CLM)——Period Guard和AppLocker的主要PowerShell策略執行機制,緩解PowerShell對UMCI的攻擊。
CVE-2017-0218
我們知道,絕大多數注入漏洞都會濫用帶有微軟簽名的PowerShell腳本或包含運行未簽名代碼功能的模塊。這個範圍實際上是很廣的,從調用參數的Invoke-Expression一直到PowerShell的Add-Type cmdlet的自定義實現,皆在該範圍之內。微軟簽名的PowerShell代碼是有針對性的,因為賦予微軟代碼執行許可權的AppLocker或Device Guard策略將會以全語言模式來執行——也就是說,在可以執行什麼代碼方面,沒有加以限制。
為了充分了解微軟所進行的修補工作,我們不妨先來考察一下程序在修補之前的行為。這個漏洞的主要問題是,攻擊者可以使用帶有微軟簽名的PowerShell腳本中的函數來繞過UMCI。為了把這個問題搞清楚,我們來看一下腳本「utils_SetupEnv.ps1」,該腳本是位於C:Windowsdiagnostics下面的Windows Troubleshooting Packs的一個組件。這個腳本含有一個名為「import-cs」的函數。這個函數的作用就是接收C#代碼,然後為其調用Add-Type(注意:Add-Type在約束語言模式下是禁止使用的)。 由於該腳本帶有微軟的簽名,因此,它會以全語言模式運行,也就是說,該漏洞允許攻擊者執行任意C#代碼。
正如你在上面看到的那樣,這裡導入了「utils_SetupEnv.ps1」,它為我們提供了「import-cs」函數。 在使用這個函數的時候,我們可以傳遞自己的C#代碼,從而繞過約束語言模式。上面的漏洞已經在CVE-2017-0218中說明了,現在該漏洞已經得到了修復。
緩解措施
為了應對類似上面這種漏洞,微軟為運行在PowerShell約束語言模式下的代碼強加了一些額外的限制。第一個限制就是不允許通過Import-Module或其他方式導入PowerShell腳本(.PS1)。 如果您嘗試在CLM中導入腳本的話,將會看到如下所示的內容:
對於這個限制措施,一種可能的繞過方法是將PowerShell腳本(.PS1)重命名為模塊文件(.PSM1)並以此方式導入。為了應對這種繞過方式,微軟又引入了第二個緩解措施。
微軟對通過PowerShell模塊(.PSM1)導入和使用的內容做出了相應的限制。這一點是通過「Export-ModuleMember」完成的。其中,Export-ModuleMember的作用就是定義了在導入模塊後,允許使用模塊的哪些函數。在約束語言模式下,模塊的函數必須通過Export-ModuleMember導出後才能使用。 這大大減小了濫用帶有微軟簽名的PowerShell模塊中的函數的攻擊面。 一般來說,顯式定義要向模塊的用戶公開哪些函數也是一個非常好的方法。
如果我們將「utils_SetupEnv.ps1」重命名為「utils_SetupEnv.psm1」,並嘗試導入的話,看上去會非常順利。但您可能會注意到,之前使用的「import-cs」函數沒有被識別出來。這是因為「import-cs」函數不是通過Export-ModuleMember向外公開的。
當我們查看一個正常的PowerShell模塊文件的時候,會發現Export-ModuleMember的定義將如下所示:
這實質上意味著,在導入模塊時只能使用「Export-ODataEndpointProxy」。這極大地限制了帶有微軟簽名的PowerShell腳本被濫用的可能性,尤其是那些包含可能被用來運行未簽名代碼的函數的腳本,因為大部分函數都不會公開。同時,PowerShell團隊也正在穩建地處理被用來規避約束語言模式的各種原語。
CVE-2017-8715
在研究了這個補丁之後,我發現並報告了一個與Export-ModuleMember有關的漏洞,該漏洞的編號為CVE-2017-8715,並在十月份發布了相應的安全補丁。這個安全措施繞過漏洞是通過濫用PowerShell模塊清單(.PSD1)來實現的。在研究這些文件的影響時,我意識到可以通過這些文件來配置模塊行為,而且它們不像其他PowerShell文件那樣具有簽名方面的限制(可能因為PSD1文件不包含可執行代碼的緣故)。儘管沒有這些限制,人們仍然可以對PSD1進行簽名。
我們再次回到「utils_SetupEnv.ps1」腳本,發現「import-cs」函數無法使用,因為該腳本中的任何函數都無法通過Export-ModuleMember公開。為了解決這個問題,我們可以將「utils_SetupEnv.ps1」重命名為「utils_SetupEnv.psm1」,這樣我們就可以導入它了。進行重命名之後,我們就可以刪除為我們導出「import-cs」函數的「utils_SetupEnv.psm1」模塊所對應的模塊清單了。這個模塊清單的內容如下所示:
如您所見,我們已經將「import-cs」設置為一個通過「FunctionsToExport」導出的函數。這樣的話,就能像Export-ModuleMember那樣導出函數了。由於PowerShell的模塊清單文件不像其他PowerShell文件那樣具有簽名要求,因此我們可以直接為我們想要濫用的帶有Microsoft簽名的腳本創建自己的模塊清單文件。在刪除了PowerShell模塊「utils_SetupEnv」的上述清單後,就可以繞過微軟新引入的.PS1與Export-ModuleMember相關的安全措施,並能使用「import-cs」函數執行任意C#代碼了。
總結
如前所述,這個繞過漏洞已經通過CVE-2017-8715公之於眾了。相應的補丁要求PowerShell模塊清單文件(.PSD1s)與模塊中的所有其他文件那樣,必須提供相應的代碼簽名,也就是說,即使某個模塊帶有相應的簽名,並滿足Device Guard或AppLocker策略的要求,其模塊清單也必須具有與白名單規則一致的簽名才行。這樣做可以防止攻擊者修改現有的清單或使用他們自己的清單文件進行攻擊。
推薦閱讀: