Challenge 6:
The puzzles for these challenges are located in puzzles/
. Challenge 6 contains the following:
{
"code": "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03401600114602a57fd5b00",
"askForValue": true,
"askForData": false
}
Opcodes:
00 7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0 PUSH32 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0
21 34 CALLVALUE
22 01 ADD
23 6001 PUSH1 01
25 14 EQ
26 602A PUSH1 2A
28 57 JUMPI
29 FD REVERT
2A 5B JUMPDEST
2B 00 STOP
Solution:
This is simply an integer overflow. We need to add 0x10 to the value on top of the stack to make it 0x01. Thus, our callvalue simply has to be 17.
{"value":17,"data":"0x"}
Challenge 7:
The puzzles for these challenges are located in puzzles/
. Challenge 7 contains the following:
{
"code": "5a345b60019003806000146011576002565b5a90910360a614601d57fd5b00",
"askForValue": true,
"askForData": false
}
Opcodes:
00 5A GAS
01 34 CALLVALUE
02 5B JUMPDEST
03 6001 PUSH1 01
05 90 SWAP1
06 03 SUB
07 80 DUP1
08 6000 PUSH1 00
0A 14 EQ
0B 6011 PUSH1 11
0D 57 JUMPI
0E 6002 PUSH1 02
10 56 JUMP
11 5B JUMPDEST
12 5A GAS
13 90 SWAP1
14 91 SWAP2
15 03 SUB
16 60A6 PUSH1 A6
18 14 EQ
19 601D PUSH1 1D
1B 57 JUMPI
1C FD REVERT
1D 5B JUMPDEST
1E 00 STOP
Solution:
This one is the first challenge that contains a loop! Here is what all of this code does. First, it places the current gas on the top of the stack. Then, it creates a loop that it will go through CALLDATASIZE
times. Finally, once it exits the loop it will check that we have consumed precisely 0xa6 amount of gas. If we have we win! Otherwise, we fail. The pseudocode below demonstrates an interpretation of the puzzle’s path:
gas_num = GAS;
i = CALLDATASIZE;
while (i != 0) {
i--;
}
if ((gas_num - GAS) == 0xa6) {
STOP
} else {
REVERT
}
Ok, great so now we just need to exhaust 0xa6 in gas from the time the first GAS
is called.
Here are the costs of the OPCODES
CALLVALUE: 2
<LOOP>
JUMPDEST: 1
PUSH1 01: 3
SWAP1: 3
SUB: 3
DUP1: 3
PUSH1 00: 3
EQ: 3
PUSH1 11: 3
JUMPI: 10
PUSH1 02: 3
JUMP: 8
<END LOOP>
JUMPDEST: 1
GAS: 2
So we have 2 + (x(43)-11) + 3 = 166
solving for x we get 4 as our CALLVALUE
.
{"value":4,"data":"0x"}
Challenge 8:
The puzzles for these challenges are located in puzzles/
. Challenge 8 contains the following:
{
"code": "341519600757fd5b3660006000373660006000f047600060006000600047865af1600114602857fd5b4714602f57fd5b00",
"askForValue": false,
"askForData": true
}
Opcodes:
00 34 CALLVALUE
01 15 ISZERO
02 19 NOT
03 6007 PUSH1 07
05 57 JUMPI
06 FD REVERT
07 5B JUMPDEST
08 36 CALLDATASIZE
09 6000 PUSH1 00
0B 6000 PUSH1 00
0D 37 CALLDATACOPY
0E 36 CALLDATASIZE
0F 6000 PUSH1 00
11 6000 PUSH1 00
13 F0 CREATE
14 47 SELFBALANCE
15 6000 PUSH1 00
17 6000 PUSH1 00
19 6000 PUSH1 00
1B 6000 PUSH1 00
1D 47 SELFBALANCE
1E 86 DUP7
1F 5A GAS
20 F1 CALL
21 6001 PUSH1 01
23 14 EQ
24 6028 PUSH1 28
26 57 JUMPI
27 FD REVERT
28 5B JUMPDEST
29 47 SELFBALANCE
2A 14 EQ
2B 602F PUSH1 2F
2D 57 JUMPI
2E FD REVERT
2F 5B JUMPDEST
30 00 STOP
Solution:
Looking at the opcodes, we can see that we create a contract using whatever our calldata is then we get the balance of the calling account (which should be 0). Next, we call into our newly created contract with no value and no calldata and we need this to return 1 (no revert). Finally, we make sure we still have the same balance on this account (which started as 0).
To be honest I’m a bit thrown off by what the point of this level is. We can just send in basically anything to solve this.
{"data":"0x00","value":0}
Challenge 9:
The puzzles for these challenges are located in puzzles/
. Challenge 9 contains the following:
{
"code": "34600052602060002060F81C60A814601657FDFDFDFD5B00",
"askForValue": true,
"askForData": false
}
Opcodes:
00 34 CALLVALUE
01 6000 PUSH1 00
03 52 MSTORE
04 6020 PUSH1 20
06 6000 PUSH1 00
08 20 SHA3
09 60F8 PUSH1 F8
0B 1C SHR
0C 60A8 PUSH1 A8
0E 14 EQ
0F 6016 PUSH1 16
11 57 JUMPI
12 FD REVERT
13 FD REVERT
14 FD REVERT
15 FD REVERT
16 5B JUMPDEST
17 00 STOP
Solution:
What we’re doing here is taking the keccak256()
hash of our callvalue input and seeing if it begins with a8
. If it does then we win the challenge. This can be solved by brute forcing a valid solution.
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
contract solveKeccak {
function getDesiredCalldata() public view returns (uint256){
for (uint i; i < 1000; i++){
bytes32 hash = keccak256(abi.encodePacked(i));
if (bytes1(hash) == 0xa8) {
return i;
}
}
}
}
{"value":47,"data":"0x"}
Challenge 10:
The puzzles for these challenges are located in puzzles/
. Challenge 10 contains the following:
{
"code": "602060006000376000517ff0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f01660206020600037600051177fabababababababababababababababababababababababababababababababab14605d57fd5b00",
"askForValue": false,
"askForData": true
}
Opcodes:
00 6020 PUSH1 20
02 6000 PUSH1 00
04 6000 PUSH1 00
06 37 CALLDATACOPY
07 6000 PUSH1 00
09 51 MLOAD
0A 7FF0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0 PUSH32 F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0
2B 16 AND
2C 6020 PUSH1 20
2E 6020 PUSH1 20
30 6000 PUSH1 00
32 37 CALLDATACOPY
33 6000 PUSH1 00
35 51 MLOAD
36 17 OR
37 7FABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABAB PUSH32 ABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABAB
58 14 EQ
59 605D PUSH1 5D
5B 57 JUMPI
5C FD REVERT
5D 5B JUMPDEST
5E 00 STOP
Solution:
The final challenge! Basically, the first 32 bytes of our calldata will be part of an AND
operation with 0xF0F0F0...
. The reulst of this will then be part of an OR
operation with the next 32 bytes of our calldata. We want the result to be equal to ABABAB...
to solve the puzzle. The AND
operation will set everything the same as it comes in for odd positioned characters and flip the even positioned characters to 0. But we then get to send the result of this to the OR
operation. So, we can just send 0xABABAB...
for 64 bytes and call it a day.
{"data":"0xabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababab","value":0}