作者:BitMEX Research
摘要:64 字節長的比特幣交易可能跟區塊默克爾樹的哈希對象相混淆,因為後者也是 64 字節。我們研究了這個漏洞可以如何用來欺騙 “簡易支付驗證(SPV)” 客戶端,使它認為自己收到了一筆交易(實際上並沒有),以及這個弱點會造成的其它問題。雖然發動這樣的攻擊是非常複雜的,而且這個漏洞也不嚴重,它有一種較為簡單的修復措施,那就是在一次軟分叉中禁掉所有剝除見證數據之後長為 64 字節的交易。

概述
這篇文章屬於我們討論 BIP 54 共識清理軟分叉將修復的四個安全漏洞的系列。我們已經介紹了其中兩個安全漏洞:
在這篇文章中,我們會關注所謂的 “64 字節長的交易” 問題。其中的機關在於,在生成比特幣區塊中的默克爾樹的中間節點時,其哈希對象的長度也是 64 字節。
一筆比特幣交易的哈希值,也就是 “TXID”,是 32 字節長的。而比特幣區塊默克爾樹的倒數第二行是哈希兩個 TXID 的拼接 —— 也就是 64 字節。這個安全漏洞在於,這個 64 字節的數據(兩個哈希值的拼接)可能會跟一筆 64 字節長的交易混淆。比如說,攻擊者可以創建一筆長度恰好是 64 字節長的比特幣交易,以此來迷惑或者誘騙一個輕節點確認一筆入賬支付。我們將在下文了解這種攻擊的部分步驟。
圖解比特幣區塊中的默克爾樹

Sergio Lerner 製圖:虛假交易的位置

總體而言,我們認為,與這個漏洞相關的風險是中等乃至較低的,因為攻擊非常複雜;這與 “時間扭曲攻擊” 相反,我們認為後者更加嚴重。不過,這依然是一種有趣的漏洞,也值得修復。
將一個交易的 ID 藏在另一個交易裡
當前已知的利用該漏洞的最嚴重的攻擊形式,應該是誘騙使用簡易支付驗證(SPV)客戶端的人確認一筆無效的入賬交易。我們在下文提供了一個示意圖,總結了這種攻擊。攻擊步驟如下:
- 攻擊者創建一筆真實有效的比特幣交易,其長度恰好是 64 字節。這個數字已經排除了任何隔離在外的見證數據。
- 攻擊者再創建一筆虛假的、無效的比特幣交易,發送(比如說)1000 BTC 給受害者。比如說,該交易的 1000.002 BTC 來自一個虛假輸入,它並不存在於 UTXO 集中。
- 攻擊者為這筆虛假交易安排一個找零地址,然後使用暴力搜索,不停切換找零地址,直到該虛假交易的 TXID(32 字節長)恰好與真實有效交易(64 字節長)的後面 32 個字節完全一樣。
- 一旦找出了這樣的配對,攻擊者就可以向受害者的輕客戶端發送 SPV 證據,其中包含從真實的區塊頭默克爾樹根通向虛假交易的有效路徑。受害者會誤以為該默克爾樹的最底層是倒數第二層,下面還有一筆交易。然後,這個受害者就會認為自己收到了 1000 BTC —— 來自礦工的工作量證明被攻擊者用來欺騙受害者。當然,全節點是不會受到這種方式欺騙的(其中有很多原因),但 SPV 節點就會被欺騙。
圖示攻擊所用的兩筆交易

- 注:這種攻擊在 Peter Todd 於 2018 年 6 月 7 日出版的文章和 Sergio Lerner 在 2018 年 6 月 9 日出版的文章中分別得到了解釋 -
上面這種攻擊看起來在計算上是不可行的,因為似乎需要找到一個完整的 32 字節的 SHA256 碰撞案例。我們已經直到這在計算上是不可行的了,而且,要欺騙一個 SPV 客戶端,挖出虛假區塊(在今天,需要 2^84 次搜索)顯然要更加容易(比起用 2^256 次搜索找出哈希碰撞)。然而,這裡的機關在於,64 字節的交易是可以調整的,所以你不需要通過純粹的暴力搜索來匹配 32 字節。
64 字節長的交易的後面 32 字節的組成
| 物件 | 描述 | 長度 | 需要暴力搜索的長度 |
|---|---|---|---|
| 輸入 TXID | 一筆前序比特幣交易的哈希值。因此,它是隨機的,無法操縱。需要暴力搜索。 | 5 字節(在該字段的後半段) | 5 字節 |
| 輸入索引 | 可以先製作一筆啟動交易(作為前序交易),帶有幾千個輸出。這樣,輸入的索引號就可以操縱,以跟虛假交易碰撞(在一定程度上)。不過,這可能比較貴,而且構造起來也不容易。在現實中,在這裡可能也需要部分暴力搜索。 | 4 字節 | 0 |
| 輸入長度 | 難以操縱,因為對交易還有其它約束。因此需要暴力搜索。 | 1 字節 | 1 字節 |
| 輸出數量 | 交易只能有恰好一個輸出,否則難以恰好是 64 字節。 | 1 字節 | 1 字節 |
| 輸出價值 | 攻擊者想發送多少比特幣,就可以發送多少,只要有這麼多錢,並且做好了放棄它的準備。如果這筆交易的輸入價值 1 BTC,那麼輸出的數值就有 1 億種可能性(1 億聰等於 1 BTC)。因此,這個字段(在一定程度上)是可以操縱的。不過,可能需要燒掉 2100 萬 BTC 才能完全操縱這個字段。 | 8 字節 | 0 |
| 輸出腳本長度 | 難以操縱,因為對交易還有其它約束。因此需要暴力搜索。 | 1 字節 | 1 字節 |
| 輸出腳本公鑰 | 因為注入這筆交易的資金是無法取回的,所以這個字段可以輕鬆地自由操縱。 | 8 字節 | 0 |
| 鎖定時間 | 鎖定時間是可以操縱的,比如說表達為區塊高度,最大值為 5 億。因此這裡有大量熵。 | 4 字節 | 0 |
| 總計 | 8 字節 |
因此,基於上表,在對攻擊者最有利的情況下(用上一切能夠操縱的字段),攻擊者只需要找出 8 字節的碰撞。8 字節,或者說 2^64 次搜索,並不需要許多計算資源;普通的一臺筆記本電腦也可以很快完成。事實上,可能需要稍微高於 2^64 次,因為上面的所有字段都不是完全可操縱的。
但這種攻擊也並不像它看起來那麼嚴峻。因為啟動起來極端複雜,也許要製作一筆帶有幾千個輸出的啟動交易,還可能要燒掉幾千美元,這還僅僅獲得了能夠操縱幾個字節的熵。此外,SPV 錢包現在也不是那麼流行了。預計要收取高價值支付的人,都直到自己需要一個全節點來驗證入賬支付。不過,這種攻擊依然是可行的,尤其在工具都已齊備的情況下,因此,它值得關注,值得我們嘗試緩解風險。
默克爾根哈希值碰撞
另一個一定程度上相關的比特幣漏洞在 2012 年被發現和修復。這種漏洞在於,兩個不同的比特幣區塊,一個是有效的、另一個是無效的,可能具有相同的默克爾根哈希值。有幾種可能會造成這種局面,其中一種也涉及將一個 64 字節的中間哈希步驟與 64 字節長的交易相混淆。
問題的核心在於,比特幣節點會存儲無效區塊的區塊哈希值,從而避免再次驗證它(浪費資源)。但是,如果兩個區塊帶有相同的區塊哈希值,一個是有效區塊,另一個是無效區塊,比特幣節點(如果先驗證了無效區塊,就不再能驗證有效區塊)就可能被誘騙從具有最多工作量證明的鏈上脫離、跟隨較少工作量證明的敵對鏈。這個問題在 2012 年得到了修復,方法是讓節點在緩存無效區塊的哈希值之前,作額外的檢查。
相關的一個漏洞在 2019 年再次曝出,因比特幣開發者 Suhas Daftuar 注意到:一個相似的 bug 在 Bitcoin Core 0.13.0(發佈於 2016 年 11 月)中於無心之中再次引入,並在 2017 年 2 月再次修復。還有其它漏洞,也跟本文討論的這個問題有關;可能還有尚未發現的利用方式。
擬議的解決方案
修復這個問題不需要軟分叉,至少對於欺騙 SPV 的利用方式是不需要的。SPV 錢包所用的方法可以升級,比如,總是在跟 coinbase 交易的同一默克爾樹層級檢查交易。然而,問題在於,SPV 錢包並沒有這樣做,對這個問題的瞭解也不廣泛。因此,人們還是容易受到傷害。
當前,擬議的軟分叉解決方案是 BIP 54,其方法是完全禁止剝除了見證數據之後長為 64 字節的交易。這聽起來是非常簡單而且容易的修復。不管怎麼說,似乎沒有什麼理由要製作恰好長為 64 字節的交易。比如說,在我們上面的例子中,是把資金打進黑洞,才製作出了 64 字節長的交易。Suhas Daftuar 在 2019 年的一封郵件中指出,他掃描了整個比特幣區塊鏈,沒有發現長為 64 字節的交易。這應該會讓軟分叉更流暢、更容易獲得共識,因為它禁止的是從未發生過的事,因此是風險較小的、比較沒有爭議的。不過,到了今天,也許有一些 64 字節的交易了。
BIP54 將讓比特幣出現一條有些奇特的新規則:63 字節長的交易和 65 字節長的交易,都是有效的;唯獨 64 字節長的交易是無效的。但是,儘可能少設立對交易的禁令,應該是更好的。

