✅Recovery
deterministic address
Description
A contract creator has built a very simple token factory contract. Anyone can create new tokens with ease. After deploying the first token contract, the creator sent 0.001
ether to obtain more tokens. They have since lost the contract address.
This level will be completed if you can recover (or remove) the 0.001
ether from the lost contract address.
Background Knowledge
https://medium.com/coinmonks/ethernaut-lvl-18-recovery-walkthrough-how-to-retrieve-lost-contract-addresses-in-2-ways-aba54ab167d3
Code Audit
The contract Recovery
creates a new instance of contract SimpleToken
, and the developer lost this contract address. Our job is to recovery the address and take out 0.001 ether from it.
Behind the scene, the keyword new
in Solidity uses the CREATE
opcode in EVM. Recall that contract address generated by CREATE
is deterministically computed. According to the Yellow Paper, the formula for computing such contract's address is:
sender address
is just the challenge contract address. In my case it is 0x41D8b9C48319614aB97BF7d9dF1e052835bc21C6.nonce
is a non-negative number that is incremented by 1 for each new contract creation. Nonce 0 is assigned to the creation of the challenge contract itself, so the token contract should have nonce 1.RLP
(Recursive Length Prefix) is a serialization method used extensively across Ethereum's execution layer. The RLP encoding of a 20-byte address is:0xd6, 0x94
. And for all integers less than0x7f
, its encoding is just its own byte value. So the RLP of 1 is0x01
.
Now we can compute the lost token contract address:
The easiest way is computing this in chisel
(it is installed when you install foundry
):
Now we can finish coding the solution contract.
Solution
Step 1: Copy and paste the content of contract SimpleToken
to Remix and save it as SimpleToken.sol
.
Step 2: Deploy the solution contract in Remix:
Note that Remix gives a warning on the checksum of the address we just computed. Just follow the instruction and modify it.
Step 3: Invoke pwn()
.
Summary
Contract addresses are deterministic and are calculated by keccak256(address, nonce)
where the address
is the address of the contract (or ethereum address that created the transaction) and nonce
is the number of contracts the spawning contract has created (or the transaction nonce, for regular transactions).
Because of this, one can send ether to a pre-determined address (which has no private key) and later create a contract at that address which recovers the ether. This is a non-intuitive and somewhat secretive way to (dangerously) store ether without holding a private key.
An interesting blog post by Martin Swende details potential use cases of this.
If you're going to implement this technique, make sure you don't miss the nonce, or your funds will be lost forever.
Further Reading
Learn more about RLP:
Last updated