This was a “very easy” challenge. That’s relative, but it was simple.
With some GDB-fu and manual dynamic analysis we can reverse engineer a way to get the flag.
TL;DR - Abuse strcpy to zero the program’s XOR key. It will print the flag.
The Program
The program’s basic functionality is
- Generate a random 32 byte key by reading
/dev/urandom
and store it in memory. The binary is PIE but we don’t need to know where it’s stored, for this challenge.offset of random key in binary
- Present the user with a simple 2-option menu
- If the user enters
1
, we enter a key generation routine- users control the length of the new key
- the same place in memory is used, every time
- after the routine we return to the original menu
- If
2
is entered- the 32 bytes stored in memory is used to byte-wise XOR the flag
- the result is printed
- Any byte XOR’d with
0
is itself >;)
flag.txt “encrypted” with random bytes
The vulnerability in this application is the use of strcpy
to move random bytes
into the random_key
memory.
According to man pages for man (3) strcpy
, the resulting string is null-terminated. We can abuse this behavior to zero the key used to XOR the flag. The trick is to zero the memory highest byte first, because strcpy
will overwrite previously written null bytes if we start from the lowest byte.
Hints
- The GDB command
x/32bx &random_key
shows the bytes used for the key. Watch it change as the program generates keys of various lengths. - Set the key from the highest byte, first (31, 30, 29, …)
execution while zero’ing xor key
Appendix I: Resources
GDB Command file (used with -x
)
b *new_key_gen
b *secure_password + 410
commands 1
x/32bx &random_key
end
Script main
io = start()
i = 31
input("\n[Press ENTER to start]\n")
while i >= 0:
io.info(f"zeroing random_key[{i:02d}]")
io.readuntil(b'> ')
io.sendline(b'1')
io.readuntil(b': ')
i_string = str(i).encode('utf-8')
io.sendline(i_string)
i -= 1
io.readuntil(b'> ')
io.sendline(b'2')
io.readuntil(b'Vault: ')
flag = io.readall().decode()
