
Safe space, a place to be vulnerable
ΞthernautDAO is common goods DAO aimed at transforming developers into Ethereum developers. Author: https://twitter.com/StErMi They started releasing CTF challenges on Twitter, so how couldn’t I start solving them?CTF 2: WalletThe challenge starts with this Tweet: https://twitter.com/EthernautDAO/status/1546101932040790016?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1546101932040790016%7Ctwgr%5E%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fcdn.embedly.com%2Fwidgets%2Fmedia.html%3Ftype%3Dtext2...

Ethernaut Wei series presents: wasp
A place where developers tell their stories of how they became part of web3.Donate and get one of these NTFs here!What did you do before getting into web3?Starting in college, my goal was to become a doctor. I spent almost my entire undergrad preparing for medical school until my senior year when I decided on a whim to take an Intro to Java course that forced me to revaluate many decisions concerning my career and life aspirations.I decided to pick up a second major in Computer Science and I ...

Ethernaut Wei series presents: Crisgarner (mentor)
A place where developers tell their stories of how they became part of web3.This is Crisgarner's Ethernaut NFT!Donate and get one of these NTFs here!What did you do before getting into web3?I was obsessed with entrepreneurship, created many tech startups (all failed), also was organizing events for entrepreneurs, taught formally entrepreneurship in a college, and even had my own startup incubator. What were the first things you did in web3?I did a lot of simple projects to get to know we...
A common goods DAO aimed at transforming developers into Ethereum developers.

Safe space, a place to be vulnerable
ΞthernautDAO is common goods DAO aimed at transforming developers into Ethereum developers. Author: https://twitter.com/StErMi They started releasing CTF challenges on Twitter, so how couldn’t I start solving them?CTF 2: WalletThe challenge starts with this Tweet: https://twitter.com/EthernautDAO/status/1546101932040790016?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1546101932040790016%7Ctwgr%5E%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fcdn.embedly.com%2Fwidgets%2Fmedia.html%3Ftype%3Dtext2...

Ethernaut Wei series presents: wasp
A place where developers tell their stories of how they became part of web3.Donate and get one of these NTFs here!What did you do before getting into web3?Starting in college, my goal was to become a doctor. I spent almost my entire undergrad preparing for medical school until my senior year when I decided on a whim to take an Intro to Java course that forced me to revaluate many decisions concerning my career and life aspirations.I decided to pick up a second major in Computer Science and I ...

Ethernaut Wei series presents: Crisgarner (mentor)
A place where developers tell their stories of how they became part of web3.This is Crisgarner's Ethernaut NFT!Donate and get one of these NTFs here!What did you do before getting into web3?I was obsessed with entrepreneurship, created many tech startups (all failed), also was organizing events for entrepreneurs, taught formally entrepreneurship in a college, and even had my own startup incubator. What were the first things you did in web3?I did a lot of simple projects to get to know we...
A common goods DAO aimed at transforming developers into Ethereum developers.

Subscribe to EthernautDAO

Subscribe to EthernautDAO
Share Dialog
Share Dialog


<100 subscribers
<100 subscribers
https://twitter.com/giovannidisiena
Reading Private Data
If you have some familiarity with Solidity smart contracts then you will have come across state variable visibility – public, internal, and private. Although it sounds counter to what you might expect, the key takeaway from this challenge is that anyone can read the value stored in a private variable.
Repeat after me:
private variables aren’t private
This keyword refers only to the ability of an external contract to access the variable, while to Shadowy Super Coders th
e value is accessible via inspecting the contract storage layout and reading the corresponding slot directly.
To pull off the hack we are going to be using Foundry (big up Georgios & Co). If you don’t already have it installed then go ahead and run curl -L https://foundry.paradigm.xyz | bash before running foundryup in a new session. Additional documentation is available in the official repo and book.
We will first create a new directory and initialize a new Forge project like so:
mkdir private-data && cd $_ && forge init
Go ahead and copy the contract code to PrivateData.sol. We’ll need this to inspect the contract storage layout (and if you wanted to run tests against a local fork using anvil).
The easiest method for inspecting the storage layout really is as simple as:
forge inspect PrivateData storage —pretty

From this, we can see that the variable secretKey corresponds to storage slot 8.
To arrive at the same result without the power of Forge, you would need to apply storage layout rules manually, understanding that the EVM stores state variables in 32-byte slots and performs slot packing, such that these variables get stored in a single slot, if successive declarations sum to no more than 32 bytes:
NUM is inlined to contract bytecode at compile time since it is a constant variable
owner is of address type, which is 20 bytes, and occupies storage slot 0
randomData is a constant-size array of bytes32 and occupies 160 bytes, from storage slot 1 to slot 5
addressToKeys mapping has an unpredictable size, so the elements it contains are stored starting at a different storage slot that is computed using a keccak hash which is stored at storage slot 6
a and b are both of type uint128 which together pack to 32 bytes and as such both occupy slot 7
secretHash therefore occupies storage slot 8
Regardless of which method you choose, once you have the desired storage slot it is again as simple as running the following command to read the value stored:
cast storage 0x620E0c88E0f8F36bCC06736138bDEd99B6401192 8 --rpc-url https://eth-goerli.g.alchemy.com/v2/${ALCHEMY_GOERLI_ID}

And there it is! We have the secret key.
Now to take ownership of the contract, send a transaction with:
cast send 0x620E0c88E0f8F36bCC06736138bDEd99B6401192 --rpc-url https://eth-goerli.g.alchemy.com/v2/${ALCHEMY_GOERLI_ID} --private-key ${PRIVATE_KEY} "takeOwnership(uint256)()" 0x43223b17c0688af05eea8efbd2b6c424174874f5945a09fce2e3fa1afb6984b7
And view the current owner with:
cast call 0x620E0c88E0f8F36bCC06736138bDEd99B6401192 --rpc-url https://eth-goerli.g.alchemy.com/v2/${ALCHEMY_GOERLI_ID} "owner()(address)”
Of course, you could also use our newfound superpower and read the storage slot 0 directly.
As a quick aside, it is important to note that you should not rely on block data for randomness, as explained here and rndString is visible on Etherscan as a decoded constructor argument.

A slightly improved solution could be storing the keccak hash of the secret key in a commit-reveal type fashion, so as not to expose the key itself, and validating input against this; however, it is still of course flawed in that the correct key will become visible to everyone once someone crafts a successful transaction.

I hope that was helpful – happy hacking!
https://twitter.com/giovannidisiena
Reading Private Data
If you have some familiarity with Solidity smart contracts then you will have come across state variable visibility – public, internal, and private. Although it sounds counter to what you might expect, the key takeaway from this challenge is that anyone can read the value stored in a private variable.
Repeat after me:
private variables aren’t private
This keyword refers only to the ability of an external contract to access the variable, while to Shadowy Super Coders th
e value is accessible via inspecting the contract storage layout and reading the corresponding slot directly.
To pull off the hack we are going to be using Foundry (big up Georgios & Co). If you don’t already have it installed then go ahead and run curl -L https://foundry.paradigm.xyz | bash before running foundryup in a new session. Additional documentation is available in the official repo and book.
We will first create a new directory and initialize a new Forge project like so:
mkdir private-data && cd $_ && forge init
Go ahead and copy the contract code to PrivateData.sol. We’ll need this to inspect the contract storage layout (and if you wanted to run tests against a local fork using anvil).
The easiest method for inspecting the storage layout really is as simple as:
forge inspect PrivateData storage —pretty

From this, we can see that the variable secretKey corresponds to storage slot 8.
To arrive at the same result without the power of Forge, you would need to apply storage layout rules manually, understanding that the EVM stores state variables in 32-byte slots and performs slot packing, such that these variables get stored in a single slot, if successive declarations sum to no more than 32 bytes:
NUM is inlined to contract bytecode at compile time since it is a constant variable
owner is of address type, which is 20 bytes, and occupies storage slot 0
randomData is a constant-size array of bytes32 and occupies 160 bytes, from storage slot 1 to slot 5
addressToKeys mapping has an unpredictable size, so the elements it contains are stored starting at a different storage slot that is computed using a keccak hash which is stored at storage slot 6
a and b are both of type uint128 which together pack to 32 bytes and as such both occupy slot 7
secretHash therefore occupies storage slot 8
Regardless of which method you choose, once you have the desired storage slot it is again as simple as running the following command to read the value stored:
cast storage 0x620E0c88E0f8F36bCC06736138bDEd99B6401192 8 --rpc-url https://eth-goerli.g.alchemy.com/v2/${ALCHEMY_GOERLI_ID}

And there it is! We have the secret key.
Now to take ownership of the contract, send a transaction with:
cast send 0x620E0c88E0f8F36bCC06736138bDEd99B6401192 --rpc-url https://eth-goerli.g.alchemy.com/v2/${ALCHEMY_GOERLI_ID} --private-key ${PRIVATE_KEY} "takeOwnership(uint256)()" 0x43223b17c0688af05eea8efbd2b6c424174874f5945a09fce2e3fa1afb6984b7
And view the current owner with:
cast call 0x620E0c88E0f8F36bCC06736138bDEd99B6401192 --rpc-url https://eth-goerli.g.alchemy.com/v2/${ALCHEMY_GOERLI_ID} "owner()(address)”
Of course, you could also use our newfound superpower and read the storage slot 0 directly.
As a quick aside, it is important to note that you should not rely on block data for randomness, as explained here and rndString is visible on Etherscan as a decoded constructor argument.

A slightly improved solution could be storing the keccak hash of the secret key in a commit-reveal type fashion, so as not to expose the key itself, and validating input against this; however, it is still of course flawed in that the correct key will become visible to everyone once someone crafts a successful transaction.

I hope that was helpful – happy hacking!
No activity yet