banner
zach

zach

github
twitter
medium

damn-vulnerable-defi | Unstoppable

Challenge #1 - Unstoppable#

Unstoppable

合约#

  • 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);
    });
加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。