zombie
> > > >
> > > >

DeFi 乾貨|Position Exchange 重入漏洞解析

2022/05/27 17:30
DeFi 乾貨|Position Exchange 重入漏洞解析

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 的六個步驟:

  1. 攻擊者創建一個惡意合約 Exp,並從 Exp 呼叫 stake() 函數。如上圖所示,為了成功做到後續的劫持操作,此惡意合約 Exp 實現了一個外部函數 onERC721Received();
  2. 攻擊者從 Exp 合約觸發了 unstake() 函數;
  3. 透過 safeTransferFrom(),Exp 合約成功劫持了 unstake() 函數的調用;
  4. 從 Exp 合約重新進入 stake() 函數,使其之後能夠調用第二次 unstake() 函數;
  5. 當 Exp 合約返回到被劫持的 unstake() 調用時,第四步驟設置的 _stakeWeightes 會被重置設為 0;
  6. 攻擊者發出第二個 unstake() 調用並使用歸零的 _stakeWeightes 篡改 _weightBalances 變數。

透過上述步驟,攻擊者可以只用一個 NFT 持續累積 _weightBalances,並且可以在沒有質押任何 NFT 的情況下,透過 NFTReward 合約中的 harvest() 函數不斷獲取獎勵。

下方惡意合約的程式碼說明了我們如何模擬攻擊。 在 trigger() 函數中,我們執行了多次 [stake(), unstake(), unstake()] 調用。 每當 unstake() 將 NFT 轉移回惡意合約時,onERC721Received() 函數就會劫持 unstake() 並在 flag 為 true 時發出另一個 stake() 調用,這就是重入攻擊竄改狀態的流程。

下方的 eth-brownie 截圖證明了我們的猜想。 具體來說,我們:

  1. 通過 eth-brownie 的模擬,「借用」了 NFT #1183410;
  2. 在 NFTReward 合約上竄改狀態;
  3. 「歸還」該 NFT;
  4. 收穫獎勵。

最後,我們的駭客在沒有質押任何 NFT 的情況下以 4.93 POSI 獲利出場,這也間接證明了攻擊者可以創建多個合約,為每個合約偽造狀態,並透過來回轉移同一個 NFT 來獲得獎勵。

0x03 時間軸和緩解措施

該漏洞於 3 月 9 日通過 ImmuneFi 提交;3 月 21 日,Position Exchange 團隊確認了該問題,並將其評為高危漏洞; 3 月 22 日,我們觀察到一個新的 NFTReward 合約被部署上鏈,此合約加入了 reentrancy guard。 但自那以後,我方仍未能收到 Position Exchange 團隊的任何回覆。

完整的時間軸如下圖所示:

2022/03/09 提交

2022/03/21 確認

2022/03/22 修復

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

除了 Position Exchange,我們還聯繫了 Dego FinanceSmarty Pay。兩方都部署了類似的 NFTReward 合約,且其中含有類似的漏洞。Dego Finance 團隊的處理方式是透過將 DEGO 代幣轉移到新代幣。 與此同時,Smarty Pay 團隊升級了他們的 NFTReward 合約,並將所有的用戶狀態遷移到了新版本。 據我們了解,這三個具有漏洞的項目,在我們披露細節之前皆沒有被真的攻擊。

關於 Amber Group

成立於 2017 年,業務遍及亞洲及歐美各大主要城市,現為 1,000 多家知名大型機構客戶提供加密金融服務,在 100 多個電子交易所中累計交易總額已超過 1 兆美元,資產管理規模超過 50 億美元,幫助客戶管理各種加密資產的風險,提供靈活化的投資、最大化的回報來優化長期價值。

若有產品相關問題,請聯繫 Amber 客服團隊:
[email protected][email protected]

join Zombit

加入桑幣的社群平台,跟我們一起討論加密貨幣新資訊!

Amber Group

Amber Group

桑幣熱門榜

zombie

桑幣正在徵文中,我們想要讓好的東西讓更多人看見!
只要是跟金融科技、區塊鏈及加密貨幣相關的文章,都非常歡迎向我們投稿
投稿信箱:[email protected]

為提供您更多優質的服務與內容,本網站使用 cookies 分析技術。若您繼續閱覽本網站內容,即表示您同意我們使用 cookies,關於更多相關隱私權政策資訊,請閱讀我們的隱私權及安全政策宣示