在過去一週(2026/07/27 - 2026/08/02),以下 2 起重大安全事件值得關注,合計造成約 8,800 萬美元的損失。
| 日期 | 事件 | 類型 | 預估損失 |
|---|---|---|---|
| 2026/07/29 | LULA | 業務邏輯缺陷 | ~$578K |
| 2026/07/30 | COLDCARD | 熵值生成缺陷 | ~1,370 BTC (~$88M)* |
* COLDCARD 的損失因確認方式而異:所示的約 1,370 BTC(~$88M)為可公開驗證的鏈上最低值(coldcardwatch.com);私下渠道的核對數據(Galaxy Research,來自與 73 名受害者的往來通信)顯示數字更高,約為 1,596 BTC,若加入疑似但未確認的提款,最高可達約 2,055 BTC(~$130M)。
入選原因
- LULA:一個具有特權的代幣函式可移動 AMM 交易對的餘額並強制重新同步儲備,透過價格操縱成為可重複利用的流動性抽取原語。
- COLDCARD:錢包韌體中的一個建置與整合錯誤,悄無聲息地將種子生成路由至確定性軟體備用路徑,破壞了熵值保證,並將種子恢復轉變為離線搜尋,最終演變為大規模資金損失。
Web3 最佳安全審計機構
在上線前驗證設計、程式碼與業務邏輯
本週重點:COLDCARD
我們選擇 COLDCARD 作為本週重點,因為一個錢包熵值漏洞造成了本期最大損失。根本原因是一個建置防護機制僅檢查設定巨集是否存在,而未檢查其是否已啟用,這類無聲的整合錯誤是功能測試無法發現的,其教訓適用於任何鏈上安全性依賴鏈下隨機性的系統。
COLDCARD 是一款比特幣硬體錢包,其於 2021 年發布的韌體使用確定性軟體來源而非預期的硬體隨機數生成器(RNG)來生成錢包種子 [1][2]。該缺陷直到 2026 年 7 月下旬才遭到大規模利用,受影響的錢包於 7 月 30 日起在鏈上被分批清空:公開確認的損失合計至少 1,370 BTC(按 8 月 5 日 $64,099 的價格計算約合 $88M)[3],而私下確認的報告則顯示數字高達約 1,596 BTC [4]。根本原因是一個建置與設定錯誤,將種子生成路由至軟體備用路徑,而非預期的硬體 RNG。對於受影響的設備而言,這使種子恢復從一個在密碼學上不可行的問題變成了離線搜尋。
背景
COLDCARD 是一款比特幣硬體錢包。錢包的私鑰和地址均源自單一秘密值——其種子,因此任何自我保管錢包的安全性都依賴於該種子的兩個特性:保持秘密,以及在生成時不可預測。硬體錢包的存在主要是為了保護第一點;而本次事件是第二點的失敗。BIP-39 助記詞是人類可讀的,但不可預測性要求背後的安全屬性,仍然是用於創建它的隨機位元組的熵值。如果這些位元組可以被重現,種子就可以被重現。直觀的比喻是:一個保險箱的密碼由擲骰子決定——如果骰子被動了手腳,那麼任何知道偏差的人都能打開保險箱,無論鎖有多堅固。
對於錢包來說,「被動了手腳的骰子」意味著弱隨機數生成器。硬體錢包預期從其安全微控制器上的硬體真隨機數生成器(TRNG)獲取種子熵值,因為軟體偽隨機數生成器(PRNG)是確定性的:給定其內部狀態和呼叫歷史,其輸出可以被精確重現。如果生成器的輸出是可預測的,其候選範圍就可以被枚舉,並與公開的錢包數據(如地址、xpub 或公鑰)進行匹配,從而將種子恢復從密碼學上不可行的問題簡化為離線搜尋。
COLDCARD 的韌體暴露了兩個獨立的 RNG 介面。MicroPython 提供了一個 STM32 平台層,暴露了錢包加密庫所需的全域 rng_get() 符號,而 COLDCARD 也維護了自己的板載本地硬體 RNG 封裝。兩個介面均旨在提供硬體熵值,錢包的加密庫透過韌體建置時解析的單一全域 RNG 符號來呼叫其中一個。
漏洞分析
根本原因是圍繞 MICROPY_HW_ENABLE_RNG 設定巨集的建置與整合錯誤。COLDCARD 的生產板設定將此巨集設為 0,因為韌體打算使用自己的板載本地硬體 RNG 封裝,而非 MicroPython 的硬體 RNG 實作。然而,錢包生成路徑已遷移至 ngu.random.bytes(32),而加密庫的 STM32 路徑最終依賴於由 MicroPython 解析的全域 rng_get() 符號。
問題鏈如下:
generate_seed()
-> ngu.random.bytes(32)
-> libngu CHIP_TRNG_32()
-> rng_get()
-> MicroPython STM32 RNG 模組
-> 因 MICROPY_HW_ENABLE_RNG == 0 而使用 Yasmarang 軟體備用路徑
板設定停用了 MicroPython 的硬體 RNG 分支:
// We have our own version of this code.
#define MICROPY_HW_ENABLE_RNG (0)
加密庫仍將此巨集視為硬體 RNG 存在的充分證明 [5],因為它在呼叫 rng_get() 之前僅檢查巨集是否存在:
extern uint32_t rng_get(void);
#define CHIP_TRNG_32() rng_get()
#ifndef MICROPY_HW_ENABLE_RNG
#error "get a HW TRNG plz"
#endif
此防護機制遺漏了危險情況:被定義為 0 的巨集仍然是已定義的,因此 #ifndef 檢查通過,建置成功。由於 MicroPython 根據巨集的值而非其存在來選擇 RNG 實作,MICROPY_HW_ENABLE_RNG == 0 將 rng_get() 路由至軟體備用分支,而非 COLDCARD 的板載本地封裝 [6]:
#if MICROPY_HW_ENABLE_RNG
// STM32 硬體 RNG
#else
// Yasmarang 軟體備用路徑
#endif
不同設備世代的後果有所不同。對於 Mk2/Mk3 韌體 v4.0.0-v4.1.9,Block 的分析 [7] 指出,沒有任何密碼學熵值被加入 ngu.random,因此一旦備用狀態和呼叫歷史已知,錢包生成即可變為確定性的(Coinkite 的公告 [2] 將 Mk2/Mk3 的範圍稍作縮小,定為 v4.0.1-v4.1.9)。對於 Mk4/Q/Mk5,安全元件的素材雖被雜湊處理,但傳入 ngu.random.reseed() 的僅有四個位元組,將安全重播種限制為單一 32 位元狀態字,遠少於使用者預期的錢包熵值搜尋空間。對最終的 32 個隨機位元組進行雜湊無法增加結果的熵值;它只是對一個本已受限的候選集合進行了轉換。
攻擊分析
與智能合約漏洞不同,本次事件沒有單一的鏈上攻擊交易可追溯。這是一個離線種子恢復問題,隨後才出現鏈上清空。前提條件是受影響的用戶透過存在漏洞的 ngu.random.bytes(32) 路徑生成了其錢包種子,因此其種子素材依賴於可重現的軟體備用狀態,而非完整的硬體熵值。第二個推斷的前提條件是受影響的錢包可僅從種子推導:一個強而唯一的 BIP-39 密語通過 PBKDF2 混入了獨立的、用戶提供的熵值,而 RNG 缺陷從未觸及這部分,使此類錢包超出了純種子枚舉的範疇;清空的規模表明大多數受影響用戶未設置此類密語。此後,恢復過程可能分三步進行:
- 攻擊者利用設備元數據、啟動時序、RTC/SysTick 假設以及合理的 RNG 呼叫歷史,對候選 RNG 狀態進行約束或枚舉。
- 對於每個候選狀態,攻擊者推導出候選錢包種子,並離線與公開錢包數據(如地址、xpub 或生成的公鑰)進行比對。
- 一旦某個候選項與真實錢包匹配,攻擊者即恢復種子,重建私鑰,並清空相關的 BTC。
在鏈上,盜竊表現為從 7 月 30 日開始的一波地址清空。獨立的鏈上啟發式追蹤 [3] 識別出數波提款,合計至少 1,370 BTC(按 8 月 5 日 BTC 價格 $64,099 計算約合 $88M),從 4,580 個已驗證地址中清空,這是已驗證的最低值而非總計。同時,一個私下渠道 [4](透過與 73 名受害者的通信確認)顯示數字高達約 1,596 BTC,若加入疑似但未確認的提款,則上升至 2,055 BTC(~$130M)。
結論
COLDCARD 事件是一次熵值生成失敗:安全關鍵的種子生成 API 悄無聲息地解析到確定性軟體 PRNG 備用路徑,而非預期的硬體 RNG,原因是建置防護機制僅檢查設定巨集是否存在,而未檢查其是否已啟用。對於受影響的設備,這使種子恢復從密碼學上不可行的問題變成了離線搜尋,結果是超過 1,370 BTC [3] 在多波攻擊中被清空(私下渠道的統計數字為約 1,596 至 2,055 BTC [4])。
核心工程失敗在於:已發布的韌體從未驗證其最關鍵的安全 API 是否真正連接到預期的硬體 RNG。以下三個實踐本可發現此問題:密碼學熵值的建置防護必須同時檢查巨集的存在及其值;熵值備用路徑必須以失敗關閉(fail closed)而非悄悄替換為軟體 PRNG;以及最終韌體映像的驗證應涵蓋符號來源和端對端熵值流,而不僅僅是程式碼能否編譯。受影響的種子無法就地修復;其資金應移至使用修復韌體創建的新錢包,而一個強而唯一的密語可在不修復種子的情況下降低立即風險 [2]。
這種失敗模式值得特別強調:此類隨機性漏洞對功能測試而言是不可見的,因為每個生成的種子單獨來看都是有效的。缺陷不在於任何單一輸出,而在於產生它們的來源:由於該來源是可預測且可重現的,這些種子整體上落在一個小而可枚舉的範圍內。鏈下金鑰生成元件理應獲得一流的安全審查。
參考資料
- [1] BlockSec Phalcon 將 COLDCARD 錢包清空事件與弱種子生成隨機性相關聯的警報
- [2] Coinkite,熵值問題技術深度解析
- [3] coldcardwatch.com,Coldcard 清空監測:鏈上已清空地址追蹤與方法論
- [4] Galaxy Research,COLDCARD 駭客攻擊損失估算(透過受害者報告確認約 1,596 BTC)
- [5] libngu,STM32 RNG 路徑引用全域
rng_get()並僅以#ifndef MICROPY_HW_ENABLE_RNG進行防護 - [6] Coldcard MicroPython,當硬體 RNG 被停用時,
rng_get()回退至 Yasmarang - [7] Block Engineering,COLDCARD 韌體中的可預測 RNG 備用路徑與 32 位元重播種問題
本週更多事件
LULA
LULA 是 BNB Chain 上的一個 BEP-20 代幣,於 2026 年 7 月 29 日因其代幣合約中的業務邏輯缺陷損失約 $578K。攻擊者可觸達的路徑能夠觸發其特權 recycle() 函式,使 Rental 合約直接從 PancakeSwap V2 交易對中轉移 LULA,然後呼叫 sync(),將交易對的儲備更新為被操縱的餘額。攻擊者反覆觸發 recycle(),將交易對的 LULA 儲備縮減至接近零,然後用少量 LULA 換回幾乎全部的 USDT [1]。
背景
LULA 是 BNB Chain 上的一個 BEP-20 代幣,具有基於租賃的團隊獎勵機制。符合資格的地址在 Rental 合約中累積待領取的團隊獎勵,並透過 claimTeamReward() 進行領取。在領取流程中,Rental 合約呼叫代幣的 recycle() 函式以獲取 LULA 用於獎勵分發。recycle() 無法被任意用戶呼叫;只有 Rental 合約被授權執行它。
claimTeamReward() 入口點包含一個「僅限 EOA」的檢查。它支援來自外部擁有帳戶的直接呼叫(其中 msg.sender == tx.origin),也支援透過檢查委託程式碼前綴來處理 EIP-7702 委託呼叫。

在自動做市商(AMM)上,交易對根據其儲存的儲備對兌換進行定價,這些儲備透過交易對的 sync() 函式更新,該函式將儲備設為交易對當前的代幣餘額。儲備通常因兌換和流動性事件而隨真實交易移動,但交易對的代幣餘額也可透過直接轉帳來改變,而 sync() 會將當時存在的任何餘額——無論是否被操縱——複製到儲存的儲備中。
漏洞分析
根本原因在於 LULA.recycle() 允許 Rental 合約直接從 PancakeSwap V2 交易對中轉移 LULA,然後呼叫 sync(),將交易對的儲備更新為被操縱的餘額 [1]。

由於 sync() 將儲備設為交易對中剩餘的任何 LULA 餘額,此特權路徑可將交易對的 LULA 儲備任意壓低,同時保持 USDT 一側不變。一旦 LULA 儲備接近零,交易對便將少量 LULA 定價為幾乎等值於其全部 USDT。
攻擊分析
以下分析基於交易 0xa219ab9...411d7c。
- 步驟 1:攻擊者透過累積約 1.97 億 USDT 為操縱提供資金。資金來自多個閃電貸和借貸來源,包括 Moolah/Lista、Aave V3、Venus、PancakeSwap V3、PancakeSwap Vault、Uniswap V4 PoolManager 和 Uniswap V3。
- 步驟 2:攻擊者使用約 1.97 億 USDT,透過 PancakeSwap V2 路由器執行了一筆大型
USDT -> LULA兌換。這使交易對的 LULA 儲備從約 800 萬 LULA 急劇降至 24,022 LULA,同時 USDT 一側增加至約 1.9764 億 USDT。 - 步驟 3:攻擊者透過多個 EIP-7702 錢包觸發獎勵路徑。每個錢包在 Rental 合約上呼叫
claimTeamReward(),後者隨即觸發LULA.recycle(),將交易對的 LULA 儲備從 24,022 LULA 縮減至 0.004 LULA,而交易對的 USDT 一側仍持有大量 USDT。 - 步驟 4:攻擊者透過路由器執行最後一筆 PancakeSwap V2 兌換,僅向交易對發送約 4,749 LULA,並取回約 1.9764 億 USDT。
- 步驟 5:攻擊者償還所有閃電貸,獲利約 $578K。
結論
BNB Chain 上的 LULA 代幣因其代幣合約中的業務邏輯缺陷被利用,損失約 $578K:攻擊者可觸達的路徑能夠觸發其特權 recycle() 函式,使 Rental 合約直接從 PancakeSwap V2 交易對中轉移 LULA,然後呼叫 sync(),將交易對的儲備重新同步為被操縱的餘額。攻擊者反覆觸發此操作以扭曲交易對的價格,並用少量 LULA 換回幾乎全部的 USDT。
代幣合約絕不應暴露能夠移動 AMM 交易對餘額並強制重新同步儲備的特權路徑,因為這樣做會將價格控制權交給任何能夠觸達該路徑的人。與 AMM 交易對整合的代幣必須確保交易對的儲備只跟隨真實的、由市場驅動的餘額變化,任何讀取池儲備進行定價的邏輯都應將其視為可被操縱的,而非權威的。



