紅藍對抗之如何利用Shellcode來躲避安全檢測

  • 2019 年 11 月 7 日
  • 筆記

寫在前面的話

對於紅隊安全研究團隊來說,一次成功的滲透測試必須是不被目標系統發現的,隨着現代終端檢測和響應(EDR)產品日趨成熟,紅隊也必須隨之每日俱進。在這篇文章中,我們將跟大家介紹FireEye Mandiant紅隊研究人員如何通過構造特殊Payload來繞過現代EDR產品,並獲取到目標系統的完整命令控制訪問權。

Shellcode注入或Shellcode執行往往是我們在目標系統上實現Payload執行的最優方法,那麼什麼是Shellcode呢?Michael Sikorski將其定義為:「用於描述任何自包含可執行代碼的術語」。大多數商業滲透測試框架,比如說Empire、Cobalt Strike或MetaSploit,它們都內置有Shellcode生成器,而這種Shellcode生成器一般都是二進制或十六進制格式,具體需要取決於用戶是將其以原始輸出還是應用源碼的形式生成的。

我們為什麼要使用Shellcode呢?

對於Payload類型來說,Shellcode所能帶來的靈活性非常高。Shellcode可以使用多種編程語言來編寫,而且這些語言可以跟很多類型的Payload進行整合。除此之外,Shellcode的這種靈活性允許我們根據需求並在任何環境下構建定製的Payload。因為Shellcode可以直接以Payload作為載體運行,或注入到任何正在運行的進程中,我們就可以使用多種技術來躲避EDR產品的檢測了,這些技術包括Shellcode代碼混淆、編碼以及加密等等,這樣可以大幅增加商業EDR產品的檢測難度。

在這篇文章中,我們將介紹如何使用下列三種方法來隱蔽地運行Shellcode:

1、CreateThread 2、CreateRemoteThread 3、QueueUserAPC

其中的每一項技術都會對應一個Windows API函數,而這些函數將會負責分配Shellcode的執行線程,並最終實現Shellcode的運行。CreateThread主要負責Shellcode的執行,CreateRemoteThread和QueueUserAPC主要負責Shellcode的注入。

CreateThread工作流程

1、為當前進程分配內存; 2、將Shellcode拷貝到分配的內存中; 3、修改新分配內存的保護機制,以允許Shellcode在內存空間中運行; 4、使用已分配內存段的基地址創建線程; 5、等待返回線程句柄;

CreateRemoteThread

1、獲取目標註入進程的進程ID; 2、打開目標進程; 3、在目標內存中分配可執行內存; 4、將Shellcode寫入到已分配內存中; 5、使用已分配內存段的起始地址在遠程進程中創建一個線程;

QueueUserAPC

1、獲取目標註入進程的進程ID; 2、打開目標進程; 3、為目標進程分配內存; 4、向已分配內存中寫入Shellcode; 5、修改新分配內存的保護機制,以允許Shellcode在內存空間中運行; 6、使用已分配內存段的起始地址在遠程進程中創建一個線程; 7、當線程進入「預警」狀態時,將線程提交至執行隊列; 8、將線程恢復至「預警」狀態;

命令執行

大家先停一下,我們整理一下:

1、惡意代碼就是我們的Shellcode – stage 0或stage 1代碼是真正執行惡意操作的代碼。 2、標準的「Shellcode運行程序」會通過注入或直接執行的方式來運行惡意代碼。

接下來,我們還需要一種執行已編譯代碼的方法,一般來說,我們可以通過可執行程序(exe)或動態鏈接庫(DLL)來實現,不過紅隊研究人員更願意使用lolbins命令來執行。

信息整合

我們將開發一個Shellcode運行工具(DLL),它可以利用lolbins實現,並且可以在不需要更新代碼庫的情況下實現注入式或非注入式的Shellcode,以此來保證靈活性。完成之後,我們將得到一個名叫DueDlligence的C# Shellcode運行程序,源代碼可以進入【https://github.com/fireeye/DueDLLigence】獲取。

DueDlligence項目可以快速地在之前提到的技術之間進行切換,我們只需要修改下圖中的全局變量值即可:

DueDLLigence DLL包含三個非託管的導出函數,這三個導出函數使用了Rasautou,Control,和Coregen這三個原生的Windows命令(本文所使用的Shellcode樣本只會彈出calc.exe):

打開源代碼之後,你會發現樣本使用了下列導出函數:

首先,我們要生成我們的Shellcode,下圖中,我們使用了Cobalt Strike來生成「rev_dns」監聽器的原始Shellcode。完成之後,我們需要在Linux中運行下列命令來生成base64編碼版本的Shellcode:

base64 -w0 payload.bin > [outputFileName]

接下來,我們需要用base64編碼的我們自己的x86或x64 Payload替換第58行的base64編碼的Shellcode,上圖中我們生成了一個x86 Payload,有需要的話你可以修改「use x64 Payload」來生成一個x64 Payload。

此時,我們需要重新安裝DueDLLigence(Visual Studio項目)中的未託管導出庫,,因為有時當你使用不同的項目時,可能會導致DueDLLigence項目出現問題。你可以打開NuGet包管理終端,然後運行下列命令:

Install-Package UnmanagedExports -Version 1.2.7 command

完成上述所有操作之後,需要構建源碼和DLL。Visual Studio Pro自帶的Dumpbin.exe可以幫助我們運行和測試生成的DLL,並查看導出函數:

我們可以使用其他的lolbin技術來擴展上圖中的導出函數列表,不過大家盡量把不需要使用的移除掉以減小Payload的體積。

Shellcode注入技術的現代檢測方法

儘管Shellcode可以幫助我們規避檢測,但還是有可能被檢測到的,下面我們來分析幾種進程注入技術。

在我們的Shellcode運行程序中,Shellcode注入技術(CreateRemoteThread和QueueUserAPC)會以掛起狀態生成一個進程,然後向目標進程中注入Shellcode。比如說,我們選擇explorer.exe來作為注入目標,我們的Payload將通過MSIExec來運行。之後會生成一個進程樹,cmd.exe將生成msiexec.exe,並最終生成explorer.exe。

在企業環境中,可以使用SIEM來收集遙測數據,以檢測cmd.exe -> msiexec.exe -> explorer.exe進程樹的執行情況。根據父-子進程的關係,防禦端可以通過異常檢測來識別潛在的惡意軟件。

API鉤子是EDR和反病毒產品常用的惡意軟件檢測技術,很多攻擊者會使用類似PsSetCreateProcessNotifyRoutine(Ex)和PsSetCreateThreadNotifyRoutine(Ex)這樣的內核程序來實現攻擊。當進程注入發生時,一個進程會修改另一個進程地址空間中的內存保護機制,通過檢測類似API的調用情況,隨着紅隊和惡意攻擊者繼續開發新的進程注入技術,網絡防禦人員以及安全軟件需要繼續適應不斷變化的環境。監視諸如virtualAllocex、virtualProtectEx、createRemoteThread和ntQueueAPCThread之類的Windows API函數調用可以為識別潛在惡意軟件提供有價值的數據。除此之外,監視create process與create_suspended和create_hidden標誌的使用可能有助於檢測攻擊者要注入的掛起或隱藏的進程。

總結

使用Shellcode作為紅隊研究過程中Payload感染的最後階段,不僅可以方便研究人員在各種各樣的目標環境中執行Payload,而且還可以實現安全產品的規避。DueDLLigence Shellcode運行程序是一個動態工具,它可以給紅隊研究人員提供一種「現成」的安全產品規避方法。

*參考來源:fireeye,FB小編Alpha_h4ck編譯,轉載請註明來自FreeBuf.COM