以太坊遭到攻擊而導致分叉事件的技術分析

北京時間 2021 年 8 月 27 日 20 點 50 分左右(區塊高度 13107518),以太坊突然出現分叉我們通過分析 Geth 的代碼版本修改和這筆造成分叉的交易(0x1cb6fb36633d270edefc04d048145b4298e67b8aa82a9e5ec4aa1435dd770ce4)釐清了以太坊分叉的根本原因:Geth 舊版本在處理預編譯合約調用時,並未考慮特殊情況(corner case)下參數值的處理,從而引發重疊拷貝(overlapping copy),導致返回值異常。該漏洞(CVE-2021-39137)已提交 Geth 官方,目前尚未披露細節,但攻擊者已經利用漏洞實施了攻擊。我們認為及時的分析和披露是必要的,也希望我們的分析能夠為社區提供必要的理解和幫助。

攻擊分析

運用我們的在線分析工具,可以看出:

以太坊遭到攻擊而導致分叉事件的技術分析

圖一

這筆交易執行了一個精心構造的 STATICCALL, 攻擊者將 addr 設為 0x04 (是預編譯合約 dataCopy), inOffset 為 0, inSize 為 32, retOffset 為 7, retSize 為 32。

以太坊遭到攻擊而導致分叉事件的技術分析

圖二

由於 STATICCALL 的目標地址是預編譯合約,所以會執行圖二中的 RunPrecompiledContract。

以太坊遭到攻擊而導致分叉事件的技術分析

圖三

以太坊遭到攻擊而導致分叉事件的技術分析

圖四

根據圖三和圖四的代碼,可以看到預編譯合約 0x04 真正執行的邏輯只是簡單地把 in (指針)返回。

以太坊遭到攻擊而導致分叉事件的技術分析

圖五

以太坊遭到攻擊而導致分叉事件的技術分析

圖六

圖五是 STATICCALL 的執行過程,753 行是執行預編譯合約的入口,751 行的 args 指向 EVM 的 Memory 中 inOffset ~ inOffset + inSize 這篇區域的指針,也就是說 args 指向 Mem[0:32]。

根據圖六以及前文對預編譯合約 0x04 (dataCopy)的分析,我們可以知道 753 行的返回值 ret 是與 args 完全相同的指針,也指向 Mem[0:32]。

  • 在 1.10.7 版本的 Geth 中(有 Bug): 762 行將 ret 指向的值賦給 EVM 的 Memory 中 retOffset ~ retOffset + retOffset 這篇區域 , 也就是將 Mem[0:32] 的值賦給 Mem[7:7+32],而由於 ret 是一個指向 Mem[0:32] 的指針,這次 Memory.Set 修改了 Mem[7:32] 的值,也就修改了 ret 所指的值。所以在第 771 行返回的 ret 已經不是預編譯合約執行結束時的 ret 了。
  • 在 1.10.8 版本的 Geth 中(無 Bug): 增加了 766 行:ret = common.CopyBytes (ret), 將 Mem[0:32] 中的值做了一次深拷貝賦給 ret,那麼在 767 行執行的 Memory.Set 只會修改 Memory 而不會修改 ret, 在 771 行返回的 ret 就是正確的 ret。

總結

通過對整個攻擊流程的梳理和 Geth 源代碼的分析,我們認為根本原因在於 Geth 舊版本在處理預編譯合約的調用時並未考慮異常值的處理,導致攻擊者利用該漏洞實施了重疊拷貝,影響了返回值,最終導致分叉的出現。由於 Geth 是 BSC、HECO、Polygon 等公鏈的基礎,因此該漏洞影響範圍甚廣。目前各公鏈也先後推出了升級和補丁,我們也呼籲各相關節點儘早升級打上補丁,以確保基礎設施的安全。

本文鏈接:https://www.8btc.com/article/6678730

轉載請註明文章出處

(0)
上一篇 2021-08-29 10:35
下一篇 2021-08-29 11:32

相关推荐