Solidity編譯器漏洞解析及開發者安全策略

Solidity編譯器漏洞解析及應對策略

編譯器是現代計算機系統的基本組成部分之一。它是一種計算機程序,主要功能是將人類易於理解和編寫的高級程序語言原始碼轉換成計算機底層CPU或字節碼虛擬機可執行的指令代碼。

大多數開發人員和安全專家通常會較爲關注程序應用代碼的安全性,但可能會忽視編譯器本身的安全問題。事實上,編譯器作爲計算機程序,也存在安全漏洞,而這些漏洞在特定情況下可能會帶來嚴重的安全風險。例如,瀏覽器在編譯並解析執行JavaScript前端代碼的過程中,可能因爲JavaScript解析引擎的漏洞,導致用戶訪問惡意網頁時被攻擊者利用漏洞執行遠程代碼,最終控制受害者的瀏覽器甚至操作系統。

Solidity編譯器也不例外,根據Solidity開發團隊的安全警告,多個不同版本的Solidity編譯器中都存在安全漏洞。

Solidity編譯器漏洞

Solidity編譯器的作用是將開發人員編寫的智能合約代碼轉換成以太坊虛擬機(EVM)指令代碼,這些EVM指令代碼通過交易打包上傳到以太坊,最終由EVM解析執行。

需要將Solidity編譯器漏洞與EVM自身的漏洞區分開來。EVM的漏洞指虛擬機在執行指令時產生的安全問題。由於攻擊者可以上傳任意代碼到以太坊,這些代碼最終將在每個以太坊P2P客戶端程序中運行,如果EVM存在安全漏洞,將影響整個以太坊網路,可能造成整個網路拒絕服務(DoS)甚至被攻擊者完全控制。不過,由於EVM設計相對簡單,且核心代碼不會頻繁更新,因此出現上述問題的可能性較低。

Solidity編譯器漏洞是指編譯器將Solidity轉換成EVM代碼時存在的問題。與瀏覽器等在用戶客戶端計算機上編譯運行JavaScript的場景不同,Solidity編譯過程只在智能合約開發者的計算機上進行,不會在以太坊上運行。因此Solidity編譯器漏洞不會影響以太坊網路本身。

Solidity編譯器漏洞的一個主要危害在於,可能導致生成的EVM代碼與智能合約開發者的預期不一致。由於以太坊上的智能合約通常涉及用戶的加密貨幣資產,因此編譯器導致的任何智能合約bug都可能造成用戶資產損失,產生嚴重後果。

開發者和合約審計人員可能會重點關注合約代碼邏輯實現問題,以及重入、整數溢出等Solidity層面的安全問題。而對於Solidity編譯器的漏洞,僅通過對合約源碼邏輯的審計很難發現。需要結合特定編譯器版本與特定的代碼模式共同分析,才能確定智能合約是否受編譯器漏洞影響。

Solidity編譯器漏洞解析及應對措施

Solidity編譯器漏洞示例

以下通過幾個真實的Solidity編譯器漏洞案例,展示其具體形式、原因及危害。

SOL-2016-9 HighOrderByteCleanStorage

該漏洞存在於早期的Solidity編譯器版本中(>=0.1.6 <0.4.4)。

考慮如下代碼:

solidity contract C { uint32 a = 0x1234; uint32 b = 0; function f() public { a += 1; } function run() public view returns (uint32) { return b; } }

storage變量b沒有經過任何修改,因此run()函數應該返回默認值0。但在漏洞版本編譯器生成的代碼中,run()將返回1。

如果不了解該編譯器漏洞,普通開發者很難通過簡單的代碼審查發現上述代碼中存在的bug。這只是一個簡單示例,不會造成特別嚴重的後果。但如果b變量被用於權限驗證、資產記帳等用途,這種與預期的不一致可能會導致非常嚴重的問題。

產生這種奇怪現象的原因在於EVM使用棧式虛擬機,棧中每個元素均爲32字節大小(即uint256變量大小)。另一方面底層存儲storage的每個槽也是32字節大小。而Solidity語言層面支持uint32等各種小於32字節的數據類型,編譯器在處理這類變量時,需要對其高位進行適當的清除操作(clean up)以確保數據正確性。在上述情況中,加法產生整數溢出時,編譯器沒有正確地對結果高位進行clean up,導致溢出後高位的1 bit被寫入storage中,最終覆蓋了a變量後面的b變量,使b變量的值被修改爲1。

SOL-2022-4 InlineAssemblyMemorySideEffects

考慮如下代碼:

solidity contract C { function f() public pure returns (uint) { assembly { mstore(0, 0x42) } uint x; assembly { x := mload(0) } return x; } }

該漏洞存在於>=0.8.13 <0.8.15版本的編譯器中。Solidity編譯器在將Solidity語言轉換成EVM代碼的過程中,不僅僅是簡單的翻譯。它還會進行深入的控制流與數據分析,實現各種編譯優化過程,以減小生成代碼的體積,優化執行過程中的gas消耗。這類優化操作在各種高級語言的編譯器中都很常見,但由於需要考慮的情況非常復雜,也很容易出現bug或安全漏洞。

上述代碼的漏洞就源於這類優化操作。假設某個函數中存在修改內存0偏移處數據的代碼,但後續沒有任何地方使用該數據,那麼實際上可以直接移除修改內存0的代碼,從而節省gas,且不影響後續的程序邏輯。

這種優化策略本身沒有問題,但在具體的Solidity編譯器代碼實現中,此類優化只應用於單一的assembly block。對上述PoC代碼,對內存0的寫入和訪問存在於兩個不同的assembly block中,而編譯器卻只對單獨的assembly block進行了分析優化。由於第一個assembly block中在寫入內存0後沒有任何讀取操作,因此判定該寫入指令是多餘的,會將其移除,從而產生bug。在漏洞版本中f()函數將返回值0,而實際上上述代碼應該返回的正確值是0x42。

SOL-2022-6 AbiReencodingHeadOverflowWithStaticArrayCleanup

考慮如下代碼:

solidity contract C { function f(string[1] calldata a) external returns (string memory) { return abi.decode(abi.encode(a), (string)); } }

該漏洞影響>= 0.5.8 < 0.8.16版本的編譯器。正常情況下,上述代碼返回的a變量應爲"aaaa"。但在漏洞版本中會返回空字符串""。

該漏洞的原因是Solidity對calldata類型的數組進行abi.encode操作時,錯誤地對某些數據進行了clean up,導致修改了相鄰的其他數據,造成了編碼解碼後的數據不一致。

值得注意的是,Solidity在進行external call和emit event時,會隱式地對參數進行abi.encode,因此上述漏洞代碼出現的概率會比直觀感覺更高。

Solidity編譯器漏洞解析及應對措施

安全建議

Cobo區塊鏈安全團隊經過對Solidity編譯器漏洞威脅模型的分析以及歷史漏洞的梳理,對開發者和安全人員提出以下建議。

對開發者:

  • 使用較新版本的Solidity編譯器。雖然新版本也可能引入新的安全問題,但已知的安全問題通常比舊版本少。

  • 完善單元測試用例。大多數編譯器層面的bug會導致代碼執行結果與預期不一致。這類問題很難通過代碼審查發現,但很容易在測試階段暴露出來。因此通過提高代碼覆蓋率,可以最大程度地避免此類問題。

  • 盡量避免使用內聯匯編、針對多維數組和復雜結構體的abi編解碼等復雜操作,沒有明確需求時避免爲了炫技而盲目使用語言新特性和實驗性功能。根據Cobo安全團隊對Solidity歷史漏洞的梳理,大部分漏洞與內聯匯編、abi編碼器等操作有關。編譯器在處理復雜的語言特性時確實更容易出現bug。另一方面,開發者在使用新特性時也容易出現使用誤區,導致安全問題。

對安全人員:

  • 在對Solidity代碼進行安全審計時,不要忽視Solidity編譯器可能引入的安全風險。在Smart Contract Weakness Classification(SWC)中對應的檢查項爲SWC-102: Outdated Compiler Version。

  • 在內部SDL開發流程中,敦促開發團隊升級Solidity編譯器版本,並可以考慮在CI/CD流程中引入針對編譯器版本的自動檢查。

  • 但對編譯器漏洞無需過度恐慌,大多數編譯器漏洞只在特定的代碼模式下觸發,並非使用有漏洞版本編譯器編譯的合約就一定存在安全風險,實際的安全影響需要根據項目情況具體評估。

實用資源:

  • Solidity Team定期發布的Security Alerts posts:

  • Solidity官方repo定期更新的bug list:

  • 各版本編譯器bug列表:

  • Etherscan上Contract -> Code頁面右上角的三角形感嘆號標志可提示當前版本編譯器所存在的安全漏洞。

總結

本文從編譯器的基本概念出發,介紹了Solidity編譯器漏洞,並分析了其在實際以太坊開發環境中可能導致的安全風險,最後爲開發者和安全人員提供了若幹實際的安全建議。

Solidity編譯器漏洞解析及應對措施

ETH0.9%
查看原文
此頁面可能包含第三方內容,僅供參考(非陳述或保證),不應被視為 Gate 認可其觀點表述,也不得被視為財務或專業建議。詳見聲明
  • 讚賞
  • 5
  • 分享
留言
0/400
staking_grampsvip
· 07-25 15:28
漏洞门门多 谁还敢开发
回復0
Just Here for Memesvip
· 07-23 05:15
编译器也有大问题啊 溜了溜了
回復0
烤猫铁粉vip
· 07-22 21:56
漏洞全靠捡是吧
回復0
老韭新镰vip
· 07-22 21:56
高端韭菜看漏洞,底层韭菜盯盘口
回復0
RektCoastervip
· 07-22 21:52
编译器也出bug? 真是让我闪现炸街
回復0
交易,隨時隨地
qrCode
掃碼下載 Gate APP
社群列表
繁體中文
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Bahasa Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)