DEV Community

Cover image for Ethernaut - Lvl 8: Vault
pacelliv
pacelliv

Posted on

Ethernaut - Lvl 8: Vault

The Challenge:

Unlock the following Vault contract by changing locked to false.

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

contract Vault {
  bool public locked;
  bytes32 private password;

  constructor(bytes32 _password) {
    locked = true;
    password = _password;
  }

  function unlock(bytes32 _password) public {
    if (password == _password) {
      locked = false;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Inspecting the contract πŸ‘“

At creation time the constructor set the value of locked as true and password.

This contract only have a unlock function that takes a bytes32 _password as its only input parameter. If the provided password is equal to password then the contract is unlocked.

The hack πŸ‘©β€πŸ­πŸ‘¨β€πŸ­

password is a private state variable so if we try:

await contract.password()
Enter fullscreen mode Exit fullscreen mode

This call will throw with:

VM233:1 Uncaught TypeError: contract.password is not a function
    at <anonymous>:1:16
Enter fullscreen mode Exit fullscreen mode

This error is thrown because of the visibility of the variable.

Setting a state variable as private only prevents other smart contracts from accessing the data, but we need to remember that data stored in a public blockchain is not secret.

Using libraries like web3.js we can still read from the slots of contracts.

This is current storage layout of the contract:

slot          variable
-----------------------
0             locked
1             password
Enter fullscreen mode Exit fullscreen mode

Each variable occupies a slot, to read from the slots using web3.js we can use the getStorageAt(contractAddr, slot) method. This method take two parameters:

  • The address of the target contract.
  • The position of the slot to read.

password is stored in slot 1, to read from that slot with web3.js run the following command:

password = await web3.eth.getStorageAt(contract.address, 1)
Enter fullscreen mode Exit fullscreen mode

It should return:

// this is the password!
0x412076657279207374726f6e67207365637265742070617373776f7264203a29
Enter fullscreen mode Exit fullscreen mode

Now we only need to execute unlock:

await contract.unlock(password)
Enter fullscreen mode Exit fullscreen mode

After the transaction is mined check the value of locked:

await contract.locked() // should return false
Enter fullscreen mode Exit fullscreen mode

Submit the instance to complete the level.

Conclusion πŸ‘©β€πŸŽ“πŸ‘¨β€πŸŽ“

Setting state variables as private doesn't make the variable secret or inaccessible, all data stored in a public blockchain is accessible and readable by anyone, for this reason we should never stored sensitive data in public blockchains.

Further reading πŸ‘€

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (0)

The Most Contextual AI Development Assistant

Pieces.app image

Our centralized storage agent works on-device, unifying various developer tools to proactively capture and enrich useful materials, streamline collaboration, and solve complex problems through a contextual understanding of your unique workflow.

πŸ‘₯ Ideal for solo developers, teams, and cross-company projects

Learn more

πŸ‘‹ Kindness is contagious

Please leave a ❀️ or a friendly comment on this post if you found it helpful!

Okay