zer0pts CTF 2021
pwn
The target program is very simple.
The vulnerability is obviously out-of-bound write at line 14.
Basically, there's no use of overwriting data around the heap chunk allocated by calloc
. So, we abuse the fact that the return value of calloc
is not checked.
If we pass a negative value to calloc
, it fails and returns NULL. However, this is not checked and eventually we can write to NULL + i*4
. This is a very strong primitive because PIE and RELRO are disabled. Now we can overwrite GOT!
4-byte-write is not enough. To get infinite AAW, we set puts@got
to the address of the main function. puts
is used only at the end of the main function and thus we get AAW in an infinite loop.
How to get the address of libc?
My solution is overwrite calloc@got
to printf@plt
, then set n
to the address where we want to leak. calloc(n)
works as printf(n)
and we get AAR.
There are two problems however.
The first problem is that the program exits when n
is larger than 0x100.
In the graph view, it looks like this:
In the assembly, it looks like this:
So, if we overwrite the GOT of exit
and make it something meaningless, we can move to the path for n <= 0xff
. This way we can bypass the check of n
.
The second problem is that we can write 4-byte every time. When we try to overwrite the address of calloc
, the upper or lower 4 bytes are corrupted and crashes on the next calloc
call.
Be aware that we don't actually call calloc
. So, we can skip it by setting exit@got
to the address after the calloc
call. I used call rax
gadget in order to skip calloc
, because it can align RSP to avoid crash on movaps.
After leaking the libc address, just overwrite calloc
with the address of system
and execute /bin/sh
.