Skip to content

HrideshG88/ethernaut_exploits

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

71 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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

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

means last 4 characters of player address 0x62cE

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

means zeroes before last 4 characters of key. 0x000062cE

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.

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

 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

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

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

LEVEL 30 higherorder

> ### THINGS TO AVOID <br>
>
> 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

About

Solving ethernaut challenges

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published