
2023 年12 月8 日,OpenZeppelin 官方向社群發布了一條重要的安全警報。警報指出,在專案整合中使用ERC-2771 標準與類Multicall 方式時,可能存在任意位址欺騙攻擊的風險。
SharkTeam 對此事件第一時間進行了技術分析,並總結了安全防範手段,希望後續項目可以引以為戒,共築區塊鏈產業的安全防線。
一、攻擊交易分析
由於存在一系列與該漏洞相關的攻擊交易,我們選擇其中一筆攻擊交易進行分析。
攻擊者地址:
0xFDe0d1575Ed8E06FBf36256bcdfA1F359281455A
攻擊交易:
0xecdd111a60debfadc6533de30fb7f55dc5ceed01dfadd30e4a7ebdb416d2f6b6
攻擊流程:
1.首先。攻擊者(0xFDe0d157)先利用5 枚WETH 兌換了約3, 455, 399, 346 枚TIME。
2.隨後,攻擊者(0xFDe0d157)建構了惡意的calldata 參數並呼叫了[Forwarder].execute 函數。
3.在呼叫[Forwarder].execute 函數時,惡意的calldata 觸發了TIME 合約的multicall 函數。隨後,使用剩餘的calldata 觸發執行TIME 合約的burn 函數,銷毀池中的TIME 代幣。
二、漏洞分析
首先,這次攻擊事件主要涉及幾個面向:ERC 2771、Multicall、經過精心建構的calldata。我們可以從TIME 代幣合約中找到相關的繼承:
1.ERC 2771 提供了擁有虛擬的msg.sender 的能力,允許使用者委託第三方[Forwarder]執行交易,用來降低gas 成本。提交交易時,msg.sender 地址會加入calldata 中。
2.TIME 代幣合約繼承了ERC2771Context。當[Forwarder]呼叫合約時,_msgSender() 會檢查calldata 數據,並將其右移,截斷最後的20 個字節作為預期的msg.sender。
3.Multicall 是一種將單一函數呼叫轉變為在同一個合約中按順序呼叫多個函數的方法。它接受一個用戶編碼調用的數組並對其自身合約執行。這個函數遍歷呼叫數組,並對每一個操作執行delegatecall()。這允許使用者組合自己的一系列操作,並在同一筆交易中順序執行,而無需在協議中預先定義好某些操作組合。它主要目的也是為了節省gas。
4.對於經過精心建構的calldata,攻擊者呼叫了[Forwarder].execute 函數,並傳入相關參數。
我們對data 值進行對應的可讀格式化後得出:
攻擊者(0x FDe 0 d 157)透過對目前calldata 的偏移操作獲得新的data 值,並將該值傳遞給multicall(bytes[]) 函數。新data 的前4 個字節是burn(uint 256) 函數的選擇器,amount 參數為62227259510000000000000000000。
5.在multicall(bytes[])函數中,透過delegatecall 呼叫burn(uint 256)函數。在0x 20 這一行,0x760dc1e043d99394a10605b2fa08f123d60faf84 位址是在建構calldata 時一開始加入在末尾的。此地址對應Uniswap v2上的TIME-ETH 流動性池,即前文所提及的預期的msg.sender。
6.剛才提到的msg.sender 為何變成TIME-ETH 流動性池地址?原因是一開始msg.sender 是[Forwarder]合約地址。為了判斷是否是可信的[Forwarder],如果是可信的[Forwarder],則將msg.sender 設定為calldata 的最後20 個字節。
三、安全建議
這次攻擊事件的根本原因:在ERC-2771 中,[Forwarder]並不是專為multicall 設計。攻擊者將_msgSender()函數中的相關參數加入multicall 的外部呼叫中,即本次事件的[Forwarder].execute 函數。在multicall 函數中,有些函數也會附加_msgSender()中的相關參數,讓攻擊者可以欺騙_msgSender()。因此,攻擊者透過使用multicall 呼叫相關函數,可以模仿任意地址的呼叫。最終,透過授權銷毀池子裡的TIME 代幣。
針對此事件,可採取以下緩解和防範措施:
1.使用修復bug 後的新版本,OpenZeppelin 新版本的Multicall 帶有ERC 277 1co ntext 資料的context 後綴長度,用於標識ERC-2771 預期的context 後綴長度。因此,來自可信任[Forwarder]的任何call 都將被識別並適應每個子函數call。
以下是bug 版本和已更新版本的比較圖:
2.禁止任何合約呼叫multicall 來防止[Forwarder]使用它,以ThirdWeb 為例,該方法與OpenZeppelin 的解決方案相比,OpenZeppelin 仍然允許通過合約進行multicall。以下是ThirdWeb 的相關bug 版本和已更新版本的比較圖。
About Us
SharkTeam 的願景是保護Web3世界的安全。團隊由來自世界各地的經驗豐富的安全專業人士和高級研究人員組成,精通區塊鍊和智慧合約底層理論。提供包括鏈上大數據分析、鏈上風險預警、智慧合約審計、加密資產追討等服務,並打造了鏈上大數據分析和風險預警平台ChainAegis,平台支援無限層級的深度圖分析,能有效對抗Web3世界的高階持續威脅(Advanced Persistent Threat,APT)。已與Web3生態各領域的關鍵參與者,如Polkadot、Moonbeam、polygon、Sui、OKX、imToken、ChainIDE 等建立長期合作關係。
Twitter:https://twitter.com/sharkteamorg