1. 簡介
Endpoint Detection and Response (EDR) 系統的不斷演進,已顯著提高了防禦性資安的門檻。這些平台採用多層次防禦,包括靜態簽章分析和複雜的行為監控,以偵測惡意攻擊,特別是涉及 Kernel 層級 rootkit 的活動。因此,攻擊性資安工具與技巧的開發必須適應這些先進的對策。本報告提供了 Singularity Linux Kernel rootkit 案例的詳細技術分析 [1] 。主要關注點是混淆、模組片段化和分階段、記憶體內載入的技術實作,這些代表了 EDR 規避策略的重大轉變。
2. EDR 偵測機制與規避目標
現代 EDR 解決方案嚴重依賴靜態分析來識別已知威脅。就 Elastic Security 而言,這涉及使用 YARA 規則來掃描特定的字串、函數名稱和結構模式,以判斷 Kernel rootkit 的存在 [1] 。對初次偵測失敗的分析顯示,該 rootkit 立即被大約 26 個不同的警示標記,導致 Kernel 物件在載入之前就被隔離。主要的 YARA 規則針對常見的 rootkit 模式:
-
通用 Rootkit 模式:
諸如
Linux_Rootkit_Generic_61229bdf之類的規則針對一組大量的可疑函數名稱,例如hide_module和hook_getdents[1] 。 -
Hooking 簽章:
規則
Linux_Rootkit_Generic_482bca48特別尋找系統字串 (例如sys_call_table,kallsyms_lookup_name) 與 rootkit 前綴 (例如hide_,hooked_) 的組合 [1] 。 -
Ftrace 和 License 組合:
一個高度特定的規則
Linux_Rootkit_Generic_5d17781b針對kallsyms_lookup_name_t和 license 字串"license=GPL"的組合,這是基於 ftrace 的 rootkit 中常見的模式 [1] 。
規避的首要技術挑戰是,在完全消除這些靜態的、存在於磁碟上的簽章的同時,仍維持 rootkit 的功能性——其本質上需要 Kernel hooking 和模組操作。
3. 進階規避技巧分析
3.1. 透過字串片段化實現靜態簽章混淆
rootkit 隱蔽性的最直接威脅是 hardcoded 字串的偵測。實作的解決方案是一種編譯時的字串片段化技巧,旨在擊敗依賴連續字串匹配的 YARA 規則 [1] 。此技巧利用 C 編譯器會將相鄰字串字面值串接起來的行為。透過將單一字串分解成多個較小的字面值,完整的、可偵測的字串永遠不會在二進位檔的資料區段中連續存在。
舉例來說,為了規避特定的 license 字串偵測規則,混淆器將標準 Kernel 模組巨集轉換為:
// Original, detectable code MODULE_LICENSE("GPL")
轉換成片段化的、不可偵測的形式:
// Obfuscated code: The C compiler concatenates these at compile time, // but the string "GPL" does not exist as a single entity in the binary. MODULE_LICENSE("G" "P" "L")
這種混淆的實作是透過建置 pipeline 中的一個 Python script 來管理的。以下是混淆 license 字串的邏輯片段:
- def _obfuscate_license_strings(self, content: str) -> str:
- """
- Obfuscates MODULE_LICENSE/AUTHOR/DESCRIPTION strings
- To evade YARA rule: Linux.Rootkit.Generic (5d17781b)
- """
- # 1. Obfuscate MODULE_LICENSE("GPL")
- # Transform: MODULE_LICENSE("GPL")
- # Into: MODULE_LICENSE("G" "P" "L")
- content = re.sub(
- r'MODULE_LICENSE\s*\(\s*"GPL"\s*\)',
- 'MODULE_LICENSE("G" "P" "L")',
- content
- )
- # 2. Obfuscate MODULE_AUTHOR and MODULE_DESCRIPTION using a helper function
- # ... (further obfuscation logic)
- return content
此方法有效地擊敗了未設計來重組片段化字串的靜態分析工具,從而繞過了諸如
Linux_Rootkit_Generic_5d17781b
之類的規則
[1]
。
3.2. 符號與函數名稱隨機化
除了簡單的字串,EDR YARA 規則還針對可疑的函數和變數名稱,例如
hide_module
或
ftrace_hook
。此處的規避策略涉及
智能名稱隨機化(Intelligent Name Randomization)
[1]
。在建置程序期間,一個客製化混淆器會將所有敏感的內部函數和變數名稱替換為隨機產生、非可疑的識別符號。此程序被全面套用,包括 Ftrace 輔助函數 (例如
fh_install_hook
,
fh_remove_hook
) 的名稱,這些名稱是諸如
Linux_Rootkit_Generic_f07bcabe
之類規則的特定目標
[1]
。透過重新命名這些識別符號,rootkit 消除了用於偵測的靜態簽章,同時保留了底層功能。
3.3. 模組片段化與分階段記憶體內載入
最關鍵的規避技巧是解決 EDR 在執行前隔離惡意檔案的能力。這透過一個涉及片段化、編碼和記憶體內執行的多階段載入程序來實現 [1] 。Kernel 模組首先被分割成多個片段,並使用 XOR 進行編碼。然後使用一個小型的、看似良性的載入器可執行檔案來啟動該程序。
該載入器執行以下操作序列:
- 從磁碟讀取編碼後的片段。
- 使用 XOR key 解碼片段,以在記憶體中重構完整的 Kernel 模組二進位檔。
-
利用
memfd_create系統呼叫在記憶體檔案系統中創建一個匿名檔案描述符(Anonymous file descriptor)。此檔案描述符指向記憶體中重構的模組,該模組從未寫入實體磁碟。 -
使用
finit_module載入模組到 Kernel,引用記憶體內的檔案描述符。
這種方法將偵測邊界從對磁碟上檔案的靜態分析轉移到對載入程序的動態、行為分析。EDR 被繞過,因為 malicious payload 從未以其最終的、可偵測的形式存在於檔案系統上。這個分階段載入程序的架構可以使用下圖視覺化來表示:
此技巧非常有效,因為它利用合法的 Linux Kernel 機制 (
memfd_create
和
finit_module
) 來完全從記憶體中執行 malicious payload,使得傳統基於檔案的 EDR 監控不足以應付。
4. Rootkit 能力與行為規避
一旦載入,Singularity rootkit 展現了一套全面的隱蔽和控制功能 [1] 。其核心能力包括程序隱藏、檔案和目錄隱藏 (隱藏與特定模式匹配的檔案),以及網路隱藏 (例如,從網路公用程序中遮蔽特定 port 上的 TCP 連線)。它還包含了進階的反分析功能,例如阻擋 BPF program、清除 Kernel taint flags 以隱藏未簽署模組的載入,以及淨化 Kernel log 以移除其存在的痕跡 [1] 。
一個值得注意的行為規避技巧是使用 ICMP Backdoor 進行命令與控制 ( C2 )。rootkit 被設定為監控 ICMP 封包,並在接收到具有特定序號 (例如 1337) 的封包時觸發 Reverse shell [1] 。這個 C2 channel 是低調且非標準的,旨在規避可能標記更常見 C2 protocol (如 HTTP 或 DNS tunneling) 的典型網路行為偵測規則。
5. 環境分析與未來趨勢
Singularity rootkit 所展示的多技巧方法與複雜惡意軟體開發的更廣泛趨勢一致。例如,對
HijackLoader
活動的分析強調了使用多重反虛擬機器檢查,強調了規避的縱深防禦策略
[2]
。這表明僅依賴單一規避技巧已不再可行;現代威脅需要一種同時解決靜態分析、記憶體鑑識和行為監控的分層方法。
轉向記憶體內執行和濫用合法系統呼叫 (如
memfd_create
) 對於 EDR 開發者來說是一個重大挑戰。儘管 EDR 在監控使用者空間程序方面越來越熟練,但這個 rootkit 所利用的 Kernel 層級操作和記憶體內執行路徑證明了一個關鍵的
間隙
。未來的 EDR 開發必須專注於更深入的 Kernel 層級、進階記憶體鑑識,以及偵測與分階段、記憶體內載入序列相關的微妙行為異常的能力。
6. 結論
對 Singularity rootkit 規避技巧的技術分析證實,編譯時混淆、符號隨機化以及分階段、記憶體內載入的組合對於現代 EDR 靜態分析和初次行為檢查非常有效。本報告中詳述的技巧——特別是字串片段化和基於
memfd_create
的載入機制——為進階 EDR 繞過方法學的當前狀態提供了寶貴的見解。為了維持有效的防禦,未來的資安解決方案必須演進,納入更穩健的 Kernel 層級監控和動態分析能力,以便在 payload 達到完全執行隱蔽性之前偵測到它。