GoPlus Security:由 Vyper 編譯器 0.2.15 版本漏洞引發的 Curve 攻擊分析
背景
近期,一些使用 Vyper 0.2.15 版本編寫的穩定池(alETH/msETH/pETH)遭受了重入攻擊。這是由於該版本編譯器實現錯誤導致的重入鎖故障問題。此漏洞導致了約5000萬美金的損失。本文將分析該漏洞的根本原因和攻擊原理。同時,將提供優化建議以防止類似事件再次發生。
根因分析
漏洞根源來自於編譯器對@nonreentrant(\<str>)修飾器語義的錯誤實現。
正確語義描述
@nonreentrant(\<str>)是用於限制函數的重入,其語義則類似於多線程中的互斥鎖:
單函數修飾:當一個函數被該修飾器修飾,它的多個調用無法同時執行。
多函數修飾:當多個函數都使用該修飾器,且重入限制鍵相同(字符串值相同),它們的多個調用仍然無法同時執行。
一個正確的實現是,對每個重入限制鍵設置一個布爾值,0代表有一個函數在執行,1代表沒有函數執行。多個被該鍵限制的函數根據該變量來進行同步(獲得鍵-1,釋放鍵+1,嘗試獲得鍵需檢查值是否為1)。
實際語義實現
在Vyper編譯器0.2.15版本及之前,對於該語義的實現是錯誤的。錯誤代碼如下所示。
分析 代碼中的storage_slot對應上文提到的同步變量。錯誤在於它的值域,該變量一開始為0,每當解釋器處理到一個函數聲明中的@nonreentrant,便將同步變量 +1,這樣是重複的。當代碼滿足上文中的多函數修飾情況時,由於解釋器處理了多個函數,同步變量的值域不再滿足布爾值,與正確語義不符合(即存在鎖失效)。其實,代碼中的TODO 註釋已經反映了開發者的顧慮。
修復 在patch中,檢查了該鍵是否已被創建,若是則不再+1
結果 些合約因為該修飾器的實際實現與預期不符而受到攻擊,即使這些合約在理論上是正確的。比如接下來介紹的案例。
合約攻擊案例
所有滿足上文提及的多函數修飾合約,都有可能被攻擊。比如被攻擊的一個合約,代碼有5個函數都被同一個鍵@nonreentrant("lock")修飾,因此相互可以重入。
- add_liquidity
- remove_liquidity
- exchange
- removeliquidityimbalance
- removeliquidityone_coin
黑客的攻擊利用了前兩個函數。它們分別用於往流動池中添加和移除資產,流動性提供者從中可以獲得交易費用和其他獎勵。攻擊的過程類似於一般的重入攻擊:
- 第一次調用add_liquidity存資產。
- 調用remove_liquidity移除這些資產。
其中removeliquidity 會通過外部調用,返還eth給黑客。此時黑客通過在fallback函數內調用addliquidity完成重入。
在重入到addliquidity 後,由於removeliquidity 尚未減少代幣總量total_supply ,因此在計算為黑客鑄造的代幣數量時,超出了原本應有的數量。
remove_liquidity()
add_liquidity()
解決方案與未來發展
針對這則事故,我們對於未來的Web3安全開發解決方案有一些思考:
1. 協議開發者的責任與敏感性
協議開發者需要積極關注核心供應鏈的更新和安全問題,及時獲取相關信息,增加對底層實現的理解。
2. DevSecOps的引入
如何在合約開發流程中更好的引入一些安全測試和驗證的工具,無論是靜態分析還是動態Fuzz,嵌入SDLC(軟件開發生命周期)中,使得一些問題能夠更早的被暴露並解決。
3. Software Composition Analysis (SCA) 工具的引入
我們注意到,在Vyper漏洞被曝出之後,其實給幾個被攻擊的協議團隊有大約半天到一天的時間去做出補救措施去反應,但遺憾的是,最終並沒能成功挽救被盜資產。我們認為對於這種供應鏈問題,應該引入完善的供應鏈管理平台,也就是Web2我們常說的製品庫管理,當供應鏈出現問題的第一時間,可以快速告警並給出升級方案。
4. 交易底層範式的創新
在基礎設施層面,考慮在運行時層面進行自動化防護,例如動態的安全檢查,或者在執行關鍵操作時自動執行防護措施。我們也很高興看到了許多在這個層面上的一些趨勢,例如Uniswap V4,通過引入Hook,大大增加了交易功能的擴展性,開發者可以在交易的多個階段中去提供一些防護來增強安全性。類似的還有Artela,能夠讓開發者在Runtime層面實現多個階段的擴展,天然的就能夠解決重入這個大問題,具體可以參考https://medium.com/@artela_chinese/該篇文章。
結論
智能合約開發的複雜性和困難性使得漏洞的出現幾乎不可避免。但通過更好地理解和使用現有的工具,持續關注和參與開源社區活動,優化和改進基礎設施,我們可以降低漏洞的風險,提高整個系統的安全性和健壯性。未來的區塊鏈安全不僅需要編譯器和開發者的共同努力,更需要依賴於靜態分析、動態Fuzz等先進工具的支持和推動。同樣也更需要有創新者能夠打破束縛,提出更好的底層交易模型以及方案,讓整個Web3世界更加安全。