Introduction
We are given the following code:
|
|
Let’s see what flags it is compiled with:
So far we can’t execute shellcode on the stack. However it doesn’t have ASLR enabled so we can reference segments of code without need of leaking addresses.
Solution
Before anything else, since we have the source code I compiled the binary with debugging symbols to make the task easier:
c++ -no-pie -g -O0 -fno-inline -fno-eliminate-unused-debug-types -o pie_debug_uaf uaf.cpp
The challenge makes references to uaf vulnerability, which is caused by using a pointer to memory after it was freed.
When calling new
it allocates the initialized object in the heap.
Check how the heap chunk looks like when storing the instance:
It stores a pointer to the text section where the class is located:
When m->introduce()
get’s compiled in the binary, it dereferences the pointer stored in the heap chunk and adds 0x8
to it. Afterwards it dereference it one more time and calls that function.
Within the menu we can use the third option to free the variables. Notice how the first 8 bytes where the pointer to the class is now just filled with null bytes. Therefore calling again to m-introduce()
leads to segmentation fault because it can’t dereference the address.
Finally the second menu option allows us to store the amount of bytes and data we want. So if we free the instance we can then write a chunk of the same size, since there is no other dynamic memory allocation going on we are guaranteed that our data is going to overwrite the chunk previously used by the class instance.
Therefore we can overwrite the pointer at the beginning of the chunk decreasing it’s value by 0x8
(0x401568
). Doing this when executing m->introduce()
it’s going to call give_shell
.
Only first 3 bytes are being used so you could just overwrite the pointer instead of overwriting the whole instance structure.
Side notes
After solving the challenge I thought that it may be possible to read the file just from the heap. Tried locally and voilá:
However when I tried to read on the remote server my dreams got crushed. You can only read when you execute give_shell
because bash uses setuid
. Meanwhile open
get’s called with 1029(uaf)
as effective uid so you don’t have permissions to open it.
Here are the registers after attempting to open the flag:
Basically we don’t have permissions to open it, from the docs: