你的 VM 沒在挖礦, 它在幫別人撿鑰匙
三顆磁碟快照的離線解剖:一組 Rust 寫的分散式工具,用我們的網路和帳單,去全網掃別人網站上外洩的雲端金鑰。全部以防禦為目的,不含任何能重建武器的步驟。
- 這不是挖礦、也不是勒索,是一台撿鑰匙的機器:內建 542 條敏感路徑,專找 .env、.git、service-account.json、JS bundle 裡的金鑰與錢包助記詞。
- 拉取式(pull)殭屍網路:worker 不開任何對外服務,主動連回 C2 領目標、回傳撿到的憑證。所以「收進 3.2 TB、送出 284 GiB」。
- 確認沒有 MIG 或執行個體範本,直接刪 3 台 VM 就永久停止;撿到的憑證沒留在我們磁碟上,受害的是被掃的第三方。
本篇目錄
先定義:駭客眼中的資產與變現
所有防護投入都應該從這張表開始。你的東西「值不值得防、要防多緊」,取決於它在攻擊者眼中能換多少錢、多快換到。攻擊者是理性的生意人,他挑的永遠是變現最快、風險最低的資產。
| 你的資產 | 駭客怎麼變現 | 變現速度/門檻 | 對他的價值 | |---|---|---|---| | 雲端運算權限(開 VM) | 開機器挖礦、當掃描節點(本次)、當代理轉租、發垃圾信 | 幾分鐘,帳算你的 | 極高 · 即時 | | AI API Token | 轉租算力給第三方、包裝成便宜 AI 服務轉賣 | 即時,有現成黑市 | 高 · 即時 | | 加密貨幣錢包(助記詞/私鑰) | 直接把資產轉走,不可逆 | 即時,一次性 | 極高 · 即時 | | 金流金鑰(Stripe sk_live) | 操作真實金流、退款詐欺、測卡 | 快,但易被風控 | 高 · 中風險 | | 寄信憑證(SES/SMTP) | 冒用你的網域發釣魚信(信譽度高、進得了收件匣) | 快,可大量 | 中高 | | 原始碼/Token(GitHub) | 再撈更多金鑰、供應鏈投毒、勒索 | 需加工 | 中 · 可加值 | | 個資/資料庫 | 打包上暗網、勒索、二次詐騙名單 | 需買家,慢 | 中 · 看規模 | | 網站流量/SEO | 掛暗鏈、導購、惡意廣告 | 慢,長期寄生 | 低 |
「我們又沒什麼好偷的」是最危險的錯覺,那是一般人的視角。在駭客眼中,你的價值不是你的業務內容,而是你能被換成什麼:一個空專案的開機權限、一把還沒過期的 token、一台有對外頻寬的機器。本次攻擊者根本不在乎我們是賣什麼的公司。
攻擊者鎖定的目標
工具內建 542 條敏感路徑,對每個目標網站逐一探測。這些路徑直接告訴我們「什麼檔案不能公開放上網」:
| 類別 | 例子 |
|---|---|
| 雲端金鑰 | .aws/credentials、.config/gcloud/credentials.db、service-account.json、.kube/config |
| 環境變數檔 | .env、config.env、application.properties、appsettings.json |
| 版本控制外洩 | .git/config、.gitconfig;連 CI/CD:.github/workflows、.gitlab-ci.yml、Jenkinsfile |
| 框架洩密端點 | Spring /actuator/heapdump、/actuator/env、phpinfo.php、Symfony _profiler |
| IDE/部署設定 | .vscode/sftp.json、.idea/dataSources.xml、.idea/WebServers.xml |
| SSH/資料庫 | .ssh/id_rsa、database.php、database.yml、backup.sql、.pgpass |
| 前端打包夾帶 | JS bundle、sourcemap(.map)、webpack chunk、module federation remote |
| 加密貨幣錢包 | BIP39 助記詞(12/24 字),從掃到的內容裡比對字典還原 |
撿到內容後,用開源工具 trufflehog 加上自製比對,鎖定這些憑證格式:AKIA…/ASIA…(AWS)、SES SMTP 憑證、AIza…(Google API)、ghp_…/github_pat_…、sk_live_…(Stripe)、BIP39 字典。
第一課:只要上面任何一種檔案曾經放進公開網站根目錄、Git 歷史或前端打包,就必須當作「已外洩」處理並輪替。這支工具每天在全網掃這些路徑上百萬次。你不被它撿到,只是因為還沒輪到你。
這次外洩了什麼
把上面那張路徑表翻譯成「他到底在撿哪些服務的鑰匙」。前八列是工具明確鎖定的憑證格式,受害者是被掃的第三方;後三列是我們這邊:攻擊者在我們的 VM 上自己建了兩組憑證,而他撿走了誰的什麼,我們查不到。
| 服務 | 憑證類型 | 用途 | 存在形式 | 放在哪 | 權限範圍 | 狀態 |
|---|---|---|---|---|---|---|
| AWS:IAM 使用者與臨時憑證 | access key(AKIA 開頭)、臨時憑證(ASIA 開頭) | 程式存取物件儲存、運算、寄信等全部 AWS 服務 | INI 格式設定檔的 profile 區段,或明文環境變數 | 網站可讀的 .aws/credentials、.env、Git 歷史、前端打包檔 | 依該 IAM 使用者的政策,最糟是 AdministratorAccess | 第三方受害,非我方憑證 |
| AWS SES:寄信服務 | SMTP 使用者名稱與密碼 | 用你的網域寄交易信 | 明文環境變數或應用程式設定檔 | .env、application.properties、appsettings.json | 代表你的網域寄信,收件匣到達率高 | 第三方受害 |
| Google Cloud:API 金鑰 | API key(AIza 開頭) | 呼叫地圖、AI 等計費 API | 明文字串,常直接被打包進前端 JS | JS bundle、sourcemap、.env | 依金鑰限制設定,多數專案沒設限 | 第三方受害 |
| GCP:Service Account | Google Service KEY JSON | 後端程式以服務帳戶身分呼叫 Google API | JSON 檔,內含 private_key 的 PEM 區塊 | service-account.json 放在網站可讀目錄或 repo 裡 | 看綁的角色。最糟就是 Owner,也就是我們自己那把 | 第三方受害(我方那把見另一篇防暴筆記) |
| GitHub | 個人存取權杖(ghp_ 或 github_pat_ 開頭) | 拉私有 repo、推 commit、觸發 CI | 明文字串 | .git/config、.env、CI 設定檔(工作流程 YAML) | 依 token scope,可到私有 repo 全寫入 | 第三方受害;工具另有一支端點專門去領 GitHub token |
| Stripe:金流 | 祕密金鑰(sk_live 開頭) | 建立付款、退款等真實金流操作 | 明文字串 | .env、後端設定檔 | 可操作真實金流,但容易被風控擋下 | — |
| SSH | 私鑰(id_rsa) | 登入伺服器 | PEM 私鑰檔,無密碼保護時可直接使用 | .ssh/id_rsa 被放進網站可讀目錄或 commit 進 repo | 該私鑰授權的所有主機 | — |
| 加密貨幣錢包 | BIP39 助記詞(12 或 24 個英文單字) | 控制錢包資產 | 純文字單字序列,藏在備份檔、筆記或原始碼註解裡 | 掃到的任何文字內容,用字典比對還原 | 等同錢包所有權,轉走不可逆 | — |
| 我們的 3 台 VM(攻擊者自建) | root 密碼與密碼式 SSH 登入 | 他自己登入把工具裝上去、設好常駐 | 由開機腳本寫進 sshd 設定片段(99-crusader-idle.conf) | 3 台 worker VM | VM 內 root | 9/12 專案停權、磁碟快照保存後刪除 VM |
| 攻擊者的 S3 相容集散地(他自己的) | 物件儲存存取金鑰 | worker 把撿到的內容上傳到他的儲存桶 | systemd EnvironmentFile 裡的明文變數 | 我們 VM 的 /etc/systemd/system 相關設定檔 | 他自己的儲存桶 | 屬攻擊端 IOC,內容不公開 |
| 他從我們這三台撿走了誰的什麼 | 不明 | — | — | 邊撿邊串流回 C2,本地暫存隨即清空 | — | 我們只有 findings 計數,看不到內容;VPC Flow Logs 沒開,也不知道掃了哪些網站 |
工具解剖:兩支 Rust 程式
磁碟上留下兩支主程式加一支開源工具。用唯讀方式解析 ELF 符號表(程式沒有 strip,函式名稱都在),只看「它有哪些能力」,不還原「它怎麼實作」。
| 檔案 | 語言/編譯 | 角色 | SHA-256(前 16) |
|---|---|---|---|
| /root/worker_paths | Rust 1.97(2026-07-14)Ubuntu 24.04 | 路徑探測器:對目標逐條試 542 個敏感路徑 | 6a41216ce80cd7e8 |
| /root/worker_js | 同上 | 前端爬蟲:抓 JS/sourcemap/chunk 挖夾帶的密鑰 | 40b580d3e5183186 |
| /usr/local/bin/trufflehog | Go(開源) | 憑證偵測引擎,被上面兩支呼叫 | — |
從符號表還原的能力清單(函式名層級):
- worker_paths:
fetch_config拉 C2 設定 ·probe_one探測單一路徑 ·run_trufflehog/parse_trufflehog_jsonl·extract_aws_pairs抽 AWS 金鑰對 ·find_bip39_mnemonics錢包助記詞 ·scan_ses_windowSES 憑證 ·push_github_token·Spool離線暫存 ·Pusher回傳 - worker_js:
discover_js/discover_html·enumerate_chunkswebpack chunk ·parse_sourcemap還原原始碼 ·federation_remotes·extract_secrets·candidate_map_urls找.map
運作架構:C2 拉取模型
C2 派工主機 攻擊者 S3 集散地
93.123.109.230:8844 93.123.109.247:9000
(防彈主機 AS48090) bucket crusader-recon-…
│ ① GET /api/targets/next ▲
│ ③ POST /api/findings /progress │ ④ 大量下載的內容從這裡進出
▼ │
┌──────────────────────────────────────────────┐
│ 我們專案的 3 台 worker VM │
│ crusader-gcp-probe-…-1/2/5 │
│ worker_paths + worker_js · e2-standard-4 │
│ 無服務帳戶 · 不開任何對外 port │
└──────────────────────────────────────────────┘
│ ② 掃描 .env / .git / JS bundle …
▼
全網受害網站
拉取式(pull)殭屍網路:worker 不開任何對外服務,而是主動連回 C2 領工單。這就是為什麼 VM「收進 3.2 TB、只送出 284 GiB」:它在下載受害網站的內容來掃描,撿到的精華(憑證)很小,回傳量自然小。沒有 nginx、沒有 apache,全靠內建的 Rust HTTP 客戶端。
| C2 端點 | 用途 |
|---|---|
| GET /api/targets/next | 領取下一批要掃的目標網站 |
| POST /api/findings | 回傳撿到的憑證 |
| POST /api/progress | 回報進度(讓 C2 知道節點還活著) |
| POST /api/targets/done | 確認一批完成、釋放租約 |
| GET /api/git/token | 領取 GitHub token 做進一步操作 |
完整攻擊鏈
持久化與「自我複製」的真相
「就算刪掉 VM 也會自動重建」是真實存在的技術,但這次攻擊者沒有用。誠實區分兩種層次:
| 層次 | 機制 | 刪 VM 後果 | 本次 |
|---|---|---|---|
| 開機層持久化 | systemd WantedBy=multi-user.target | 重開機照跑,但刪掉 VM 就沒了 | ✔ 有用(僅此層) |
| 基礎設施層自我複製 | 受管執行個體群組(MIG)+ 執行個體範本:設定「維持 N 台」,刪一台幾分鐘內自動長回來 | 刪 VM 沒用,要先刪 MIG 和範本 | ✗ 未使用(已確認) |
給資安課程:怎麼安全地 step-by-step
想把「攻擊者的詳細路徑」拿去教學員,同時不傷害任何人、也不做出重現攻擊的細節。這兩件事可以並存,關鍵是分清楚「可以教的形狀」與「不能給的武器」。
| 不要提供/示範 | 為什麼 | |---|---| | 惡意執行檔本體、原始碼、可運作的 C2 協定規格 | 拿了就能直接跑,等於散布武器 | | 完整可貼上就用的 startup-script、542 條路徑清單原檔 | 是現成的攻擊 payload | | 攻擊者的 S3 憑證、C2 token 等活的密鑰 | 用了就是存取他人系統 | | 對真實、未授權的網站跑掃描示範 | 就算是教學,掃別人也是攻擊行為 | | 「金鑰 → 可存取哪些資源」的實際對應表 | 等於把還沒輪替的鑰匙圈交出去 |
可以教的:kill-chain 分階段、MITRE ATT&CK 對照、時間線、去識別化的日誌片段、行為特徵、IOC 清單、偵測查詢、「為什麼會成功 → 對應防禦」的成對拆解、能力清單(函式名層級)。
要動手,就用隔離靶場:獨立的丟棄式專案或本機 VM,掃描目標是你自己架的靶機;攻擊端用只回報「我在跑」的良性 beacon 取代真的掃密工具;真樣本只在斷網沙箱做靜態解剖;學員的動手部分是寫偵測規則、跑獵捕查詢、判讀稽核記錄、練習封鎖與輪替。
教「攻擊長什麼樣、怎麼被發現、怎麼防」,不教「怎麼造一把能傷人的武器」。學員離開教室應該更會防守,而不是多一把可用的刀。
- 撿到 AWS 金鑰 → 開 EC2 挖礦、發垃圾信、再擴散。撿到 SES 憑證 → 冒用網域發釣魚信。撿到 Google API 金鑰 → 盜刷 Maps、Gemini。
- 用你的 VM 掃,被封的是你的 IP,被告的是你的專案。他零風險。
- VM 不開對外 port、不掛服務帳戶、UA 偽裝 Chrome,每一項都在降低被偵測的機會。
- 他的工具 2026-07-14 才編譯,Rust 1.97、Ubuntu 24.04。這是一個持續維護的產品,不是腳本小子。
這門生意的帳
把整件事換算成錢,才看得懂他為什麼要做這門生意。我們付的那一欄有帳單可查;他付的那一欄我們拿不到帳單,只能用公開牌價推估,所以標成推論。
| 項目 | 用量 | 單價 | 期間 | US$ | NT$ | 舉證 |
|---|---|---|---|---|---|---|
| 我們付的算力:3 台 e2-standard-4 帳單實付:Core 39.05+21.99,Ram 20.93+11.79 | 約 2,685 vCPU·小時(9 天) | E2 Core+E2 Ram 分開計價 | 9/3 → 9/12 | 93.76 | 3,000 | 帳單依 SKU 分組頁面;稽核記錄 instances.insert 確認機型與台數 |
| 我們付的磁碟:3 顆 200 GB 帳單實付。worker 本身很小,磁碟是開機映像帶來的 | 186.21 GiB·月(pd-balanced) | 約 US$0.10/GB·月 | 9/3 → 帳單截止 | 19.89 | 636 | 帳單依 SKU 分組頁面(Balanced PD Capacity 兩列相加) |
| 我們付的出口流量:回傳 findings 帳單實付。撿到的憑證很小,這些流量多半是回傳與轉送 | 約 230 GiB 送出(前 4 大流量 SKU) | US$0.08~0.12/GiB,依目的地 | 9/5 → 9/12 | 24.80 | 794 | 帳單依 SKU 分組頁面;Monitoring sent_bytes_count |
| 掃描抓回來的內容:流入 3,186 GiB 這一列是整篇的重點:他挑雲端當節點,就是因為吃進來的那一邊不用錢 | 3.2 TB 下載受害網站內容 | GCP 流入不計費 | 9/5 → 9/12 | 0.00 | 0 | Monitoring received_bytes_count;GCP 官方牌價:internet ingress 免費 |
| 證據保存:3 顆磁碟快照 估:實際依壓縮後容量計。證據要留多久,就付多久 | 600 GB 標準快照 | 約 US$0.05/GiB·月(牌價) | 保存期間每月 | 30.00 | 960 | GCP 快照公開牌價;實際金額要等帳單結算 |
| 鑑識人力:3 顆磁碟離線解剖 估:取中間值 NT$27,500 × 2。這一列比帳單貴 12 倍,這才是事件的真正成本 | 約 2 人日:快照掛載、ELF 符號表解析、時間軸重建 | 顧問日費 NT$20,000~35,000(估) | 一次性 | 1718.75 | 55,000 | 本案鑑識工作範圍;日費為假設值 |
| 他付的:C2 派工主機與集散地 估:以 US$50/月 × 9/30 計。這是他這一趟唯一真正掏錢的地方 | 1 台防彈主機同時跑派工 API 與 S3 相容儲存 | 防彈 VPS 約 US$18~150/月(公開牌價) | 9 天 | 15.00 | 480 | C2 位址與 AS 可證;租金為公開牌價推估,我們拿不到他的帳單 |
| 他撿到的:數萬筆疑似憑證 內容不在我們的磁碟上,我們只有計數 | 9 天探測約 1.17 億次路徑、抓取數百萬支 JS | — | 9 天 | — | — | worker 邊撿邊串流回 C2,本地暫存即清空;findings 內容無從得知 |
| 換算成錢的量級(示意) 估:只算 1 把、只算 1 天。這一列解釋為什麼 US$15 的 C2 值得投資 | 假設其中只有 1 把是具管理員權限的 AWS 金鑰,拿去開 1 台 GPU 機 24 小時 | US$32.77/小時(p4d.24xlarge,us-east-1 牌價) | 1 天 | 786.54 | 25,169 | AWS 官方牌價 2026-09;「他確實這樣用」沒有證據,這是變現上限的量級示意 |
| 合計(僅可證明列) | 138.45 | 4,430 | ||||
他花 US$15,我們付 US$138.45 的帳單加上兩人日的鑑識。這門生意的槓桿不在技術,在成本結構:他的邊際成本趨近於零,所以他不需要挑目標,也不在乎你是賣什麼的。
重點學習
- 01變現速度(time-to-cash)決定你該先防哪一項的唯一標準。開 VM 的權限幾分鐘就能換到錢,個資要找買家;防護預算應該照這個順序分配。
- 02拉取式(pull)殭屍網路worker 不開任何對外 port,所以掃 port、看防火牆都抓不到它。要抓它只能看出口流量與帳單。
- 03.env 與 service-account.json542 條路徑裡最值錢的兩種檔案。只要它們曾經在網站根目錄、Git 歷史或前端打包裡出現過,就當作已外洩。
- 04trufflehog / gitleaks攻擊者拿它來偵測撿到的憑證,你可以拿同一支工具先掃自己一遍。攻守用的是同一把尺。
- 05systemd WantedBy=multi-user.target本案唯一的持久化層。認得它,才知道「重開機照跑,但刪掉 VM 就沒了」。
- 06受管執行個體群組(MIG)與執行個體範本真正會「刪了又長回來」的機制。先確認攻擊者沒用它,才敢說刪 VM 就結束了。
- 07流入不計費(ingress free)雲端的計價邏輯直接決定攻擊者的選擇。掃描型工具吃的是下載頻寬,所以雲端 VM 是它最便宜的家。
- 08sourcemap 與 webpack chunk前端打包會把後端的秘密一起帶上網。worker_js 整支程式就是為了這件事寫的。
- 09BIP39 助記詞12/24 個英文單字,撿到就等於錢包直接轉走、不可逆。這是他清單裡變現最快的一項。
- 10IOC(indicator of compromise)C2 網段、systemd 服務名、檔案雜湊。把它們變成偵測規則,才是這篇對你真正的用途。
今天就可以來試試
全部唯讀,不改任何設定;做完你會知道自己有沒有同樣的破口。
- 在你自己的網站上,試三條最值錢的路徑(只對自己的網域做)。
for p in .env .git/config .aws/credentials; do curl -s -o /dev/null -w "%{http_code} $p\n" https://YOUR-DOMAIN/$p done看到什麼代表什麼:任何一條回 200 就是已外洩,該檔案裡的每一把金鑰今天都要輪替;回 403/404 才算過關。 - 掃自己的 repo 與部署目錄有沒有夾帶憑證。
trufflehog filesystem --no-update /path/to/repo gitleaks detect --source /path/to/repo --no-git看到什麼代表什麼:有 finding 就代表攻擊者的同一支工具也會撿到;要看的是「哪個身分」被撿到,不是「哪個檔案」。 - 看主機上有沒有非套件管理裝上去的 systemd 服務。
systemctl list-unit-files --state=enabled --no-pager grep -rl 'ExecStart=/root\|ExecStart=/tmp' /etc/systemd/system/ 2>/dev/null看到什麼代表什麼:ExecStart 指向 /root 或 /tmp 的服務,正常維運不會有;出現一個就當事件處理。 - 看有沒有不該存在的執行檔在暫存與家目錄。
find /root /tmp /var/tmp -maxdepth 2 -type f -perm -u+x -mtime -60 -ls 2>/dev/null看到什麼代表什麼:最近 60 天內出現的可執行檔,如果不是你放的,就是別人放的。 - 看這台機器的出口流量像不像一個掃描節點。
ss -tn state established | awk 'NR>1 {print $4}' | wc -l ss -tn state established | awk 'NR>1 {print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head看到什麼代表什麼:同時數百條到上千個不同目的地的短連線,而你的服務沒有理由去連外面,這就是 worker 的樣子。 - 看雲端帳單有沒有出現「平常不會有」的服務。
gcloud billing accounts list # 主控台:帳單 → 報表 → 依服務分組,時間拉到 60 天看到什麼代表什麼:平常 $0 的專案出現 Compute Engine 或 Vertex AI,就是本案 9/4 那天的畫面。
每篇新文章一封:三點摘要、攻擊者/防守者視角、今天能做的一件事。或先 加入會員 記錄你完成的任務。