XVG 惡意挖礦事件透視:「算力優勢+時間劫持」攻擊案例分析

安全 挖礦 技術 鏈聞研究院 2018-07-24

鏈聞 ChainNews:

本文針對 XVG 的數字貨幣幣價翻漲的攻擊事件進行分析,攻擊者主要利用自己算力的優勢偽造時間戳,使得自己挖礦難度不斷降低,從而保持自己最長鏈的優勢,讓正常的礦池挖到的都是孤塊,通過「作弊」挖礦的方式去獲利。根據 XVG 黑皮書的描述多種加密算法可以預防 51% 算力攻擊,通過這次安全事件我們知道世事無絕對,攻擊者根據代碼邏輯構造的一系列組合攻擊利用還是可以進行成功攻擊的,目前而言,51% 攻擊對於 pow 機制的加密貨幣來說還是一個逃不開的話題。

來源 | 巴比特技術指南

作者 | 360 埃癸斯實驗室

1. XVG 挖礦異常事件簡要回顧

最近幾天,一個叫 XVG 的數字貨幣在普遍都不太好的幣市中大出風頭,短短几天之中,幣價翻了好幾倍,但前段時間,一起安全事件讓 XVG 的開發團隊和持有它的礦工出了一身冷汗。 4 月 4 日,bitcointalk 論壇上 ID 為 ocminer 的用戶發帖反饋 XVG 遭到 51% 攻擊。據反饋自 XVG 區塊高度 2007365 之後,出塊時間變得很快,在某些塊高度上面,甚至是一秒出一個塊,並且這些區塊都是利用 scrypt 算法挖到的,如圖一所示。


(圖一)

在 ocminer 發帖之後的一段時間裡,起初 XVG 的開發團隊並不認為這是一次攻擊事件,並安撫大家不要太焦慮,但是隨著事件的發酵,很多礦池已經無法正常工作了,開始不斷挖到孤塊,正常情況下,礦池一天挖到的孤塊數量不會太多,連續挖到孤塊的情況更不太可能發生,如下圖所示,自從 4 月 4 號 13 點 54 開始,挖到的塊都是孤塊,因此礦池決定暫停 XVG 的挖礦服務。隨後 XVG 開發團隊開始響應這次事件,對於代碼進行了兩次 patch,這樣才讓這次安全事件漸漸平息下來。


(圖二)

雖然這次事件並沒有讓 XVG 的幣價一蹶不振,但是背後還是有些問題值得安全從業者去研究的,其一,這到底是不是一次有預謀的攻擊事件?其二,如果是,攻擊者到底如何實施攻擊的?其三,XVG 的團隊為何要進行兩次 patch?下文會一一為大家解答這幾個問題。

2. XVG 簡介和挖礦安全事件分析

2.1 加密貨幣 XVG 簡介


(圖三)

XVG 又名 verge,是基於比特幣技術的開源加密貨幣,主打匿名性,與門羅,達世類似。XVG 最初是在 2014 年推出的,由於快速增長的社區,這個數字貨幣迅速流行,並不斷吸引世界各地的用戶前來投資。 XVG 的挖礦算法有 Scrypt/X17/lyra2rev2/MYR groestl/blake2 s 這 5 種,並且出塊時間僅為 30 秒,大大小於比特幣的 10 分鐘。因為支持的算法多,可以使更多礦工能夠挖到 XVG 幣,從而確保每個人都有平等的機會獲取 XVG 幣。 在生成新塊的時間戳校驗方面,XVG 是借鑑了舊版的比特幣的代碼。在 checkblock() 和 acceptblock() 函數當中調用了時間戳校驗的算法,與 bitcoin0.8.2 相同,分別是按照如圖四中的函數執行流程獲得調用。


(圖四)

2.2 XVG 難度的調整

XVG 的難度調整算法會向前回溯取相同算法 12 個區塊的難度平均值做一個計算,如果實際出塊時間間隔小於理想出塊時間間隔(12150)的三分之一則調整難度為均值的三倍,如果大於理想出塊時間間隔(12150)的三倍則調整難度為均值的三分之一。這樣做的目的是通過對比實際出塊時間間隔和理想出塊時間間隔進行動態難度調整,如果出塊慢了,那麼就降低難度,如果出塊快了,就增加難度,但是調整的時候使用上下限進行限制,這是為了慢慢的調整難度值,防止難度過快的變化,相關代碼如圖五所示。


(圖五)

2.3 下面是我們對攻擊流程的分析

首先攻擊者擁有很大的算力,攻擊者很快使得自己的挖到的區塊所在的鏈成為了主鏈。因為區塊鏈的一個特點就是最長的鏈就是主鏈。同時修改時間戳,讓其他礦工所挖的區塊通過不了時間戳範圍校驗,成為孤塊。這就造成了只有攻擊者可以挖到塊,而其他正常礦工不能在攻擊者控制的主鏈上挖到塊。

2.3.1 初始階段
通過觀察發現,攻擊者最開始修改時間戳的塊是 2007355,並不是 ocminer 所說的 2007365,如圖六 :


(圖六)

從區塊 2007355 到 2007363 可以看出,攻擊者修改出塊時間為每五分鐘一個 (上圖紫色顏色的時間),當然實際上攻擊者的出塊時間比顯示的時間戳快很多。由於偽造的時間戳間隔遠遠大於正常出塊時間的 30 秒,XVG 會降低難度,通過這 9 個塊,XVG 的挖礦難度已經下降了一半 . 正常情況下,9 個塊的時間 45 分鐘左右相當於攻擊者將正常挖礦時間提前了 40 分鐘左右。在 Checkblock() 中,因為攻擊者偽造了時間戳,使得 pindexPrev->GetMedianTimePast() 的值增大,即前 11 個區塊的時間戳中值,使得正常時間戳出的塊無法滿足大於前 11 個塊時間戳中值的條件 , 從而正常時間戳出的塊無法添加到攻擊者挖掘的這條長鏈上。圖七是 Checkblock() 中校驗時間戳的代碼。


(圖六)

從區塊 2007355 到 2007363 可以看出,攻擊者修改出塊時間為每五分鐘一個 (上圖紫色顏色的時間),當然實際上攻擊者的出塊時間比顯示的時間戳快很多。由於偽造的時間戳間隔遠遠大於正常出塊時間的 30 秒,XVG 會降低難度,通過這 9 個塊,XVG 的挖礦難度已經下降了一半 . 正常情況下,9 個塊的時間 45 分鐘左右相當於攻擊者將正常挖礦時間提前了 40 分鐘左右。在 Checkblock() 中,因為攻擊者偽造了時間戳,使得 pindexPrev->GetMedianTimePast() 的值增大,即前 11 個區塊的時間戳中值,使得正常時間戳出的塊無法滿足大於前 11 個塊時間戳中值的條件 , 從而正常時間戳出的塊無法添加到攻擊者挖掘的這條長鏈上。圖七是 Checkblock() 中校驗時間戳的代碼。

file

(圖七)

下面對代碼做簡單解釋。圖七代碼的意思為只要新塊的時間戳大於之前 11 個 block 的時間戳的中位數,且不超過當前網絡時間 2 個小時,則這個塊都被認為有效。GetBlockTime() 只是簡單返回位於 class CBlockHeader 中的 nTime 成員,也即本塊生成的時間戳。GetMedianTimePast() 的實現如圖八 :


(圖八)

新塊的時間戳需要大於前 11 個 block 的時間戳的中位數這個容易理解,但是 nMaxClockDrift 為什麼要設置為 2 個小時,將 nMaxClockDrift 寬泛的設置成 2 個小時主要是考慮到 blockheader 上的時間戳並不像 NTP 服務器那樣是一個嚴格準確的時間,新塊的開採也需要一定的時間,比方說對於比特幣可能是 10 分鐘左右才能創建成功一個新塊,極端情況下可能會遠遠超過 10 分鐘,一 旦 nMaxClockDrift 時間設置的過小,後續合法產生的新塊的時間戳,由於時間戳過大,很可能沒辦法滿足時間戳校驗條件,造成區塊鏈沒有辦法再添加的區塊。

2.3.2 控制修改時間戳,使得難度不至於快速下降

經過第一階段,攻擊者已經基本上可以獨佔挖礦了,難度也已經下降了很多,這一階段攻擊者已經不需要很大的算力了,因為這時候,正常礦工挖出的塊,已經不能通過時間校驗了,攻擊者可以不受干擾的挖礦,自己也完全可以控制挖礦難度。同時為了不至於難度下降過快,從而導致其他礦工發現和其他問題出現,攻擊者有意的控制了出塊的時間戳。 第一種方式:故意交替的改變時間戳,大約差值為一個半小時 (從 2007365 塊高度開始) 當前一個塊減去後一個塊時間為正的一個半小時,這時候難度是下降的 當前一個塊減去後一個塊時間戳為負的一個半小時,這時候難度是增長的。 如下表所示

第二種方式 : 每隔 9 個塊,使得連續的三個塊時間間隔改為 1 秒 (圖二紅色字體) 很顯然根據難度調整的函數,我們知道這裡出塊的速度非常的快。導致這裡難度極速回調。 下表是紅色的塊的難度情況。

當然總體的趨勢是難度不停的下降,如圖九所示。


(圖九)

綜上所述,攻擊者就可以獨佔自己的這條長鏈進行挖礦,根據最長鏈原則(把累計了最多難度的區塊鏈作為主鏈,在一般情況下,也是包含最多區塊的那個鏈),這條鏈就變成了主鏈,並使得自己挖礦難度不斷降低,從而保持最長鏈的優勢,某些區塊的難度被攻擊者降為接近於 0。由於 XVG 每 30 秒就出塊一次,它的分叉會比特幣頻繁很多。同樣挖掘第 2007433 高度的塊,正常礦工和攻擊者挖礦難度不同,因此正常礦工所挖的分叉鏈遠遠沒有辦法同攻擊者的最長鏈做競爭,導致最後都成為了孤塊。


(圖十)


(圖十一)

圖十是礦池挖到的孤塊,圖十一是攻擊者挖到的區塊,兩圖對比可以看到高度 2007433 上的一個孤塊在挖掘的時候同攻擊者獨佔挖掘的最長鏈不是同一個鏈。並且難度也不同。

3. XVG 團隊的對代碼的修改

3.1 first patch

XVG 團隊第一次的 patch 可以在這裡看到。https://github.com/vergecurrency/VERGE/commit/a3dd53f40aaedd28bd4d0fc720f034492f7ded81
patch 改動如下三圖。


(圖十二)


(圖十三)


(圖十四)

Patch 的代碼是以區塊高度 2040000 為限,小於等於 2040000 高度的區塊時間戳檢查依然採用之前的邏輯,即新塊的時間戳要大於之前 11 個 block 的時間戳的中位數、且不超過當前網絡時間 2 個小時。而大於 2040000 高度的區塊時間戳檢查變更為,新塊的時間戳要大於前一個區塊的時間戳,並且不可以超過當前網絡時間 20 分鐘。很明顯第一次 patch 的第一個條件 if (GetBlockTime() < pindexPrev->GetBlockTime())return error(“AcceptBlock() : block’s timestamp is too early”); 會大量誤傷礦工合法產出區塊。因為即使是正常出塊,下一個區塊的時間戳也不能總是保證比上一個塊的時間戳大。由於 XVG 是 30 秒左右出一個塊,不同於比特幣 10 分鐘的出塊時間,後一個條件設置將 nMaxClockDrift 由 2 小時縮短到 20 分鐘也不會造成 XVG 區塊鏈無法接續的情況。XVG 團隊的第一次 patch 主要是想通過縮短 nMaxClockDrift 的值加強時間戳校驗,阻止例如 2007385 和 2007386,2007387 和 2007388 這樣的間隔超過 20 分鐘的區塊產生。縮短 nMaxClockDrift 的值以及校驗前後區塊時間戳順序從表面上看似可以阻止攻擊,但是如果使用大算力的 scrypt 繼續挖礦,攻擊者依然可以按照相應的時間戳判定邏輯偽造時間戳,並繞過代碼檢測。

3.2 xvg 團隊的第二次 patch

由於 XVG 支持 5 種算法競爭挖礦,正常挖礦的情況下,取 10 個區塊如下截圖。


(圖十五)

由於競爭關係,可以看到 10 個區塊不全都是一種算法產生的。而在被惡意挖礦的區塊,截圖情況如圖十六,scrypt 算法在這段時間壟斷了出新塊的挖礦。

(圖十六)

第二次 patch 的在如下鏈接
https://github.com/vergecurrency/VERGE/commit/80c81aef63272231fc39c2af4b8db9f3f2e9


(圖十七)


(圖十八)

如圖十七和十八,代碼主要的改動是將上次改動的判斷時間戳校驗的代碼進行恢復,nMaxClockDrift 由 20 分鐘調整回 2 小時。修復了代碼 if (GetBlockTime() < pindexPrev->GetBlockTime())return error(“AcceptBlock() : block’s timestamp is too early”);可能誤傷正常產出的區塊的問題。


(圖十九)


(圖二十)

為了阻止單一算法獨佔挖礦,新加入 CheckPreAlgo() 函數,如圖十九和圖二十所示,從塊高度 2042000 開始,在執行 checkblock() 函數的時候開始調用新加入的檢查邏輯。自當前區塊共向前回溯 10 個區塊,檢查單一算法挖出的區塊數,當每 10 個區塊有 6 個或者 6 個以上的區塊是由單一算法挖出的時候,新出的這個區塊不會被鏈接受,從而緩解單一算法獨佔挖礦引發的安全問題。

  1. XVG 「算力優勢+時間劫持」攻擊事件總結

根據 ocminer 的論壇反饋和我們的區塊高度統計,攻擊者的兩次獨佔挖礦造成其他礦工的損失統計如圖二十一,有 15000 左右個區塊被攻擊者惡意挖礦。


(圖二十一)

兩次攻擊可疑的收幣地址如下圖所示,更詳盡的信息可見 https://pastebin.com/K7L1G5FE

就這次攻擊分析來看,攻擊者主要利用自己算力的優勢偽造時間戳,使得自己挖礦難度不斷降低,從而保持自己最長鏈的優勢,讓正常的礦池挖到的都是孤塊,通過「作弊」挖礦的方式去獲利。根據 XVG 黑皮書的描述多種加密算法可以預防 51% 算力攻擊,通過這次安全事件我們知道世事無絕對,攻擊者根據代碼邏輯構造的一系列組合攻擊利用還是可以進行成功攻擊的,目前而言,51% 攻擊對於 pow 機制的加密貨幣來說還是一個逃不開的話題。

最後希望我們的聲音能讓更多人去關注區塊鏈安全!

更多精彩內容,關注鏈聞 ChainNews 公眾號(id:chainnewscom),或者來微博@ 鏈聞 ChainNews與我們互動!轉載請註明版權和原文鏈接!

相關推薦

推薦中...