一、事件描述
2022年9月18日,以太坊合併完成後,PoW鏈遭到PoS鏈上交易的重放攻擊,根本原因是網橋未正確讀取並驗證區塊鏈的chainid。攻擊者首先通過Gnosis鏈的Omni跨鏈橋轉移了200 WETH,然後在PoW鏈上重放了相同的消息,獲得了額外的200 ETHW。
SharkTeam對此事件進行了技術分析,並總結了安全防範手段,希望後續項目可以引以為戒,共築區塊鏈行業的安全防線。
二、事件分析
該事件涉及兩個不同鏈的交易hash以及攻擊者地址,分別如下:
(1)PoS鏈交易hash:0xbddb0cc8bc9949321e1748f03503ed1a20dd618fbf0a51dc5734c975b1f8bdf5
(2)PoW鏈交易hash:0x9c072551861ce384203516f4d705176a2d2e262d5b571d853467425f1a861fb4
(3)攻擊者地址:0x82FaEd2dA812D2E5CCed3C12b3baeB1a522DC677
首先,我們對比發現兩筆交易訪問的合約相同,並且inputdata完全相同,即調用了同一個合約的同一個函數並且參數相同,根據相同的方法簽名ID 0x23caab49可知,黑客調用safeExecuteSignaturesWithAutoGasLimit函數。
因此,攻擊者通過Omni Bridge 轉移200WETH,然後在PoW鏈上重放了相同的Inputdata,獲得了額外的200 ETHW。
此時,我們對這裡的重放操作抱有懷疑態度。因為,以太坊網絡在硬分叉之前強行執行EIP-155,這就說明ETH PoS鏈上交易不能在PoW鏈上重複交易。在正常的交易中,我們通過nonce來進行排序交易,避免重複交易。在跨鏈中,我們會根據chianid進行識別鏈的類型,比如以太坊主網的chainid是1,ETHW主網的chainid是10001。
對此,我們分析了Omni Bridge相應的源碼。我們查看一下Omni Bridge驗證chainid的邏輯,發現chainid的來源於unitStorage中存儲的值,而不是通過操作碼CHAINID(0x46)直接讀取的鏈上chainid。
unitStorage是合約EternalStorage中的狀態變量,sourceChainId()函數所在的合約BasicAMB繼承了BasicBridge和VersionableAMB。其中,BasicBridge陸續繼承了合約EternalStorage。這裡保存的chainid是預先存儲好的,如果發生區塊鏈的硬分叉而chainid又沒有重新設置或者chainid人為設置有誤,從合約層面上來說,由於不是通過操作碼獲取的chainid,不會正確驗證跨鏈消息的實際chainid。這樣的漏洞,容易被攻擊者利用。
問題分析總結:主要是Omni使用的solidity版本是0.4.24,採用的是手動存儲和更新chainid的方式,並未通過EIP-1344中規定的CHAINID(0x46)操作碼進行實際chainid獲取。
三、安全建議
引發本次安全事件的原因是在PoW升級PoS過程中,Omni Bridge對chainid未及時處理。導致過舊的solidity版本中,存在歷史遺留問題。建議在後續項目迭代中,及時應對新問題,採取必要的代碼優化措施。雖然Gnosis 鏈上Omni Bridge有每日最大轉移代幣數量限制250個WETH,但是依舊要保持警惕,以防止積少成多,造成更大的損失。