從EIP-1967談大火的“魷魚游戲SQUID”安全風險

原標題 | 知道創宇區塊鏈安全實驗室 | 從EIP-1967談“魷魚游戲SQUID”安全風險

前言

隨著電視劇的爆火,魷魚游戲的熱度也逐漸攀升,而 SQUID 在 10 月 21 日上線后,價格幅度變化巨大,但是現在的它真的安全嗎?

Squid 從代碼上來看其依賴于以太坊提案 EIP-1967,知道創宇區塊鏈安全實驗室 將從 EIP-1967 提案再談 Squid 的安全風險。

SQUID 價格從 0.08 刀一路扶搖直上九萬里,飆升到 3000 美元,然而令人唏噓的是,價格隨即閃崩,5 分鐘從 3000 跌至 0.0007,究其原因,合約開發者在短短的幾分鐘內利用 7000w 枚 Squid 砸盤 ,導致流動性池被抽干,直至歸零。在經歷了底部 0.0007 后,該游戲代幣最近短短幾天重新漲到了 0.4,漲幅達到了 50 倍以上,可謂勢頭不小,

EIP-1967

首先,EIP-1967 的目的是規定一個通用的存儲插槽,用于在代理合約中的特定位置存放邏輯合約的地址,

在該提案中,對邏輯合約地址的存儲槽進行了標準化,而不是像 DelegateProxy (EIP897) 一樣在代理合約上使用公共方法。

通過跟進該提案,在提案中定義了如下的標準化存儲槽,

bytes32(uint256(keccak256(“eip1967.proxy.implementation”)) – 1)

bytes32(uint256(keccak256(“eip1967.proxy.beacon”)) – 1)

bytes32(uint256(keccak256(“eip1967.proxy.admin”)) – 1)

最后通過計算,列出來了三個 byte32位 的 Hash 值作為推薦的存儲槽,

bytes32(uint256(keccak256(“eip1967.proxy.implementation”)) – 1)

//邏輯合約地址 存儲槽 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc

bytes32(uint256(keccak256(“eip1967.proxy.beacon”)) – 1)

//信標合約地址 存儲槽 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50

bytes32(uint256(keccak256(“eip1967.proxy.admin”)) – 1)

//admin 地址 存儲槽 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103

EIP-1967 中有提到,對于一個代理來說,代理永遠不應該向最終用戶公開可能與邏輯合約功能沖突的方法。此處計算將 keccak256 結果進行減一再轉化為 bytes32 來隱藏前像,以防止基于函數簽名攻擊,

針對該攻擊,具體哈希后的前 4 個 bytes 函數簽名的攻擊思路如下:

  • 由于 solidity 中識別一個函數,靠的是函數簽名,而函數簽名是函數哈希后的前 4 個 bytes,是非常容易碰撞出來的,而函數簽名相關知識點可以參考實驗室之前的文章。

  • 在一個獨立的 solidity 文件中,編譯器自己會去檢查所有的 external 和 public 函數是否存在函數簽名碰撞,但對于代理模式的合約文件,可能存在 proxy 合約中的函數簽名與 impl 合約中的函數簽名碰撞,而一旦發生這種碰撞,proxy 合約中的函數就會被直接調用,而不是 impl 合約對應的函數。

除了以上用途,使用 EIP-1967 還有如下的好處

合約代理模式規范性:

由于代理合約中缺少用于獲取代理的邏輯地址的通用接口,因此無法構建對這些資訊進行操作的通用工具,比如在區塊鏈瀏覽器中,最終用戶想要與底層邏輯合約而不是代理本身進行交互,

如果擁有從代理檢索邏輯合約地址的通用方法將可以允許區塊瀏覽器去顯示邏輯合約的 ABI 而不是代理的 ABI,瀏覽器可以還檢查合約在不同槽位的存儲,來確定它是否確實是一個代理,

Squid安全性

通過跟進 Squid 合約,雖然我們看到合約部署者0x87230146e138d3f296a9a77e497a2a83012e9bc5 通過 renounceOwnership 方法將 _owner 設置為了 0 地址:

但是這樣就可以高枕無憂了嗎?在Squid的初始化中,部署者通過為ApprovedEngine傳入邏輯函數地址并設置為接口實現。

但與此同時,初始化傳入了參數_sir,該參數從代碼中可以發現,其被存儲在了存儲槽(storage[‘0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103’])中。該地址后續可成功通過ifSir修飾器的檢查并隨時調用approveTo函數來部署新的邏輯合約實現。

_sir可通過升級對應的邏輯合約,進而改變了_implementation返回的對于EIP-1967中提到的槽中bytes32(uint256(keccak256(“eip1967.proxy.implementation”) – 1))的值通過改變Engine收到調用的時候合約執行邏輯,進而修改邏輯合約的代碼:

針對該修改邏輯合約進行攻擊已屢見不鮮,在幾天前 bzx 就曾因”開發方被釣魚導致私鑰被盜”,進而代理合約被修改并影響到了流動性提供者,攻擊者不僅轉走了原本合約內的資金,還嘗試轉移對合約進行了approve的賬戶的資產,

最后,通過追溯該Squid的部署合約,我們可以發現該合約的具體部署Transaction:

https://bscscan.com/tx/0xcaa4186f7e4dacd856835cb92a8518c88b098a33348a42168f99a0c57b7291c7

而在此 Transaction 中,傳入合約的參數最后一個參數則為 _sir 地址:

0x6bdb3b0fd9f39427a07b8ab33bac32db67eb4e38

當然,還存在多種方法拿到該地址如:

并且該sir后門地址至今仍非常活躍:

后記

Squid 經過了暴跌與暴漲,但本質上仍沒有完成去中心化,合約依然存在諸多安全風險,在頻繁和大幅度的漲跌中,常有參與者忘記了本心,最后導致虧空的結局,

0 条回复 A文章作者 M管理員
    暫無討論,說說你的看法吧