針對 Bybit 多簽冷錢包遭駭,造成史上最大規模竊案的攻擊發生原因,本文源自 BSOS Labs 區塊鏈資安研究員,為您深入剖析攻擊手法、影響與安全啟示。
(前情提要:V神喊「多簽+冷錢包最安全」被駭客打臉,專家:Bybit案衝擊大量機構、資安整頓期或達半年 )
(背景補充:Haotian:Bybit 被駭的 15000 cmETH 為何能救回? )
Bybit 近日遭受一起涉及 15 億美元的駭客攻擊,此事件引發了區塊鏈安全社群的廣泛關注。駭客成功滲透 Bybit 的多簽冷錢包,並透過某種方式竄改或利用既有的安全機制,將大額資產轉移至不明地址。
這次攻擊不僅對 Bybit 造成了巨大的財務損失,也對多簽錢包的安全性提出了新的挑戰。本文由 BSOS Labs 區塊鏈資安研究員撰寫,將深入剖析該攻擊事件的技術細節,包括 Bybit 所使用的多簽架構、攻擊者的手法,以及此次事件帶來的安全啟示。
事件背景
Multisignature Wallet
在以太坊的區塊鏈設計中,有兩種類型的帳號,一個是 EOA 帳戶 (Externally Owned Account),另一種是合約帳戶 (Contract Account),Bybit 在這次事件中用來進行資產管理的多簽冷錢包,就屬於後者。這個錢包其實是一份智能合約,透過程式來自定義一些商業邏輯。在多簽帳戶的設計中,當這個錢包收到外部傳進來的資產後,如果想要進行提取或是任何使用上的操作,則必須要通過這個多簽錢包所設定的一些門檻,才能夠實際執行。
一般用戶可以把 Safe Wallet 想像成是一個公司的金庫,而這座金庫內由公司的董事們共同進行管理,當公司董事想要提取金庫資產時,或是利用這些資產去進行外部投資時,他們必須要先通過以下的流程:
- 董事會內部先提案,決定未來要使用的資金金額,目標以及要執行的操作
- 董事會的成員針對這個提案進行簽署,當簽署人數超過門檻數值,才能實際執行
舉例來說,一個 5 取 3 的多簽錢包,總共會有 5 個董事,我們稱之為 Signer,這些 Signer 可以首先發起提案,提案對應多簽錢包的名詞是 Transaction,也有一派說法是 Proposal,避免與區塊鏈的 transaction 混淆。
而這個提案可以是簡單的轉送 ETH / ERC-20 到其他帳戶,也可以是進行一些較為複雜的 DeFi 操作。接下來這些 Signer 針對這些 Proposal 進行簽署,表示同意這份提案,過程中會產生一個 Signature 做為憑證。當有效的 Signature 數量大於 3 後,用戶可以呼叫 Safe Wallet 的 executeTransaction 操作並且提交這些 Signature,當驗證完這些 Signature 確實是由認證的 Signer,也就是該金庫的董事們簽署之後,就會實際的去執行當初 Proposal 的內容。

簡單的流程如上圖所示,首先有 Signer 0 去提交一份 Proposal,然後由 Signer 2, 3 確認過 Proposal 沒有問題之後進行簽署,通常提交 Proposal 的人會同時進行簽署,所以此時已經拿到 3 個 signature,符合這個多簽錢包設定的門檻。這時就可以執行這份 Proposal 的內容,在 Safe 前端的設計,如果你簽署的時候剛好符合門檻,系統會詢問你是否要簽署後一起執行,你可以選擇 Yes,或是選擇 No,然後讓別人來幫你執行,差別則是在誰來付這個 gas 的費用。
Proxy Pattern
以上是透過 Safe Wallet 的介紹來初步了解多簽錢包的運作,我們接著看 Safe 的合約設計。上述所提到的邏輯,有很大一部分是寫在該智能合約中的,有興趣的話,可以參考 Safe Wallet 的主合約實作:https://etherscan.io/address/0x34cfac646f301356faa8b21e94227e3583fe3f5f#code
這份合約並不複雜,程式碼的數量也沒有很大,但是如果每次要創建 Safe 錢包時,都必須要部署一份這樣的合約,是非常消耗 Gas 的,所以 Safe 採用了 Proxy Pattern 來降低成本。要注意的是,這裡是指 Proxy Pattern 而非 Upgradeable Proxy,跟常見的 Transparent Proxy 與 UUPS Proxy 不太一樣,這裡沒有預設升級的行為。具體的運作原理比較像 EIP-1167 中的 Minimal Proxy。

當每次使用者創建 Safe 錢包時,一份 Proxy 就會被創建,這份 Proxy 的程式非常精簡,基本上只會利用 Delegatecall 呼叫主合約,呼叫的資料則是用戶和 Proxy 互動時的 data。所有的商業邏輯都在主合約 0x34Cf…3F5F 之中,但是因為 Delegatecall 的特性,每份 Proxy 的狀態 (如 token balance 等) 是分離的,如上圖。這樣的設計,不會因為只有單一一份主合約而造成大家資產混在一起。
簡單來說,這個 Proxy 透過 Delegatecall 呼叫主合約,使用主合約的商業邏輯來修改自己 Proxy 本身的狀態,例如 token transfer 等操作。
在 Bybit 的事件中,一樣有 Proxy 和主合約兩個地址,都是在以太坊主網區塊鏈上。
- Proxy: 0x1Db92e2EeBC8E0c075a02BeA49a2935BcD2dFCF4
- Safe Wallet: 0x34CfAC646f301356fAa8B21e94227e3583Fe3F5F
我們接著來實際看一下這份 Proxy 的程式,你會發現有一個 masterCopy
的 address 變數 (L#14),這個數值在合約創建時 (詳見合約的 Constructor
, L#18) 就會設定一次 ,這個數值的初始數值此時是主合約 0x34Cf…3F5F,而 function()
(L#26) 則是會將用戶傳進來的 data 都透過 assembly 區塊內的 delegatecall
(L#39) 都一起傳送給主合約。
NOTE: 熟悉 Solidity 的讀者可能會對 function()
感到比較陌生,但其實這就是 Solidity 0.5.0 版本的 fallback
。
我們接著看一下主合約 execTransaction
的實作,這個函式傳入了很多參數,但比較重要的是:
to
: 多簽要互動的合約地址value
: 要傳送的 ETH 數量data
: 要對to
地址呼叫時所要傳送的data
operation
: 不同操作的模式,在Safe
內支援call
和delegatecall
signature
: 各個Signer
簽署之後的 Signature
這裡再稍微說明一下運作流程:
- L#25–32 透過
encodeTransactionData
和keccak256
還原出當時 Signer 簽署的 Digest - L#33 驗證該 Signature 是否為該多簽的 Signer 所簽署,並確認是否超過 Threshold
- L#40 實際執行 Transaction 的資料,底層是使用 low-level 的 call 或是 delegatecall
如果 Operation 是 0 的話,程式邏輯大概如同以下:
(bool success, ) = to.call{gas: gas}(data);
require(success, "transaction execution failed");
Attack Transaction
那這次的攻擊跟上述到底有什麼關聯呢?根據 Bybit CEO 的說法,他們在簽署多簽錢包的 Proposal 時,是希望可以把多簽冷錢包中存放的一些資產,轉移到熱錢包,這本來只是一次例行性的資產轉移,他們在簽署過程中,有檢查過 Safe 錢包網頁是正確的,且轉移的地址等資訊也是正確的,也就是說他們對於這份 Proposal 是有全面性的審核過才簽署並執行的。
然而實際檢驗執行的 Transaction,會發現一些奇怪的地方。以下是這個 Transaction 執行時的參數片段,你可以發現 value 為 0,而 data 並非 null 數值。根據我們上述的討論,value 應該是用來定義傳送 ETH 數量的一個數值,但是這裡卻是 0。一個常規 ETH 的轉移,根本不需要 data 的資料。
那如果不是 ETH 的轉移,而是像 WETH 或是 stETH 等 ERC20 的轉移呢?這樣 value 為 0,data 非 null 的情況就合理了。透過解析 data 的前 4 個 Byte 所代表 function selector,我們可以用這個資訊還原出 function signature,試圖理解 data 想要執行的操作為何。

把 0xa9059cbb
丟到 function signature database,可以查到以下資訊,確實 ID 145 這個 function selector 是 ERC-20 的 transfer 操作。

而且 decode 了這個 data 的剩餘部分,參數也如同 ERC-20 的 Transfer,有 to (address) 和 amount (uint256)。所以這裡偽裝的很好,沒有確切檢查 data 可能會被 function selector 騙了。

但是這裡奇怪的是,如果只是要進行 ETH / ERC-20 的移轉,我們大可以用 call (Operation = 0) 來執行就好,但是這邊的 Operation 數值為 1 (見圖三),代表用了 delegatecall。綜合我們前面對於 Proxy Pattern 的理解,這個操作等同是 Proxy 合約使用 to 合約 (0x9622…C7242) 的邏輯,來修改 Proxy 自身的狀態。
透過 Dedaub 等逆向工具觀察 0x9622…C7242 這份合約,我們可以看到這份合約有一個 transfer 操作 (L#15) 但跟 ERC-20 的 Transfer 一點關係都沒有,他只把傳進來的 recipient 參數指定給了 _transfer 這個變數 (L#07)。

為了方便起見,我們把此時的 to 地址 0x9622…C7242 稱為 Malicious Contract,那為什麼這邊要將 _transfer
這個數值指定成 recipient
這個參數?我們將整個運作邏輯攤開來看,流程會像以下這樣:
- Signer 簽署後要執行操作,此時 Safe 會向 Proxy 合約呼叫 execTransaction
- 這個操作會透過 Delegatecall 傳送到 Safe 的主合約,執行 execTransaction 的邏輯
- 在 execTransaction 的邏輯中,又對 to 地址用 Delegatecall 進行呼叫,觸發 transafer 操作,這個 Transfer 操作修改 _transfer 的數值
簡化這一連串的 Delegatecall 後,目前的操作就是 Proxy 使用 Malicious Contract 的邏輯,來對 Proxy 本身的狀態進行修改。此時在 Malicious Contract 修改的 _transfer 變數位於 Storage Layout 的 Slot 0,那相對應更改到的就是 Proxy 合約 Storage Layout 的 Slot 0。根據圖三,這個數值就是 MasterCopy 的數值。

上述的流程圖,其實也可以呼應在 Phalcon 呈現出來的 invocation flow

當 MasterCopy 被修改後,以後 Signer 對 Proxy 合約進行呼叫,執行 Delegatecall 的對象將不再是 Safe 的主合約,而是後來設定的 0xbDd0…9516 地址,也就是傳入的 recipient 的地址。

繼續逆向 0xbDd0…9516 這份合約,可以看到兩個操作,一個是 sweepETH 的 function。在 L#18 執行 call 把 ETH 轉送到 receiver 的地址。

以及 SweepERC20,在 L#35 可以看出,這裡在做 ERC-20 的 Transfer,會把合約內所有的 Balance 都做一次性的移轉。

所以 Bybit 內部不小心在 execTransaction 更新了 MasterCopy 的地址後,後面的 sweepERC20 與 sweepETH 的操作就是這麼來的,這些 Transaction 才是真正把資產進行轉移的操作。

Blind Signing
所以,整起事件的根本原因是 Bybit 在進行多簽錢包簽署時,未對 Safe 的數值進行檢查嗎?如果當時對參數中的 Operation 數值以及其他關鍵地址資訊進行驗證,是否能夠及早識別異常操作,進而阻止這次攻擊的發生?
這起案件仍存在許多疑點。首先,該多簽提案是由誰發起的?其他 Signer 是否有仔細核對提案內容,包括 Safe 前端的 URL 等重要資訊?是否可能已有 Signer 的私鑰洩漏,導致整個系統面臨嚴重的安全風險?
根據 Bybit 的說法,其聯合創辦人兼 CEO Ben 在簽署過程中,確實檢查了 Safe 的網址及實際參數資訊。然而,冷錢包簽署時顯示了一串亂碼,這是否意味著 Safe 的前端網站已遭到駭客篡改?目前,Safe 官方已暫時關閉前端服務,以進一步釐清事件經過。
另一種可能性是 Bybit 的電腦遭到入侵,導致顯示的畫面並非 Safe 官方介面,而是駭客精心偽造的頁面。這種情況並非不可能,早在 2024 年 10 月 16 日的 Radiant Capital 事件中,就發生過類似的攻擊手法:Radiant Post-Mortem。
Radiant 也使用 Safe 的多簽錢包,當時三位資深工程師透過硬體冷錢包進行簽署,並在簽署前使用 Tenderly 模擬 Transaction 的結果,依照內部嚴格的 SOP 進行檢查。然而,在簽署與執行的過程中,MetaMask 彈出了錯誤訊息,要求重新簽署。
這種情況並不罕見,Transaction 執行過程中,因 Nonce 或 Gas 相關問題導致失敗,往往需要重新執行。然而,正因這類操作過於常見,當錢包彈出重新簽署請求時,工程師未再次驗證 Transaction 的具體內容,最終落入駭客的圈套。
那我們應該如何預防?還是這類攻擊防不勝防?
其實,在這幾起事件中,朝鮮駭客主要利用的仍然是人性的弱點。我們可能下意識地認為自己已經對這些操作非常熟練,因此容易掉入陷阱。
為了降低風險,我們可以將多簽錢包的操作環境與其他設備隔離,確保每次簽署時都能夠仔細驗證 Payload。如果發現 Safe 與 Ledger 之間的資訊存在任何異常,應立即停止操作,並確保私鑰的安全存放。
建立起一定的 SOP 流程並每次嚴格遵守,確保每個階段都符合規範,還是能有效防範這些事件的發生。
Conclusion
雖然 Web3 因爲 Bybit 事件蒙上了一層陰影,安全性不足與高風險的印象似乎揮之不去,但是相信在這些事件頻發的背後,會讓大家更加重視 Operation Security,對於私鑰管理和簽章的教育與認知會再更加深入。
回顧過往,2021 年至 2023 年間駭客事件頻傳,動輒幾週就會出現百萬級別損失的智能合約漏洞,但是也讓行業逐漸重視安全開發與審計的重要性,Bug Bounty 的制度也更加明確。在實際部署之後監控的系統也越加完善。

因此,在文章的結尾,我們可以用相較樂觀的態度看待未來產業的發展。這些看似簡單卻造成重大損失的事件,隨著產業逐步成熟,將會逐漸減少,並且損失也將隨之降低。
📍相關報導📍
Bybit竊案》Elliptic:北韓駭客用混幣器洗錢下一步:支付商+OTC大規模凍結要來了