Points: 384 Solves: 25 Category: Exploitation
This program is based off the
CaNaKMgF pwnable challenge, except that
CaNaKMgF_remastered has full RELRO enabled and PIE enabled. Interestingly, during the CTF, I had already solved
CaNaKMgF using a technique that bypassed both mitigations, so I re-used the same exploit for
CaNaKMgF_remastered and was able to get the flag.
When we run the program, we are presented with the following menu.
The program is very simple. It allows us to allocate heap chunks of different sizes, which it places in a global array in the .BSS called
We can write data of our choosing into these chunks and the program ensures that the length of our data fits inside the chunk we’ve allocated for it.
We can specify chunks from this list that we would like to print out the contents of. Similarly, we can also free any chunks in this list.
There was also some functionality to read limited files off the remote server when one selected the “Pray for Allah” option in the
CaNaKMgF binary, but this function no longer worked in
CaNaKMgF_remastered, and I didn’t use it in my exploit for
The main vulnerability in this program is that when a chunk is freed, the associated pointer to the chunk is not removed from
alloc_list. This allows us to perform use-after-frees and double-frees which we can abuse to corrupt the heap and gain code execution.
To get a libc leak, we can exploit the UAF to allocate 2 small chunks, free the first one, and then print its contents out, since we know the
BK pointers of our free’d small chunk will be populated with a pointer to an offset from
main_arena in libc. (The purpose of allocating a 2nd small chunk, is to prevent top chunk consolidation.)
To get control of
RIP, we can perform a fastbin attack to get
malloc() to return an almost arbitrary pointer, overwrite
__malloc_hook, and then call our overwritten
__malloc_hook function pointer by triggering a double free memory corruption error.
To perform the fastbin attack, we will allocate 2 fast chunks of size
0x68 bytes, and free the 2nd one, then the 1st one, and then the 2nd one again, abusing the fact that we can double-free fast chunks, so long as the head of the freelist that their fast chunk size is associated with, is not the same as the chunk that is being free’d.
So, right now our fastbin looks like this:
Now, we will allocate another fast chunk of the same size as D, so that D is popped off this freelist and used to service our
Since we can also specify the contents of chunks we allocate, we will overwrite the first qword of this chunk with the address of our target that we would like
malloc() to return.
This corrupts the
FD pointer of chunk D, a pointer to which, still exists in the singly linked freelist!
We can select any address to overwrite the
FD pointer with, subject to certain constraints.
To satisfy these constraints, we will abuse the fact that we can make
FD point to misaligned addresses as long as they satisfy the valid size metadata field constraint. In our case, since we are targeting fast chunks of size
0x68, the following is a valid address should do the trick.
At this point, our freelist should now look like this:
After two more allocations, our target address should now be at the head of this freelist:
Then, the next memory allocation of size
0x68 should return a pointer to our target address
+0x10 and since we can control the contents of chunks we allocate, we will simply overwrite
__malloc_hook with a “magic” one gadget RCE address.
Once we trigger an actual double free corruption error, the program should now spawn a shell.