Bitcoin Core 0.7ms 的代價

細說CVE-2018–17144的來龍去脈

Nomed Emag
7 min readSep 27, 2018

前言

Bitcoin Core 在 2018/09/18 時緊急發布了新版本 0.16.3,並在其中提到:

We highly recommend users of all affected versions immediately upgrade to 0.16.3.¹

區塊鏈圈無不掀起一波討論,當然各式媒體也相繼報導;最聳動的莫過於這句話:

康奈爾大學教授 EminGünSirer 表示,估計只需不到 8 萬美元的成本(12.5 枚比特幣)就能癱瘓整條比特幣區塊鏈。²

事情真有這麼可怕?癱瘓整條鏈?只要八萬美元?

秉持著工程師精神,追根究柢找了一些資料終於瞭解整件事情的前因後果,就讓我娓娓道來。

前因

Bitcoin Core 身為元老級的 bitcoin 用戶端(Bitcoin 的其餘分支也師承此 source code),算得上是 open source 界經典範例。擁有五百個以上的全球貢獻者時時都為 Bitcoin Core 上 pull request,有的為了修正 bug,有的為了提升效能。

那現在我們就要回到 2016/11 的 pull request #9049³:

Benchmark results indicate this saves about 0.5–0.7ms during CheckBlock.

這個 PR 提高了CheckBlock的效能,主要是做了以下的 change:

// Check for duplicate inputs — note that this check is slow so we skip it in CheckBlock
Code Snippet for PR#9049

簡單來說,礦工們會無所不用其極地節省各式計算的時間,以期在挖礦時確保能挖的比別人快。所以這個 PR 的用意在於,想要在 CheckBlock 時略過檢查於 transaction 中是否有兩個相同的 input,以節省時間。(檢查的方式算是蠻暴力的,利用 std::set::count 與 std::set::insert 來檢查是否有重複,時間複雜度為 O(n log n))

其實,有沒有相同的 input 是一個非常重要的檢查,意義在於避免雙花(double-spending);當初此 PR 作者群認為,每個 transaction 在上到 mempool 的時候,就應該做過檢查了,所以當 block 上鏈後,照理說事後應不需多花這個計算時間重複檢驗。

後果

But,就是這個 but ,在將近兩年後的 2018/09/17 ,這段 comment 被一位 Bitcoin Cash/Bitcoin Unlimited 的開發者 Awemany 於開發時無意發現⁴,於是做了一些實驗,製造出具有相同的 input 的 transaction,來測試 Bitcoin ABC (Bitcoin Cash 的 client),居然遇到了 assert() 程式直接 crash ,當他轉而測試 Bitcoin Core 也得到相同結果(這並不意外,Bitcoin 子子孫孫的原始程式大多都從 Bitcoin Core fork 出來),這時候 Awemany 就知道不太妙了,開始做後續通報的動作。

bitcoin/src/validation.cpp code snippet
Assertion failure point 在CheckBlock()之後的鏈結區塊ConnectBlock()。
而其中之 UpdateCoin() 會檢查 input 是否有被重複 spend,若有則 assert()。

Bitcoin Core 團隊迅速的於24小時內提出修正並釋出新版本⁵。Fix 非常簡單,就是把原本於CheckBlock() 的duplicate inputs重新打開…⁶

這件事情為什麼是個區塊鏈圈大新聞,這邊歸納為以下幾點:

  1. 影響範圍廣大:許多區塊鏈實作受到影響,尤其是從 Bitcoin 分叉出來的,除了上述的Bitcoin Cash、Bitcoin Unlimited 外,Litecoin 也受其影響。
  2. 可能引發嚴重後果:普通程式異常關閉雖然是我們生活中的日常,但在區塊鏈的世界中卻是一件大事。礦工利用程式挖礦,以建立共識並確認交易;當程式異常關閉(而且是一直關閉),就不會有礦工可以幫交易做確認,整條區塊鏈可以算是癱瘓;更嚴重的是,只要駭客成功算出一個包含有重複 input 的區塊放到鏈上,會成為一種阻斷服務攻擊(DoS),可以大大的降低整體算力,使 51% 攻擊更容易成功,進而修改區塊鏈上的資料。
  3. 修復是一個緩慢的過程:P2P 世界中,成千上萬的節點需要被更新,這不是像按一個按鈕就可以完成的。截至 9/24 修正釋出的一個禮拜後,Bitcoin 全網仍有 87% 的節點受此 CVE 影響⁷。(真的是87%….)

反思

理解了來龍去脈,回到最前言的部分,到現在為止我們已經知道了為什麼大家認為這是一個(目前)史上最嚴重的 Bitcoin bug,會使整條鏈癱瘓。

但讓我再次引用 INSIDE 文章的某一段文字:

康奈爾大學教授 EminGünSirer 表示,估計只需不到 8 萬美元的成本(12.5 枚比特幣)就能癱瘓整條比特幣區塊鏈。²

那個 8 萬美元的成本(12.5 枚比特幣)到底是怎麼算出來,一直困擾著我。查閱了 Bitcoin Core 0.16.3 的 release note 後發現:

Such blocks are invalid, so they can only be created by a miner willing to sacrifice their allowed income for creating a block of at least 12.5 BTC (about $80,000 USD as of this writing)

原來國內外媒體一直引用的 8 萬美元的成本(12.5 枚比特幣)就可以癱瘓 Bitcoin 的這句話是有一些誤解的。

原意其實是指:攻擊者先必須真正的算出合法的 hash ,才可將不合法的交易包入區塊中,進而達成攻擊。

反過來說,攻擊者等於是放棄了這 12.5 枚比特幣挖礦獎勵(時下匯率換算約八萬美元),來達成攻擊,因為包含了不合法的交易之區塊絕對不會被其他礦工承認。

所以真正要成功完成攻擊,成本絕對是遠高於所謂的 8 萬美元

(cryptoglobe 文章中提到,crypto51 已經成功預估出於 Bitcoin Private (BTCP) 網路上,只需 $122 美金即可達成 51% 攻擊⁸,不過目前還找不到相關佐證文件)

另一個反思則是,區塊鏈世界強調去中心化,但吸引眾多使用者的交易所、共用的智能合約與區塊鏈全網使用的相同程式,再再的打破去中心化的概念,只要任何一點被攻破,都是重大的損失,這樣還算是真正的去中心化嗎?

--

--