banner
zach

zach

github
twitter
medium

該死的易受攻擊的DeFi | 不可阻擋

挑战 #1 - 不可阻挡#

不可阻挡

合約#

  • ReceiverUnstoppable:繼承 IERC3156FlashBorrower 合約,用於發起閃電貸款,執行閃電貸款後的回調
  • UnstoppableVault:金庫合約,繼承 IERC3156FlashLender、ERC4626,支援閃電貸款

腳本#

  • 依次部署 DamnValuableToken、UnstoppableVault 合約
  • 存入 TOKENS_IN_VAULT 數量的 token 到金庫中,轉入 player 使用者 INITIAL_PLAYER_TOKEN_BALANCE 數目的 token
  • 部署 ReceiverUnstoppable 合約
  • 執行攻擊腳本
  • 期望 ReceiverUnstoppable 執行閃電貸款的交易被 revert

題解#

攻擊目標是使得通過 ReceiverUnstoppable 合約發起的 executeFlashLoan 方法被 revert,首先分析 executeFlashLoan 的調用流程

image

重點在 UnstoppableVault.flashLoan 方法,分別會進行以下操作:

  • 計算閃電貸款開始前的餘額:totalAssets ()
  • 計算當前的 share:convertToShares (totalSupply) 是否與前面計算出來的餘額一致
  • 計算閃電貸款手續費:flashFee
  • 轉移 amount 個 token 到 receiver,再調用 receiver 的 onFlashLoan 方法執行回調
  • 從 receiver 方轉回 amount+fee 數目的 token
  • 將 fee 轉移給 feeRecipient 帳戶,完成本次閃電貸款

若要使交易 revert,關鍵的校驗點在於使得:convertToShares(totalSupply) != totalAssets()

這兩個函數都是 ERC4626 中的定義,關於此協議可參考下面的文章:
WTF-Solidity/51_ERC4626/readme.md at main · WTFAcademy/WTF-Solidity

簡單來說就是 ERC20 的組合:資產代幣 asset 和份額代幣 share,存入資產或提取資產時都會相對應的鑄造或銷毀對應數目的 share 代幣

  • totalAssets():計算的是當前金庫中的資產代幣數目
  • convertToShares(totalSupply):totalSupply 是總的 share 代幣數目(只有 deposit 或 mint 時才會產生),convertToShares 就是計算:assets * totalSupply /totalAssets ()

要想使得兩者不一致,只要不通過 depost 或 mint 方法向 UnstoppableVault 中轉入 token 即可,因此攻擊腳本內容如下:

it('Execution', async function () {
        /** CODE YOUR SOLUTION HERE */
        const dvtForPlayer  = token.connect(player);
        await dvtForPlayer.transfer(vault.address,1);
    });
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。