An open API service indexing awesome lists of open source software.

https://github.com/singularity0x00/ethernaut_exploits

Solving ethernaut challenges
https://github.com/singularity0x00/ethernaut_exploits

Last synced: 3 months ago
JSON representation

Solving ethernaut challenges

Awesome Lists containing this project

README

          

# EXPLOIT CONTRACTS FOR ETHERNAUT
# LEVEL 0 hello_ethernaut

player
"0x3A22d5B698CCb49b51B7B4D953a8Abb8F8a562cE"

# LEVEL 1 fallback

player
"0x3A22d5B698CCb49b51B7B4D953a8Abb8F8a562cE"

Owner Address
0x3c34A342b2aF5e885FcaA3800dB5B205fEfa3ffB

Send eth without data to hit `recieve` and bypass `contribute() require(msg.value < 0.001 ether);`

# LEVEL 2 fallout

Send eth to fal1out function and become owner.
sollidity 0.6 constructor is declared by giving it same name as contract.
but fallout != fal1out
so fal1out is public payable and has no onlyowner + owner = msg.sender.

# LEVEL 3 coin_flip

copy function to exploit contract if true call coin_flip contract.
repeat till 10 consecutive wins.

# LEVEL 4 telephone

create a contract which calls changeowner on this contract.
profit!!!

# LEVEL 5 token

simple overflow.

# LEVEL 6 delegation

delegate call missuse exploiting context. send 0xdd365b8b via low lvl transaction with your own acc.

# LEVEL 7 force

selfdestruct and boom!!!

# LEVEL 8 vault

```
web3.eth.getStorageAt(addr, 1, console.log)
> null 0x412076657279207374726f6e67207365637265742070617373776f7264203a29

web3.utils.toAscii("0x412076657279207374726f6e67207365637265742070617373776f7264203a29")
'A very strong secret password :)'
```

# LEVEL 9 king

exploit contract becomes king but has no recieve or fallback function breaking the recieve function in king contract

# LEVEL 10 reentrancy

Straightforward reentrancy attack.

# LEVEL 11 elevator

send false when function is first called and true when it is called again.

# LEVEL 12 privacy

```
// get the entry of data array at index 2.
await web3.eth.getStorageAt(contract.address, 5, console.log)
"0x14690fdf857625e4fe6f798d6ad3c7dbf82a6b1a6c9c082c0c6cfca4d394c4b1"

// convert 32 bytes to 16. (strip the last 16 bytes) and get the key

0x14690fdf857625e4fe6f798d6ad3c7db
```

# LEVEL 13 gatekeeperone

### Gateone

basically telephone challenge.

### Gatetwo

> gasleft() % 8191 == 0; ????????

BruteForce gas to send in local foundry env.

### Gatethree

```sol
require(uint32(uint64(_gateKey)) == uint16(uint160(tx.origin)), "GatekeeperOne: invalid gateThree part three");
```

means last 4 characters of player address `0x62cE`

```sol
require(uint32(uint64(_gateKey)) == uint16(uint64(_gateKey)), "GatekeeperOne: invalid gateThree part one");
```

means zeroes before last 4 characters of key. `0x000062cE`

```sol
require(uint32(uint64(_gateKey)) != uint64(_gateKey), "GatekeeperOne: invalid gateThree part two");
```

means random non-zero 8 characters for the rest ??? `0x53a8abb8000062ce`

# LEVEL 14 gatekeepertwo

While constructor is running for a contract `EXTCODESIZE` for it's address will return 0.

### SIMPLE THING TO REMEMBER:

> msg.sender == address of exploit contract for target. xD

# LEVEL 15 naught_coin

1. From main acc approve acc2 to be able to withdraw all tokens.
2. Use allowance function to verify approval.
3. From acc2 use transfer from function to withdraw all tokens.

# LEVEL 16 preservation

Unsafe delegate call use where it is possible to override variables of the contract. Once we can control the address of the contract it delegates to we can run our own code inside the contract.
**Smart contract version of RCE **.

# LEVEL 17 recovery

address for new contract in solidity by create opcode is computed by kecchak256(relp(sender, nonce))
Sender would be instance address(0xe473eF11db6be3F1bA29F3b8bc5B4e33D75E634f)

so using the sender we can generate possible addresses and find the lost address.
Once found just call self destruct to recover all eth inside contract.

# LEVEL 18 magic_number

low level

# LEVEL 19 alien_codex

cause the Codex[] to underflow using retract function. then overwrite the owner state variable using revise function.

# LEVEL 20 denial

set receive function such that it consumes all gas.

# LEVEL 21 shop

Just like the elevator but view functions cannot modify state variables hence gotta improvise and use conditionals to pass the if() check in buy function.

# LEVEL 22 dex

## TEST1

spender - dexinstance
| mytokens (start) | 1 swap usd->inr | 2 swap | 3 swap |
| ----------------- | ---------------- | -------- | ------ |
| usd - 10 | 9 | 8 | 7 |
| inr - 10 | 11 | 11 | 11 |
| dextokens(start) | ---------------- | -------- | ------ |
| ----------------- | ---------------- | -------- | ------ |
| usd - 100 | 101 | 102 | 103 |
| inr - 100 | 99 | 99 | 99 |

swap price (1 swap usd->inr)->(2 swap)->(3 swap)
1 token -> 0 -> 0 -> 0
100 token -> 98 -> 97 -> 96
swap ammount 0 hence inr not increasing in above table.

swap price (1 swap inr->usd)->(2 swap)->(3 swap)
1 token -> _ -> _-> 1
100 token -> _ -> _-> 104

!('./dexbrainstorming.png')

INCREASE THE `swap amount` TO DRAIN THE DEX CONTRACT.

so basically swap from token1 to token2 and then swap from token2 to token1 and vice versa, until you can empty tokens from dex contract.

# LEVEL 23 dextwo

Can I deploy my own tokens??? yeah.
Create Fake tokens and give dex2 just 10 so that 10 of fake 100 of dex2's.

# LEVEL 24 puzzlewallet

transparent upgradeable proxy.(upgrade and admin logic handled by proxy itself)

> address(uint160(maxbalance)) == admin address....... wtf..

can make proxy balance zero by delegating call to `execute`. provided player and wallet contract have enough balance

- step 1: call `proposeNewAdmin(address)`and become pending admin.
- step 2: call `addToWhitelist(address)` and become Whitelisted.
- step 3: use multicall with \["deposit","multicall(deposit)"] as parameter to rick contract into calling deposit twice
- step 4: call execute to empty the balance.
- step 5: call set maxBalance to becom admin.

> proxy's fallback function delegates call to implementation and there is a collision in state variables which can be exploited to cause chaos

# LEVEL 25 motorbike

## PRE DECUN SOLUTION

Get the implementation address.

```javascript
await web3.eth.getStorageAt(
contract.address,
"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc",
);
```

initialize the implementation to become upgrader then call `upgradeToAndCall()` func with exploit contract addr and selfdestruct func identifier.

## AFTER DECUN UPDATE (courtesy of https://github.com/Ching367436)

The selfdestruct function will no longer remove the contract code after the upgrade, so the above solution will not work.

so we would need to use a contract to call ethernaut contract to create an instance and the in the same transaction perform the above exploit to solve the challenge. but still won't appear on the ethernaut client side.

my solution txn:

https://sepolia.etherscan.io/tx/0x05599a912ee760312d6a5585762887b4bc499022b100cd31c73867bb7d9666ab

# LEVEL 26 doubleentrypoint

LegacyToken can delegate to new contract so if legacy token delegates to DET, DET can be swept from vault.
bot should monitor delegateToNewContract function of Legacytoken.

# LEVEL 27 good_samaritan

Backdoor function `notify` inside of coin contract can be leveraged to pass custom error value like `NotEnoughBalance()` which will make the good samaritan contract jump into `catch` statement and give us tokens.

# LEVEL 28 gatekeeperthree

StraightForwad.
get password from trick's storage -> put >0.001 eth into gatekeeper-> deploy a contract without fallback or recieve and call constructor for gatekeeper. enter.

> why did I not directly fund gatekeeper and used a hacky way instead?? realized later lol.

# LEVEL 29 switch

```sol
assembly {
calldatacopy(selector, 68, 4) // grab function selector from calldata
}
```

Copies 4 bytes from the calldata from the 68th byte to write to memory at location `selector`. where,
`selector` can only be `offSelector`

**Copies 4 bytes from the calldata from the 68th byte** means we can control the calldata as long as `0x20606e15` is present at 68th byte of calldata.

## Exploit calldata

```javascript
await sendTransaction({
from: player,
to: contract.address,
data: "0x30c13ade0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000020606e1500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000476227e1200000000000000000000000000000000000000000000000000000000",
});

await contract.switchOn(); // should return true
```

# LEVEL 30 higherorder

```DOCS
> ### THINGS TO AVOID

>
> Inline assembly might have a quite high-level look, but it actually is extremely low-level. Function calls, loops, ifs and switches are converted by simple rewriting rules and after that, the only thing the assembler does for you is re-arranging functional-style opcodes, counting stack height for variable access and removing stack slots for assembly-local variables when the end of their block is reached.
```

While solidity does enforce type-checking **_EVM does not_**.
By sending a low level call to `registerTreasury(uint8)` function we can bypass the restriction of uint8 type as it is enforced by solidity and not by the EVM.

> ABI encoder v2 impliments type checking safegaurds for contracts compiled with sol v0.8.0 onwards

# LEVEL 31 stake

`0xdd62ed3e , 0x23b872dd` are vuln to collisions.

`0x23b872dd: transferFrom(address,address,uint256) `

`0xdd62ed3e: allowance(address,address)`

contract does not handle false return for low level calls.
can stake weth without having any.

- step 1: use another EOA to fund stake with 0.002 ether.
- step 2: sendETH 8000000000000000 wei
- step 3: send Weth "2000000000000000" weth
- step 4: unstake 9900000000000000 such that contract eth = 0.0001
- step 5: unstake remaining stake

this works because ` (bool success, ) = payable(msg.sender).call{value : amount}("");` in function `Unstake(uint256)` will give you ether if contract has enough balance othwerwise it will pay in weth