返回所有文章
發佈於 · 作者 Renaud Deraison

那次封鎖就是投遞

本週的 DEF CON 34 上,Tenet Security 展示了一種攻擊,它從一個你的防火牆必定會拒絕的請求開始。403 正是重點:WAF 會把被封鎖的請求原封不動寫進安全日誌,數天後某個編碼代理讀取那份日誌來排查 403,並照著裡面的指示行事。這條鏈上沒有任何一步是未經授權的。Bromure Agentic Coding 在文字抵達時就為它評分,並把被劫持的代理所需要的憑證,留在它執行所在的機器之外。

防火牆運作正常。它命中規則、回傳 403,並依設計把它所拒絕的請求寫進日誌。 那一筆日誌記錄,正是酬載抵達編碼代理的路徑。

DEF CON 34 今天上午在拉斯維加斯閉幕。週五,Tenet Security 的 Barak Sternberg、 Nevo Poran 與 Ron Bobrov 發表了一場講題本身就是論點的演講: Your WAF Blocked Us, That Was The Exploit。 議程摘要寫著「Remote Agent Takeover via Cloudflare, Sentry and Claude Zero-Day for data exfil」。綜合報導在 8 月 8 日 刊出。

同一支團隊在六月為 Agentjacking 命名,當時他們證明:一份透過 MCP 取回的偽造 Sentry 錯誤報告,能在超過一百個 線上實例中、以 85% 的成功率讓編碼代理執行攻擊者控制的程式碼。週五的演講把它 延伸到 Sentry 自家的代理 Seer,被下毒的建議接著往下游流進 Cursor。Cloudflare 這條鏈才是新材料。

403 正是重點

從攻擊者的難題開始。他們碰不到你的編碼代理。它跑在開發者的機器上,藏在你所擁有 的一切之後,而攻擊者沒有憑證、沒有工作階段、也沒有進得去的路徑。

於是他們送出一個被設計成必遭拒絕的請求。

WAF 命中一條受管規則並回傳 403。它同時完成工作的另一半,把它封鎖的請求連同 酬載一起記進安全事件日誌。一筆略去酬載的日誌記錄,對它所服務的分析師而言毫無 用處。

數天後,有人注意到那個端點一直丟出 403,就請自己的代理去看看。代理呼叫 Cloudflare 的可觀測性 MCP 伺服器,也就是 Cloudflare 為此發布的官方伺服器 之一,拉出被封鎖請求的資料列。攻擊者的文字就裝在一個 tool_result 區塊裡抵達, 來自開發者自己接上的原廠服務,掛在一個意思是這是我們拒絕過的請求的欄位下。

代理把它讀成指示。接著它動用自己那組已獲授權的 Cloudflare 工具改寫 DNS 記錄、 改道客戶流量。Tenet 估計曝險範圍超過 15,000 個組織,其中包含 Fortune 1000 的 27%。

底下每一步都在做自己份內的事1. 一個請求被造來遭到拒絕,瞄準公開端點不需要任何存取權2. WAF 封鎖它受管規則命中:403並把請求原封不動記錄下來,理應如此3. 有人開口問「結帳為什麼一直丟 403?你看一下」再平常不過的週一雜事4. 代理讀取可觀測性 MCP伺服器,原廠出品,是刻意接上的tool_result: blocked_request.body攻擊者的文字未經更動,躺在一個名字意思是「這是我們攔下的那個請求」的欄位裡代理用自己的工具改寫 DNS客戶流量遭到改道;每一次呼叫都獲得授權
封鎖本身才是投遞酬載的動作。攻擊者永遠碰不到代理,於是送出一個 WAF 必定會拒絕的請求,而 WAF 就把酬載原封不動歸檔進日誌。代理稍後透過 MCP、從原廠服務取回它,外面還包著一個意思是請求已被攔下的欄位名稱。

沒有任何未經授權的事發生

Tenet 把這個模式叫做 Authorized Intent Chain,六月那篇文章則說明了後果:

再走一次這條鏈,試著找出該對哪一步發警報。開發者授權了代理。代理被設定了那台 MCP 伺服器。MCP 伺服器查詢了它本來就該查詢的日誌。它所用的帳號握有你刻意授予 的 DNS 權限。而引發這一切的那個請求,被封鎖了。路徑上每一項控制都做了它被買來 要做的事,而正是這些正確行為的組合構成了攻擊。

任何靠著問是誰在做這件事、他有沒有被允許來運作的東西,在每一跳都會回答「有」, 因為答案確實是「有」。剩下兩步棋:在文字進來的路上讀它,以及把強制執行放在被 劫持的代理碰不到的地方。

在文字抵達時為它評分

Bromure Agentic Coding 讓代理在 Apple Silicon 上一台用完即丟的 Linux VM 裡執行, 並把它流量的每一個位元組都導過主機上的代理伺服器, 在代理執行的那個盒子之外。這包含模型流量,而那正是 日誌資料列變成指示的地方。

工具輸出一律視為不可信

Bromure 會用一個本機的提示注入模型,為代理讀到的內容評分,包括檔案內容、 網頁,以及從 MCP 伺服器與 shell 命令回來的 tool_result 區塊。這個偵測器 找的正是這種東西:一筆帶著祈使句、對著讀者說話的日誌資料列。它評的是那段 文字本身,所以由 Cloudflare 透過你自己設定的連線送達,並不能替酬載換到 任何好處。

偵測到之後要做什麼由你決定

Log and continue 會把每次命中記進 Security Log 視窗,並讓請求繼續走。Ask me what to do 會暫停外送的請求並把標記的文字攤在你面前,讓你看著那句話再 決定。Block 會在模型讀到之前單方面攔下,代理只會拿到一個硬邦邦的 451,並 把它回報成 API 失敗。

權威檔案有自己的分類器

設定下毒是這次 DEF CON 揭露的另一半。一個微調過的 ModernBERT 分類器會為 代理視為常設命令的檔案評分,也就是 CLAUDE.mdAGENTS.mdGROK.md 以及它們的巢狀與全域變體;旁邊還有一個確定性掃描器,專門對付任何模型都 讀不出來的零寬、雙向與 Unicode 標籤酬載。

一切都留在你的 Mac 上

兩個偵測器都在裝置上執行,用的是你從 bromure.io 下載過一次的模型。為你的 正式環境 WAF 日誌評分、找出被注入的指示,並不需要把你的正式環境 WAF 日誌 送去任何地方。

那次寫入需要一把不在機器裡的鑰匙

假設酬載還是通過了。這條鏈的末端是一次修改 DNS 記錄的 API 呼叫,而那次呼叫需要 一份憑證。

在 Bromure 的設定檔裡,它並不在那裡等著被拿走。Cloudflare 權杖是以一筆 Other API keys 條目加入的,這會鑄出一個假的 brm_… 值,並以你選定的環境 變數名稱匯出到 VM 裡。真正的權杖留在主機上,由代理伺服器在線路上替換,而且只 針對送往你為它綁定的那一個目的主機的外送請求。代理的行程從來不曾持有它。 dotfile 與 shell 歷史也沒有。

為那筆條目開啟 Require approval to use,那麼每一次替換都會在 VM 之外、在 macOS 上跳出一個對話框,然後 Bromure 才會轉送真值。被劫持的代理可以組出一個 格式完全正確的 DNS 更新,但它回答不了那個對話框。

其餘的波及範圍有更嚴格的答案。Guardrails 是一個跑在主機代理伺服器裡的政策 引擎,會把破壞性操作從代理所使用的協定中剔除:Kubernetes、AWS、DigitalOcean、 容器登錄檔、GitHub、GitLab、Bitbucket,以及 HTTPS 的資料庫端點。你可以逐項資源 選擇 Block destructive 或 Read-only,被擋下的呼叫會回傳一個硬邦邦的 403。因為 做這個決定的是主機,所以在 VM 裡照著別人指示行事的代理,根本沒有東西可以關掉。

在開發者的筆電上日誌資料列抵達原廠 MCP 伺服器,所以值得信任沒有東西去讀文字本身權杖就擺在那裡CLOUDFLARE_API_TOKEN,有效且可用DNS 寫入送了出去而且成功而且沒有任何警報響起授權過的使用者、授權過的代理、授權過的權杖、授權過的呼叫在 Bromure 設定檔裡資料列在抵達時被評分本機模型讀的是那段文字,不是寄件者詢問,或以硬性 451 擋下權杖不在 VM 裡env 放 brm_…,真值留在主機上替換會在 macOS 跳出同意對話框而整條鏈就是一串資料列主機、狀態、延遲、替換報告逐個請求,都在 Trace Inspector 裡
同一個被劫持的代理,放在兩台機器上。在開發者的筆電上,權杖就在環境變數裡,那次呼叫直接送了出去。在 Bromure 的設定檔裡,日誌資料列在抵達時就被評分,環境變數裡只有一個佔位值,真正的權杖在同意對話框之後才由主機替換,而整段往來就是 Security Log 裡的一列。

沙箱的瑕疵搬不動一台 Hypervisor

這場演講還揭露了一個 Claude 零時差漏洞,可繞過代理的網路沙箱進行完整資料外洩, 外加由記憶體注入與設定下毒組成、任何 EDR 都抓不到的代理式 rootkit。這兩項發現 指向同一個弱點:代理隨附的圍堵機制,從內部就構得到。

Bromure 把邊界放在別的地方。 邊界是一台虛擬機,跑在 Apple 的 hypervisor 上、有自己的核心、位於 NAT 之後,每一個封包都要穿過一個在 macOS 上 執行的代理伺服器。代理行程內沙箱的瑕疵,是 VM 裡面的瑕疵。它搬不動那台 VM, 也不會給 VM 內的程式碼一條繞過主機代理伺服器的網路路徑。

而當真有東西落在那裡時,它落在一台生來就是要被丟掉的機器上。Erase home 會 抹掉 /home/ubuntu,也就是 dotfile、.sshnpm-global.cargo 與 shell 歷史,並把它重設回剛複製完的狀態。Reset to base 會丟棄所有系統層級的變更, 並從基礎映像重新複製工作磁碟。那個沒有掃描器找得到的 rootkit,依舊只是坐在一層 你刪得掉的磁碟裡。

把看不見的鏈寫下來

Tenet 最有力的觀察是:這條鏈之所以藏在光天化日之下,正因為它的每一步都合法。 沒有特徵碼,也沒有異常可供關聯。

Bromure 不打算去關聯什麼。VM 發出的每一個請求都會穿過主機代理伺服器,而 Bromure 會記下主機、狀態、延遲,以及它替換了哪些憑證。注入偵測會連同被標記的文字一起 落進 Security Log。把追蹤層級調高,Bromure 還會保留 AI 請求的內文,並用與你設定 檔密鑰相同的鑰匙圈金鑰加密。

於是你可以改問另一個問題:這次工作階段碰了什麼。一個整個下午都在讀 Cloudflare 日誌、然後第一次呼叫 DNS API 的代理,就是你讀得懂的兩行字,就在那場工作階段 執行的機器上,不需要部署任何代理程式,也不需要把它導向任何 SIEM。

Cloudflare 會調整自己的表面,Sentry 會調整他們的,週五演講裡那兩條鏈都會被補上。 但只要把任何一個會記錄敵意輸入的系統,配上任何一個會讀取記錄來完成工作的代理, 你就用兩個都在盡本分的零件,把這個攻擊重新組裝出來了。你留著日誌是為了讓人去讀, 而如今那個讀者是一支會依據所見去行動的程式。

一個直覺就夠了:把代理讀到的一切,都當成可能是陌生人寫的,包括你自己的防禦寫下 的那些部分。

安裝 Bromure Agentic Coding,在日誌與代理之間放上一個會檢查 文字的東西。