iT邦幫忙

2026 iThome 鐵人賽

DAY 28
0
AI Security

把 AI 接進 SOC系列 第 28 篇

【Day 28】唯讀 ≠ 無害:稽核 MCP server

  • 分享至 

  • xImage
  •  

昨天講完「唯讀不等於安全」這個教訓。 今天想把這句話再往前推一步:我信任的這個 MCP server 本身,到底乾不乾淨?


稽核一個自己每天在用的工具?
Day 27 那個 MCP server 是社群寫的,不是官方出品。 我用了它好一陣子,但從來沒有真的檢查過它的原始碼跟依賴鏈長什麼樣子——這件事想想有點奇怪:我對 Wazuh 規則寫沒寫對這麼講究,卻對「幫 AI 跟 Wazuh 對話的這個中間人」毫無戒心。

限制條件先講清楚:不裝 Rust 工具鏈(裝起來要 1–2 GB,而且我只是想稽核,不是要開發)。 這代表 cargo audit、cargo geiger 這類工具用不了,得完全靠公開資料手動比對。

四個步驟,全部不需要 Rust

  1. git clone 原始碼
  2. 雜湊驗證本機執行檔對應哪個 release
  3. grep 第一方程式碼裡的 unsafe
  4. 依賴清單對照 RustSec 漏洞資料庫(公開的純文字 git repo)

實際指令:

# 版本驗證
sha256sum mcp-server-wazuh.exe
# 比對 GitHub release 頁面公布的 digest

# 第一方 unsafe 盤點
grep -rn "unsafe\|unsafe impl\|unsafe extern\|static mut\|from_raw\|transmute" src/
# 0 處命中

版本先確認:雜湊完全相符
本機執行檔的 SHA-256,跟 GitHub 官方發布的那份完全一致,確定對應到 v0.3.0(2025 年底發布)。 順手查了一下數位簽章——未簽章。 這個工具沒有簽章不代表它有問題,但代表「這份檔案真的來自它宣稱的來源」這件事,目前只能靠雜湊比對,沒有簽章鏈可以驗證。


第一方程式碼:0 處 unsafe
Grep 第一方原始碼(8 個檔案、2,221 行),unsafe 關鍵字——包含 unsafe impl、static mut、transmute 這類高風險寫法——全部 0 處。

這件事我想特別澄清一下怎麼解讀:「0 處」是一個有效的結果,不是「什麼都沒查到」的失敗。 它精確地說明了一件事:這 2,221 行沒有動用任何記憶體安全的逃生口。 但它完全不涵蓋依賴、FFI、巨集展開後的程式碼——而這個工具的直接依賴裡,就有一個是 C 函式庫的 FFI 綁定,那裡 Rust 的保證完全不適用。
https://ithelp.ithome.com.tw/upload/images/20260911/20178898mDuy40TZmk.png

真正的轉折點:一行 .gitignore
這次稽核最大的發現,不是「unsafe 是 0」,是一行被排除在版本控制外的鎖定檔案。

這個工具的原始碼倉庫裡沒有 Cargo.lock——不在 git 歷史裡、被 .gitignore 明確排除。 這代表沒有人能知道 2025 年底那次發布,實際編譯進去的依賴版本是什麼。 16 個直接依賴裡,有 7 個曾經出過安全公告,合計 11 份;因為沒有鎖定檔案,其中 8 份無法判定這次發布到底受不受影響。

因果鏈很直接:.gitignore 排除鎖定檔案 → 倉庫不保存依賴版本 → 無法得知實際編譯的版本 → 大多數安全公告無法判定 → 今天想重建同一個版本標籤,得到的依賴組合會不一樣。 這違反 Cargo 官方的建議——函式庫可以不提交鎖定檔案,執行檔專案應該提交。

雜湊相符證明的事,比感覺上的少。 它只證明「我電腦上的檔案 = GitHub 發布的檔案」,不證明「這個執行檔真的是由這份原始碼編譯出來的」。 中間缺的是可重現建置、簽章、build attestation 這些機制。

那 11 份公告裡,唯一能判定的一項值得細看
有一個依賴的版本落在一份高風險公告(CVSS 8.8,一種透過 DNS 重綁定攻擊的手法)的受影響範圍內。 我沒有停在「版本在範圍內,所以有風險」這一步,回頭查了實際的編譯設定:

  • 那個公告針對的是一種需要另外啟用的 HTTP 傳輸功能
  • 官方發布這個工具的時候,沒有啟用這個功能的編譯旗標
  • 這個專案實際使用的連線方式是 stdio,根本不是那個有風險的傳輸路徑

結論:版本家族落在受影響範圍,但目前這個部署形態沒有啟用那條路徑,不能宣稱現在可以被那個手法攻擊。 但這是條件式的——如果哪天改用 HTTP 版的替代方案(Day 27 提過的另一條路線),必須先確認依賴版本升級過,不然就是直接把這個高風險路徑打開。

上游還在維護嗎:252 天沒有更新
最後一次程式碼提交,距今已經 252 天,而且那次提交只是一個裝飾性的動作(觸發 GitHub 的貢獻者圖表刷新),不是功能變更。 2026 年新出現的幾份安全公告,上游完全沒有回應過。 這代表如果這個工具未來被發現更嚴重的問題,不會有人主動幫你修。


https://ithelp.ithome.com.tw/upload/images/20260911/20178898BwlX9df0Tu.png
這次稽核能證明什麼,不能證明什麼
能證明的:本機執行檔跟官方發布的雜湊相符;第一方 2,221 行沒有明示的 unsafe;16 個直接依賴裡有 7 個曾有公告;那個高風險公告目前因為部署形態(stdio、未啟用 HTTP 功能)沒有被觸發;上游 252 天沒有實質更新。

不能證明的:不能證明執行檔真的是由這份原始碼編譯出來的;不能列出完整的間接依賴或它們的 unsafe 使用量;不能確認 2025 年底那次發布實際包含的依賴版本;不能排除依賴、FFI、巨集或 Rust runtime 裡的 unsafe;完全沒有檢查邏輯漏洞、認證機制、TLS 設計這些更深層的東西。

投入產出比最高的一件事
我列了幾個可能的處置方案,成本從低到高排:維持現狀但定期重跑這次的比對(成本最低,至少不會對新公告完全無感)、繼續用 stdio 唯讀部署(已經是現狀,順帶避開了那個高風險 HTTP 路徑)、把一個已經沒人維護的依賴換成還在維護的分支(成本低)。

但投入產出比最高的一件事,是自己 fork 一份、補上被排除的鎖定檔案。 這個動作能把那 8 份「無法判定」直接變成「可判定」,而且是一次性成本——不用重寫任何功能,只是把原本該有、卻被排除的資訊補回來。


明天
明天想寫一起外部案例:一個自主 agent,對外攻擊了四百多個目標,但最後全部失敗——不是因為被偵測到,是因為目標端的設定擋住了它。

明天見。


上一篇
【Day 27】將 Wazuh 接上 LLM 查詢
下一篇
【Day 29】兩起自主 Agent 入侵案例
系列文
把 AI 接進 SOC 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言