ctfwriteup.com
Search…
⌃K

Puzzle 8

Puzzle

############
# Puzzle 8 #
############
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
? Enter the calldata:

Solution

NOT may behave differently than what you think: it flips every single byte in its input. In high-level languages, the NOT operation turns 0 to 1 and 1 to 0. This is different from what we have here.

Chunk 1

00 34 CALLVALUE
01 15 ISZERO
02 19 NOT
03 6007 PUSH1 07
05 57 JUMPI
06 FD REVERT
07 5B JUMPDEST
msg.value can not be 0.

Chunk 2

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
Pseudocode:
calldatacopy(0, 0, calldata_size);
new_address = create(0, 0, calldata_size);
call_success = call(gas, new_address, address(this).balance, 0, 0, 0, 0);
if (call_success) {
jump(0x28);
}

Chunk 3

29 47 SELFBALANCE
2A 14 EQ
2B 602F PUSH1 2F
2D 57 JUMPI
2E FD REVERT
2F 5B JUMPDEST
30 00 STOP
It requires the new balance equals to the old balance.

Building calldata

The new contract should not keep any balance when CALL sends balance to it. My idea is to let the contract selfdestruct and send the balance back to the caller.
Runtime code:
PUSH1 0x33 // opcode for CALLER
PUSH1 0x20
MSTORE8
PUSH1 0xFF // opcode for SELFDESTRUCT
PUSH1 0x00
MSTORE8
PUSH1 0x40
PUSH1 0x00
RETURN
Basically this contract only executes selfdestruct(caller) to send the balance back to the challenge contract.
Compile:
603360205360ff60005360406000f3
Creation code:
PUSH15 0x603360205360ff60005360406000f3 // runtime code
PUSH1 0x00
MSTORE
PUSH1 0x0F
PUSH1 0x11
RETURN
Compile:
6e603360205360ff60005360406000f3600052600f6011f3
Last modified 1d ago