This is the first in the Ethernaut write-up series by CAPS LOCK DAVE.
LEVEL 0 CAN BE FOUND HERE
This level serves as the tutorial and guides us through the setup needed to participate in the CTF.
We need:
- MetaMask Wallet with Testnet Ether
- Web Browser Console (Dev Tools)
Connecting our MetaMask wallet will allow us to track our progress and create a new instance of the challenge contracts, which are actually deployed to the Goerli testnet.
Opening up the console we can see a welcome message and some addresses, as well as a help() command that can give us more info on commands that may be useful.
Following some of the tutorial commands, we can see that player returns my wallet address, getBalance(player) returns my wallet balance, and the help() command returns a list of methods that we can use.
(Note: I’m using Chrome Dev Tools so I use await before most methods to directly return the value, some other browsers might not have this need.)
Next we need to request an instance of the level so that we can complete it.
Clicking Get new instance should make a MetaMask transaction popup for you to sign.
After signing this transaction, wait for it to be mined, and your instance will be created.
Now we can start inspecting the contract using the contract.info() method.
After following some tricky methods we have been lead to this last hint, ‘If you know the password, submit it to authenticate().’
I think we have figured out how to solve the level, now we need the password.
Let’s do some digging into the abi with contract.abi.
In the abi we can see a method named password, let’s try that and see if we can authenticate.
Once we send the password using the authenticate method a transaction should popup for you to sign.
Once the transaction has been mined we are ready to submit our instance.
Ethernaut gives us this colorful congratulations message, we’ve completed this level.
The contract code is revealed to us to show what we have been interacting with from the console.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Instance {
string public password;
uint8 public infoNum = 42;
string public theMethodName = 'The method name is method7123949.';
bool private cleared = false;
// constructor
constructor(string memory _password) {
password = _password;
}
function info() public pure returns (string memory) {
return 'You will find what you need in info1().';
}
function info1() public pure returns (string memory) {
return 'Try info2(), but with "hello" as a parameter.';
}
function info2(string memory param) public pure returns (string memory) {
if(keccak256(abi.encodePacked(param)) == keccak256(abi.encodePacked('hello'))) {
return 'The property infoNum holds the number of the next info method to call.';
}
return 'Wrong parameter.';
}
function info42() public pure returns (string memory) {
return 'theMethodName is the name of the next method.';
}
function method7123949() public pure returns (string memory) {
return 'If you know the password, submit it to authenticate().';
}
function authenticate(string memory passkey) public {
if(keccak256(abi.encodePacked(passkey)) == keccak256(abi.encodePacked(password))) {
cleared = true;
}
}
function getCleared() public view returns (bool) {
return cleared;
}
}
That’s it for level 0, time to move on to the first real challenge.
DAVE