
SharkTeam:Multicall 任意地址欺騙漏洞原理分析
TechFlow Selected深潮精選

SharkTeam:Multicall 任意地址欺騙漏洞原理分析
此次攻擊事件的根本原因:在 ERC-2771 中,[Forwarder]並不是專為 multicall 設計。
撰文:SharkTeam
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 代幣。

二、漏洞分析
首先,此次攻擊事件主要涉及幾個方面:ERC2771、Multicall、經過精心構造的 calldata。我們可以從 TIME 代幣合約中找到相關的繼承:

1.ERC2771 提供了擁有虛擬的 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 值進行相應的可讀格式化後得出:

攻擊者(0xFDe0d157)通過對當前 calldata 的偏移操作獲得新的 data 值,並將該值傳遞給 multicall(bytes[]) 函數。新 data 的前 4 個字節是 burn(uint256) 函數的選擇器,amount 參數為 62227259510000000000000000000。
5.在 multicall(bytes[]) 函數中,通過 delegatecall 調用 burn(uint256) 函數。在 0x20 這一行,0x760dc1e043d99394a10605b2fa08f123d60faf84 地址是在構造 calldata 時一開始添加在末尾的。該地址對應 Uniswapv2 上的 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 帶有 ERC2771context 數據的 context 後綴長度,用於標識 ERC-2771 預期的 context 後綴長度。因此,來自可信任[Forwarder]的任何 call 都將被識別並適應每個子函數 call。

以下是 bug 版本和已更新版本的對比圖:

2.禁止任何合約調用 multicall 來防止[Forwarder]使用它,以 ThirdWeb 為例,該方法與 OpenZeppelin 的解決方案相比,OpenZeppelin 仍然允許通過合約進行 multicall。以下是 ThirdWeb 的相關 bug 版本和已更新版本的對比圖。

【免責聲明】市場有風險,投資需謹慎。本文不構成投資建議,用戶應考慮本文中的任何意見、觀點或結論是否符合其特定狀況。據此投資,責任自負。
歡迎加入深潮 TechFlow 官方社群
Telegram 訂閱群:https://t.me/TechFlowDaily
Twitter 官方帳號:https://x.com/TechFlowPost
Twitter 英文帳號:https://x.com/BlockFlow_News










