Accounts

導致 EIP 150 硬分叉的狀態膨脹攻擊是如何執行的?

  • July 31, 2017

我了解SELFDESTRUCT操作碼的錯誤定價允許以便宜的方式創建許多空賬戶,如為什麼允許空賬戶在區塊鏈上? 該問題的答案還包括創建許多空帳戶的交易。該交易/攻擊是如何工作的?當合約呼叫SELFDESTRUCT時,它不能SELFDESTRUCT再次……或者可以嗎?

古代歷史,但這裡有:-)

最初的攻擊有一個協調契約後來版本有一個更複雜的算法來生成空賬戶地址,大概是為了阻止任何未來的清理工作。這只是通過地址空間增量工作。

每次呼叫協調合約時——它被呼叫了 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

this 的前 12 個字節是子合約的建構子的程式碼;接下來的四個字節是子契約程式碼本身,如上所述。

(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將其(零)值發送到該地址,從而創建一個空膨脹帳戶。

這裡的關鍵點是子合約直到目前交易執行結束才真正自毀,因此它可以在一筆交易中被多次呼叫。黃皮書裡的描述是“暫停執行並註冊賬號以便以後刪除”(強調我的);它將在目前事務終止時被刪除。僅在每次呼叫協調合約時重新創建子合約就足夠了;然後可以在其中多次呼叫它。

(4) 檢查剩餘gas,如果有足夠的則返回並再次循環所有40個呼叫,繼續增加地址計數器。

0328 GAS
0329 PUSH2 0x6000
032c LT
032d PUSH3 0x00002f
0331 JUMPI

因此,對協調合約的每次呼叫都能夠創建數千個膨脹賬戶,具體取決於最初供應的天然氣量。

(5) 最後,儲存地址計數器,為下一次呼叫做好準備。

0332 PUSH1 0x00
0334 SSTORE

當然,問題在於,通過 SELFDESTRUCT 創建帳戶並沒有使用應有的燃料。這在EIP150:長期天然氣成本變化中得到了解決。

引用自:https://ethereum.stackexchange.com/questions/11312