Ethernaut Puzzle 17 Recovery

The gist of this question is that the “Recovery” contract created a “SimpleToken” contract but lost the address of the SimpleToken contract. Now, the goal is to find the address of the SimpleToken contract and transfer the ETH inside it.

One convenient method is to check Etherscan, below shows a transaction generated when creating this task.

https://goerli.etherscan.io/tx/0xb434bb56783dad258111a8529709e92dee13fd29c37eb83223037382d7f6e692#internal

Next, we need to identify the account that holds 0.001 ETH to determine the target smart contract.

However, there is another method to calculate the address of the generated smart contract based on the existing smart contract’s address.

address = rightmost_20_bytes(keccak(RLP(sender address, nonce)))

From the ethereum yellow paper, it says:

The address of the new account is defined as being the rightmost 160 bits of the Keccak-256 hash of the RLP encoding of the structure containing only the sender and the account nonce.

  1. First, the sender’s address and the nonce of the transaction are encoded using the RLP (Recursive Length Prefix) encoding. RLP is a serialization method used to encode different types of data into byte arrays.
  2. Next, the encoded data is hashed using the Keccak-256 hash function. Keccak-256 is a cryptographic hash function that transforms arbitrary-length input into a fixed-length output.
  3. Finally, the rightmost 20 bytes (160 bits) are extracted from the hash result and interpreted as an Ethereum address.

Regarding how to calculate it in Solidity, you can refer to this answer:

https://ethereum.stackexchange.com/questions/760/how-is-the-address-of-an-ethereum-contract-computed/761#761

Now we can proceed, below is my code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// SPDX-License-Identifier: MIT
pragma solidity ^0.4.21;


interface IChallenge {

function destroy(address _to) external;
}

contract Challenge {
IChallenge challenge;
address lostcontract;

constructor() {
lostcontract = address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), address({%YOUR_CHALLENGE_ADDRESS%}), bytes1(0x01))))));
challenge = IChallenge(lostcontract);
}

function attack() external {
challenge.destroy({%YOUR_ADDRESS%});
}
}