幣安被盜,再談以太坊空賬戶DoS攻擊事件
事件回顧
近日來,幣安被盜事件再次引發了大家對數字貨幣安全的關注。其實網路盜竊事件很普遍,並且引發了技術的不斷升級。以太坊作為區塊鏈2.0的代表,自從誕生以來就一直遭受各種攻擊。為此,本文就以太坊空賬戶DoS攻擊事件,來談一談以太坊如何在技術上保障安全。
以太坊在2016年9月份和10月份遭受一連串的DoS攻擊,攻擊者在以太坊網路內以非常低的成本建立了1900萬個空賬戶。空帳戶會浪費硬碟空間,增加同步時間並減慢處理時間,這導致了2016年10月的“EIP-150 Hard Fork”硬分叉。以及,11月的“Spurious Dragon”分叉對此攻擊所造成的影響進行了進一步修復。
什麼是空賬戶?
空帳戶是具有零餘額,零常數和空程式碼的帳戶(以太坊中每個賬戶都有一個常數,常數等於和這個帳號所相關的交易數)。空賬戶在功能上等同於不存在的賬戶,唯一的實際區別是,空賬戶需要儲存在以太坊狀態樹中。 空賬戶很容易產生,只需要你向一個不存在的賬戶發0個或者任意個以太坊,那個不存在的賬戶就會變成空賬戶。從理論上講,如果礦工接受0交易手續費,甚至可以從空賬戶或者不存在的賬戶傳送交易。
空賬戶會儲存在以太坊狀態樹中
· 他們浪費儲存空間
· 它們會增加同步時間,尤其是fast sync 和 warp sync.
· 它們減慢了事務處理速度,因為在RAM中儲存大部分或全部狀態變得更加困難,因此需要更多的磁碟訪問。
攻擊方式:
攻擊者建立了一個母合約,這個智慧合約被呼叫了4750次。這個母合約方法如下:
(1)建立一個子合約
0000 PUSH32 0x6004600c60003960046000f3600035ff00000000000000000000000000000000
0021 PUSH1 0x00
0023 MSTORE
0024 PUSH1 0x20
0026 PUSH1 0x00
0028 PUSH1 0x00
002a CREATE
這會在一個新地址上建立一個子合約。
;; Child contract (in full)
PUSH1 0x00
CALLDATALOAD
SELFDESTRUCT
子合約的程式碼在PUSH32裡,即:
0000 PUSH32 0x6004600c60003960046000f3600035ff00000000000000000000000000000000
前面的12 bytes是構造子合約的函式,接下來的4 bytes是子合約的程式碼。
(2)在儲存中載入一個計數器
002b PUSH1 0x00
002d SLOAD
002e DUP1
這將跟蹤正在建立的空帳戶,並允許後續呼叫母合約,從前一個停止的位置繼續生成空賬戶。
(3)迴圈呼叫子合約的”自毀函式“40次
(以下程式碼會被迴圈40次)
0030 PUSH1 0x01
0032 ADD
0033 DUP1
0034 PUSH1 0x00
0036 MSTORE
0037 PUSH1 0x00
0039 DUP1
003a PUSH1 0x20
003c DUP2
003d DUP1
003e DUP8
003f PUSH1 0x06
0041 CALL
0042 POP
首先向計數器新增一,複製它,將一個副本放回記憶體,然後用計數器作為呼叫資料呼叫子合約。子合約將它傳送的資料(計數器)解釋為一個地址,當它自毀時,它將其(零)值傳送到該地址,從而建立了一個空的帳戶。
selfdestruct(address)“自毀函式“會將合約的餘額轉到指定地址address,”自毀函式“函式的Gas數很少,這個設計是為了鼓勵人對不再使用的智慧合約進行銷燬,銷燬後合約的狀態會從狀態儲存中消失。當你不再使用一個合約,你呼叫“自毀函式“,比起呼叫Transfer將合約中的錢轉出要更划算。
子合約在當前交易終止時被刪除。 每次呼叫母合同時,會重新建立子合約,然後可以從內部多次呼叫它的”自毀函式“,最後被銷燬。
(4) 檢查剩下的Gas
如果有足夠的Gas話, 再返回並重新遍歷所有40個呼叫,並繼續增加地址計數器。
0328 GAS
0329 PUSH2 0x6000
032c LT
032d PUSH3 0x00002f
0331 JUMPI
因此,每次對母合同的呼叫都能夠建立數千個空賬戶,具體取決於最初供應的Gas量。
(5)儲存計數器,為下一次呼叫中做準備
0332 PUSH1 0x00
0334 SSTORE
使用”自毀函式“建立賬戶,成本極低。
誰會進行這種DoS攻擊?
網路協議存在著攻擊機會,這是很常見的,現實世界中並沒有人會去做,因為他們沒有動力去利用這些攻擊漏洞。可悲的是,我們擔心會有人針對以太坊發動這樣的攻擊。
最危險的群體是“griefers”,他們可能為了做空以太幣,從而發動一次DoS攻擊,為的就是讓以太幣的價格在短期內能夠下跌。同樣的,極端分子認為加密貨幣是一種零和遊戲,他們也可能會參與破壞。當然,那些想要攻擊以太坊礦工的人也可能會參與進來。因為在目前,這種攻擊還沒有什麼成本,這些群體很可能會發動攻擊。
以太坊的防禦措施
- 阻止這樣的攻擊
調整Gas用量,使“自毀函式”成本變高。以太坊進行了一次“EIP-150 Hard Fork”硬分叉。在2016年10月18日 23:19:31 2463000號塊。除了其他的Gas量的調整以外,“自毀函式”調整成了5000 Gas(原本是0 Gas)。
- 清除以前建立的空賬戶
隨後,以太坊做了叫做“Spurious Dragon”的分叉。在2016年11月23日 01:15:44 2675000號塊,這次分叉的相關改動是EIP 161 狀態清掃, 為了清除以前建立的空賬戶。真正的清除賬戶的操作實際是在分叉之後進行的,空賬號會在被某個交易“觸碰”時自動刪除。以太坊基金會會系統性的開始”CALL“這些因為攻擊而生成的空賬號以逐步完成清掃。
概括:當一筆交易“觸及”一個“空賬戶”時,這個“空賬戶”會被刪除。
- 解釋:
· “空賬戶”:如果帳戶沒有程式碼且常數為0和餘額為0,則該帳戶被視為空。(以太坊中每個賬戶都有一個常數,常數等於和這個帳號所相關的交易數)
· “觸及”:當一個賬戶涉及到“狀態改變”的操作時,被認為是被“觸及”。這包括但不限於,被轉入0個以太坊。
· 賬戶的“狀態改變”:
o 當它是"SUICIDE"操作的目標或者退款地址時。("SUICIDE"即後來的"selfdestruct",因為自殺是一個沉重的主題,所以改成了自毀)
o 當它是"CALL"操作或 message-call的目標或者源時。
o 當它是"CREATE"操作或者合約建立操作的目標或者源時。
o 作為礦工,是區塊獎勵或者交易費的接受方時。
· 一個交易會在產生交易收據之前,立即執行自殺列表。因此,如果出現觸及空賬戶的情況,空賬戶會被自殺掉。
事實上,目前的實現只需要跟蹤四種情境:
· 一個空帳戶,存在通過CALL傳遞給它的零值的交易;
· 一個空賬戶,存在通過SUICIDE傳輸給零值的交易;
· 一個空帳戶,存在通過message-call交易傳遞給它的值為零;
· 一個空賬戶通過zero-gas-price fees 轉賬將零值轉移給它。 (一般Gas Price設定為零的交易,礦工不會去挖,但礦工可能挖自己傳送的0交易費的交易)