Ethernaut Vault

Blockchain and Secrets

One of the important properties of Blockchain technology is Transparency.

Transparency means that the blockchain ledger is public. That anyone can access and view the transactions on the network. This makes it a highly transparent system that is resistant to fraud and corruption.

However, sometimes it is necessary to store secrets for a given use case. The fact that this property exist makes it very dangerous to store any sensitive data on the blockchain, as anyone can access it and read it.

In the following challenge we will see how a developer tried to program a Smart Contract Vault that is secured or locked by a password stored on the Smart Contract’s storage:

A Word on Visibility and Storage

In Solidity, state variables can be declared as public, private, or internal. One might assume that the private visibility defines some kind of confidentiality property to the state variable it refers to.

The real difference here is just regarding the scope of access and not the confidentiality of the values:

  • public: the compiler automatically generates getter functions for them, which allows other contracts to read their values. Setter functions are not generated so other contracts cannot directly modify their values;
  • internal: can only be accessed from within the contract they are defined in and in derived contracts. They cannot be accessed externally;
  • private: these are just like internal variables but they are not visible in derived contracts.

Furthermore, the storage layout of smart contracts, where state variables are written to, is divided up into ²²⁾⁜ slots of 32 bytes each. These slots are contiguous and referenced by indexes, starting at 0 and ending at ²²⁾⁜. All slots are initialised to a value of 0.

The following image illustrates how the challenge state variables would be stored:

Exploitation Steps

As we can see in the code and based on the above, the declaration of the password state variable being private does not mean the value is confidential.

To unlock the vault, all that is needed is to read the value stored on the correct slot of the (public) storage and then use it as parameter of the unlock() function of the contract:

Running the Exploit

root@Web3 ❯ brownie run --network sepolia -i pwn.py
Brownie v1.19.3 - Python development framework for Ethereum
EthernautvaultProject is the active project.
Running 'scripts/pwn.py::main'...
[+] Vault deployed @ 0x17ac25Bf7F59C50077AEeBD4CE71E660eA02D1f1
[+] Vault Locked Status: True
[+] Vault Password is: A very strong secret password :)
[+] Unlocking vault...
Transaction sent: 0xa9b4a0248a646b0ebad4f596ff5364aa515d2a5a217d3202e22f55807458b9aa
Gas price: 0.175156965 gwei Gas limit: 31837 Nonce: 25
Vault.unlock confirmed Block: 4192074 Gas used: 24143 (75.83%)
[+] Vault Locked Status: False
Interactive mode enabled. Use quit() to close.

References

Big props to @the_ethernaut for creating the content.

Share: Twitter LinkedIn