Amber Group 區塊鏈安全團隊和
Amber Group 區塊鏈安全團隊和獨立研究員 Rivaill 再次發現了一個重入漏洞,並向漏洞懸賞平台 ImmuneFi 提交漏洞報告。由於項目方(Position Exchange)在修復漏洞後就與我們失去聯繫,我們決定在此撰文中公佈詳情。
0x00 Position Exchange
去中心化加密平台 Position Exchange 允許用戶使用 POSI 代幣鑄造 NFT,並質押 NFT 以賺取更多的 POSI。 如 HOWTO 文檔中所述,用戶可以鑄造的 NFT 角色共有六種,藉此來獲得隨機的挖礦效率增益。
舉例來說,用戶支付 50 POSI 鑄造下方這個 Pilot NFT,隨機生成的挖礦效率為 154.06 %,因此他/她獲得 50 x 154.06% = 76.28 POSI 的算力。如果用戶選擇質押該算力,會因此獲得額外的 NFT 礦池獎勵分成。
為了實現上述的 NFT 質押機制,後端的 NFTReward 智能合約實現了 stake() 和 unstake() 函數,讓用戶轉入/轉出基於 ERC-721 的 NFT。 然而,由於 ERC-721 標準實現中內建的回調機制,NFTReward 的運作邏輯產生了問題,導致攻擊者能夠多次重入該智能合約而獲利。
0x01 漏洞
前面提的 unstake () 函數,他的基本功能是將某個 ERC721 代幣取回給調用者。 但是如下圖所示,我們注意到第 283 行中使用的 safeTransferFrom() 函數被嵌入了一個特殊的回調機制,攻擊者可利用此漏洞攔截 unstake() 調用並插入惡意的程式碼。 此外,第 283 行之後有兩行改變狀態的語句(第 285-286 行),這違反了智能合約基本的 Checks-Effects-Interactions 原則。
具體來說,在 OpenZeppelin 的 ERC721 實現中,在傳輸 ERC721 代幣時,若接收地址是合約時會調用 onERC721Received() 外部函數(第 395 行),這是此漏洞能被利用的關鍵。
透過這種方式,攻擊者可以藉由任何的外部函數進入 NFTReward 合約竄改相關數據。 如何做到?我們注意到下面兩行是 unstake() 函數調用 safeTransferFrom() 之後唯二更新過狀態的兩個地方:
如下方的程式碼片段所示,這些狀態是在 stake() 函數中被設置的。
我們認為這個的設計的初衷是先暫存 gegoId 對應 NFT 的餘額(_stakeBalances[geogoId])和權重(_stakeWeightes[geogoId])。隨後,如果用戶選擇 unstake() 該 NFT,暫存的值將用於更新與該用戶有關的全域變數 _weightBalances 和 _degoBalances(下面的第 276 和 280 行)。
因此,如果暫存的餘額和權重在用於更新全域狀態之前被竄改,意味著 _weightBalances 和 _degoBalances 可能也會被篡改。此外,我們注意到 _weightBalances 值會被用於計算獎勵,這意味著可以利用被篡改的狀態來獲取額外的獎勵,甚至可能耗盡獎勵池。
0x02 漏洞利用
下圖展示了篡改 _weightBalances 的六個步驟:
攻擊者創建一個惡意合約 Exp,並從 Exp 呼叫 stake() 函數。如上圖所示,為了成功做到後續的劫持操作,此惡意合約 Exp 實現了一個外部函數 onERC721Received();
攻擊者從 Exp 合約觸發了 unstake() 函數;
透過 safeTransferFrom(),Exp 合約成功劫持了 unstake() 函數的調用;
從 Exp 合約重新進入 stake() 函數,使其之後能夠調用第二次 unstake() 函數;
當 Exp 合約返回到被劫持的 unstake() 調用時,第四步驟設置的 _stakeWeightes 會被重置設為 0;
攻擊者發出第二個 unstake() 調用並使用歸零的 _stakeWeightes 篡改 _weightBalances 變數。n
透過上述步驟,攻擊者可以只用一個 NFT 持續累積 _weightBalances,並且可以在沒有質押任何 NFT 的情況下,透過 NFTReward 合約中的 harvest() 函數不斷獲取獎勵。
下方惡意合約的程式碼說明了我們如何模擬攻擊。 在 trigger() 函數中,我們執行了多次 [stake(), unstake(), unstake()] 調用。 每當 unstake() 將 NFT 轉移回惡意合約時,onERC721Received() 函數就會劫持 unstake() 並在 flag 為 true 時發出另一個 stake() 調用,這就是重入攻擊竄改狀態的流程。
下方的 eth-brownie 截圖證明了我們的猜想。 具體來說,我們:
通過 eth-brownie 的模擬,「借用」了 NFT #1183410;
在 NFTReward 合約上竄改狀態;
「歸還」該 NFT;
收穫獎勵。
最後,我們的駭客在沒有質押任何 NFT 的情況下以 4.93 POSI 獲利出場,這也間接證明了攻擊者可以創建多個合約,為每個合約偽造狀態,並透過來回轉移同一個 NFT 來獲得獎勵。
0x03 時間軸和緩解措施該漏洞於 3 月 9 日通過 ImmuneFi 提交;3 月 21 日,Position Exchange 團隊確認了該問題,並將其評為高危漏洞; 3 月 22 日,我們觀察到一個新的 NFTReward 合約被部署上鏈,此合約加入了 reentrancy guard。 但自那以後,我方仍未能收到 Position Exchange 團隊的任何回覆。
除了 Position Exchange,我們還聯繫了 Dego Finance 和 Smarty Pay。兩方都部署了類似的 NFTReward 合約,且其中含有類似的漏洞。Dego Finance 團隊的處理方式是透過將 DEGO 代幣轉移到新代幣。 與此同時,Smarty Pay 團隊升級了他們的 NFTReward 合約,並將所有的用戶狀態遷移到了新版本。 據我們了解,這三個具有漏洞的項目,在我們披露細節之前皆沒有被真的攻擊。
關於 Amber Group成立於 2017 年,業務遍及亞洲及歐美各大主要城市,現為 1,000 多家知名大型機構客戶提供加密金融服務,在 100 多個電子交易所中累計交易總額已超過 1 兆美元,資產管理規模超過 50 億美元,幫助客戶管理各種加密資產的風險,提供靈活化的投資、最大化的回報來優化長期價值。
免責聲明:
本文觀點僅代表作者個人觀點,不構成本平台的投資建議,本平台不對文章信息準確性、完整性和及時性作出任何保證,亦不對因使用或信賴文章信息引發的任何損失承擔責任
0.00