Defcon Quals 2016 - Heapfun4u

This challenge is a memory manager that implements a custom “heap”, allocated using mmap, with the permissions bitmap set to rwx.

We have a main menu in which we can perform the following operations:

[A]llocate Buffer: “malloc” of an arbitrary size.

[F]ree Buffer: “free” the chunk we select. Also list all the chunks and the respective addresses.

[W]rite Buffer: let us write in the data part of the specified chunk.

[N]ice guy: print an address of a variable of the stack.

[E]xit: quit the program.

All chunks’ pointers are saved in a global array (so there is a limit to their number, but the check on that is well made), but when you free a chunk, the pointer is not deleted from the array, so we can still write on it.

Inspecting the memory with qira, we saw that when we free a chunk with another allocate chunk after that, a pointer is saved at the end of the freed area. That address point to what we think is the “top chunk size”, so where the next “malloc” will allocate the next chunk.

We tried to edit it writing on a freed chunk, and we managed to change the allocation point of the next chunk inside another chunk previously declared (inside that chunk data we put a “valid” top chunk size).

So we have something like an arbitrary write, an executable “heap” and a stack address (and no canary to worry about). Out first thought is to overwrite the saved return address of the main on the stack, forcing the program to jump on a shellcode on the executable heap.

At first we tried just writing stuff on the stack, but it didn’t work. Then marcof noticed that maybe not only the top chunk size pointer that we can overwrite need to point to a valid top chunk size, but after the malloc, the nex top chunk size should maybe be on a previous memory area with all zeroes.
With qira we found the addresses on the stack of a valid top chunk size and a length for the malloc that allowed us to make the chunk stop on an area with zeroes.That suddenly worked, so we proceded to write the exploit in python using the pwntools.