7 月 30 日 21:10 至 7 月 31 日 06:00 鏈上發生大規模攻擊事件,導致多個 Curve 池的資金損失。漏洞的根源都是由於特定版本的 Vyper 中出現的重入鎖故障。
通過對鏈上交易數據初步分析,我們對其攻擊的交易進行整理歸納,並對攻擊流程進一步的分析,由於攻擊涉及多個交易池。
pETH/ETH 池子被攻擊交易:
https://etherscan.io/tx/0xa84aa065ce61dbb1eb50ab6ae67fc31a9da50dd2c74eefd561661bfce2f1620c
msETH/ETH 池子被攻擊交易:
https://etherscan.io/tx/0xc93eb238ff42632525e990119d3edc7775299a70b56e54d83ec4f53736400964
alETH/ETH 池子被攻擊交易:
https://etherscan.io/tx/0xb676d789bb8b66a08105c844a49c2bcffb400e5c1cfabd4bc30cca4bff3c9801
CRV/ETH 池子被攻擊交易:
https://etherscan.io/tx/0x2e7dc8b2fb7e25fd00ed9565dcc0ad4546363171d5e00f196d48103983ae477c
https://etherscan.io/tx/0xcd99fadd7e28a42a063e07d9d86f67c88e10a7afe5921bd28cd1124924ae2052
由於其攻擊流程基本一致所以我們主要對其中 pETH/ETH 池子 攻擊交易進行詳細的分析:
0xa84aa065ce61dbb1eb50ab6ae67fc31a9da50dd2c74eefd561661bfce2f1620c
交易由0x6ec21d1868743a44318c3c259a6d4953f9978538
調用攻擊合約0x9420F8821aB4609Ad9FA514f8D2F5344C3c0A6Ab ,並由該合約創建一次性攻擊合約
0x466b85b49ec0c5c1eb402d5ea3c4b88864ea0f04,並通過在一次性攻擊合約的構造函數中進行接下來的攻擊流程;
攻擊者通過閃電貸從 Balancer 處獲取 80,000 WETH ,並將其通過合約全部提取爲 ETH。
隨後立即向 Curve 的 pETH/ETH 池提供了40000 ETH 流動性,並收到了約 32,431.41 個 pETH-ETH LP Token
隨後在攻擊合約中調用移除流動性函數,但在其合約函數調用棧中我們可以看出,該合約在執行移除流動性時又返回調用了合約本身的回退函數,並在回退函數中又調用了交易對的添加流動性操作。
根據 pETH/ETH 交易對合約源碼分析,其中在轉账時使用合約的回退函數再次調用該合約,此處發生合約重入,但該LP合約添加流動性以及移除流動性都有使用重入鎖,如下圖所示:
但實際調用棧中還是發生了重入了,導致後續通過攻擊者合約又一次向LP Token添加了40,000 ETH 並獲取了約 82,182.76 個 pETH/ETH Lp Token, 並在攻擊合約的回調函數結束繼續移除最开始添加的 32,431.41 pETH/ETH Lp Token 獲得了約 3,740.21 pETH 和 34,316 ETH。
隨即又調用移除流動性函數,移除約 10,272.84 pETH/ETH LP Token 獲得約 1,184.73 pETH 和 47,506.53 ETH。
其剩余的7萬多pETH/ETH LP Token依舊留在攻擊者合約中,如下圖:
接下來攻擊者通過 Curve pETH/ETH 池將約 4,924.94 pETH 交換爲的 4,285.10 ETH。
最後攻擊者將約 86,106.65 ETH 兌換爲 WETH,並向 Balancer 歸還閃電貸資金 80,000 WETH,並將 獲利資金約 6,106.65 WETH 轉移至 0x9420f8821ab4609ad9fa514f8d2f5344c3c0a6ab 地址。
至此,針對 pETH/ETH 池子的攻擊流程分析完畢,是一個很經典的重入獲利操作,但是我們通過對被攻擊合約的源碼進行分析,其合約是存在相應的重入鎖機制,正常來說可以防止重入操作,但是並沒有拒絕攻擊者的重入操作;
我們回顧一下 Vyper 中對重入鎖的說明,知道了該重入鎖實現是在函數起始部位使用指定的插槽存儲是否鎖定的操作。
我們將被攻擊 LP 合約的字節碼進行反編譯查看:
https://library.dedaub.com/ethereum/address/0x466b85b49ec0c5c1eb402d5ea3c4b88864ea0f04/decompiled
可以看到其兩個函數中存儲重入鎖的插槽並不一致,所以導致其重入鎖失效,進而導致被攻擊者利用進行獲利。
Vyper項目方官方也發推說明,其某些版本中確實存在重入鎖故障。
通過對其0.2.14版本以及0.2.15 版本對比,發現其在 Vyper 對應的重入鎖相關設置文件 data_positions.py 中存在改動,其改動後的代碼對重入鎖的存儲key進行單獨設置,並且,每一個重入鎖都會佔用一個不同存儲插槽,從而導致合約的重入鎖功能不可用。
該錯誤已在 PR 中修復:#2439 和 #2514
其中修復了添加多個重入存儲插槽的問題,詳見下圖:
此次攻擊事件涉及的攻擊範圍較廣,其根本原因是因爲智能合約的基礎設施 Vyper 的 0.2.15、0.2.16、0.3.0 版本存在重入鎖設計不合理,從而導致後期使用這些版本的項目中重入鎖失效,最終遭受了黑客攻擊。
建議在項目开發時選擇穩定的技術棧以及對應版本,並對項目進行嚴格的測試,防止類似風險。
鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播信息之目的,不構成任何投資建議,如有侵權行為,請第一時間聯絡我們修改或刪除,多謝。