ctfwriteup.com
Search…
⌃K

Puzzle 2

CALL, RETURNDATASIZE

Puzzle

############
# Puzzle 2 #
############
00 36 CALLDATASIZE
01 6000 PUSH1 00
03 6000 PUSH1 00
05 37 CALLDATACOPY
06 36 CALLDATASIZE
07 6000 PUSH1 00
09 6000 PUSH1 00
0B F0 CREATE
0C 6000 PUSH1 00
0E 80 DUP1
0F 80 DUP1
10 80 DUP1
11 80 DUP1
12 94 SWAP5
13 5A GAS
14 F1 CALL
15 3D RETURNDATASIZE
16 600A PUSH1 0A
18 14 EQ
19 601F PUSH1 1F
1B 57 JUMPI
1C FE INVALID
1D FE INVALID
1E FE INVALID
1F 5B JUMPDEST
20 00 STOP
? Enter the calldata:

Solution

Pseudocode:
// Copy calldata to memory offset 0
calldatacopy(0, 0, calldata_size);
// Create a new contract based on that calldata stored in memory, deposit 0 wei into it.
// Return the new contract's address back to the stack.
contract_address = create(0, 0, calldata_size);
// Call the new contract with remaining gas.
// Return success status (0 or 1) back to the stack.
returndata = call(gas, contract_address, 0, 0, 0, 0, 0)
if (returndata_size == 0x0A) {
jump(0x1F);
}
Basically we need to build a contract that returns 10 bytes of data, any data suffices, such as 0x00's. That means our runtime code can simply return 10 bytes of stuff without writing anything to the memory:
// Return that 10 bytes
PUSH1 0x0A
PUSH1 0x00
RETURN
Compile it in Playground:
600a6000f3
Next let's build creation code:
// Store 0x600a6000f3 in memory offset 0
PUSH5 0x600a6000f3
PUSH1 0x00
MSTORE
// Return it, but skipping all the leading zeros
PUSH1 0x05
PUSH1 0x1B
RETURN
Compile:
64600a6000f36000526005601bf3
Last modified 1d ago