ctfwriteup.com
Search…
⌃K

Puzzle 8

GAS, CALL

Puzzle

############
# Puzzle 8 #
############
00 36 CALLDATASIZE
01 6000 PUSH1 00
03 80 DUP1
04 37 CALLDATACOPY
05 36 CALLDATASIZE
06 6000 PUSH1 00
08 6000 PUSH1 00
0A F0 CREATE
0B 6000 PUSH1 00
0D 80 DUP1
0E 80 DUP1
0F 80 DUP1
10 80 DUP1
11 94 SWAP5
12 5A GAS
13 F1 CALL
14 6000 PUSH1 00
16 14 EQ
17 601B PUSH1 1B
19 57 JUMPI
1A FD REVERT
1B 5B JUMPDEST
1C 00 STOP
? Enter the calldata:

Solution

00 36 CALLDATASIZE
01 6000 PUSH1 00
03 80 DUP1
04 37 CALLDATACOPY
Equivalent to CALLDATACOPY(0, 0, calldata_size).
05 36 CALLDATASIZE
06 6000 PUSH1 00
08 6000 PUSH1 00
0A F0 CREATE
Equivalent to CREATE(0, 0, calldata_size). Again, this means create a new contract and deposits 0 wei into it. The initialization code is at memory offset 0 and the length is the size of calldata.
0B 6000 PUSH1 00
0D 80 DUP1
0E 80 DUP1
0F 80 DUP1
10 80 DUP1
11 94 SWAP5
12 5A GAS
13 F1 CALL
This chunk pushes 5 0x00 onto the stack and swap the topmost element with the bottommost element. Recall that the bottommost element is the result of CREATE(0, 0, calldata_size), which is the new contract's address. Now new contract's address is at the top of the stack, following 5 0x00 underneath it.
After that we encounter a new opcode GAS:
GAS
It just pushes remaining gas onto the stack. Next, we have another new opcode CALL:
CALL
Now this is equivalent to CALL(remaining_gas, new_contract_address, 0, 0, 0, 0, 0). Basically it will just call the new contract with the remaining gas and the argument is empty. This call will push 1 onto the stack if it was successful, otherwise it will push 0 onto the stack. We shall call it result.
14 6000 PUSH1 00
16 14 EQ
17 601B PUSH1 1B
19 57 JUMPI
1A FD REVERT
1B 5B JUMPDEST
1C 00 STOP
If result == 0, the control flow will goto address 0x1B, which is our destination. In other words, we want CALL(remaining_gas, new_contract_address, 0, 0, 0, 0, 0) fail.

Building calldata

The easiest way to fail the CALL is creating a new contract containing only the REVERT instruction. The same idea appeared in Ethernaut "King".
Just modify the calldata from previous level:
PUSH1 0xFD // opcode of REVERT
PUSH1 0x00 // memory offset 0
MSTORE8
PUSH1 0x01 // return just 1 byte
PUSH1 0x00 // memory offset 0
RETURN
Bytecode:
60fd60005360016000f3
Last modified 1d ago