ctfwriteup.com
Search…
⌃K

Puzzle 5

MSIZE

Puzzle

############
# Puzzle 5 #
############
00 6020 PUSH1 20
02 36 CALLDATASIZE
03 11 GT
04 6008 PUSH1 08
06 57 JUMPI
07 FD REVERT
08 5B JUMPDEST
09 36 CALLDATASIZE
0A 6000 PUSH1 00
0C 6000 PUSH1 00
0E 37 CALLDATACOPY
0F 36 CALLDATASIZE
10 59 MSIZE
11 03 SUB
12 6003 PUSH1 03
14 14 EQ
15 6019 PUSH1 19
17 57 JUMPI
18 FD REVERT
19 5B JUMPDEST
1A 00 STOP
? Enter the calldata:

Solution

Chunk 1

00 6020 PUSH1 20
02 36 CALLDATASIZE
03 11 GT
04 6008 PUSH1 08
06 57 JUMPI
07 FD REVERT
08 5B JUMPDEST
The calldata must be longer than 0x20 = 32 bytes.

Chunk 2

09 36 CALLDATASIZE
0A 6000 PUSH1 00
0C 6000 PUSH1 00
0E 37 CALLDATACOPY
0F 36 CALLDATASIZE
10 59 MSIZE
11 03 SUB
12 6003 PUSH1 03
14 14 EQ
15 6019 PUSH1 19
17 57 JUMPI
18 FD REVERT
19 5B JUMPDEST
1A 00 STOP
Pseudocode:
calldatacopy(0, 0, calldata_size);
if (memory_size - calldata_size == 0x03) {
jump(0x19);
}
MSIZE gets the size of active memory in bytes. More importantly, from evm.codes:
The memory is always fully accessible. What this instruction tracks is the highest offset that was accessed in the current execution. A first write or read to a bigger offset will trigger a memory expansion, which will cost gas. The size is always a multiple of a word (32 bytes).
At address 0x0E when CALLDATACOPY is called, our calldata is copied to the memory. If our calldata is longer than 32 bytes but shorter than 64 bytes, then MSIZE will always return 64. To satisfy memory_size - calldata_size == 0x03, we can just feed 61 0x00 as calldata. In Python:
print("0x" + "00" * 61)
# 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Last modified 1d ago