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.
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.
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:
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
0x401568). Doing this when executing
m->introduce() it’s going to call
Only first 3 bytes are being used so you could just overwrite the pointer instead of overwriting the whole instance structure.
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
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: