The toddler’s introduction to Heap Exploitation, FastBin Dup Consolidate (Part 4.2)
In this post we are going to trigger a FastBin consolidation which we are going to combine with a double free vulnerability (dup) in order to return a pointer to an already allocated chunk. By consolidation we refer to the process of merging adjacent free chunks and placing them to the unsorted bin for future allocations.
As always, please find below the references to my previous posts relative to heap exploitation:
- The toddler’s introduction to Heap Exploitation (Part 1)
- The toddler’s introduction to Heap exploitation (Part 2)
- The toddler’s introduction to Heap exploitation — Overflows (Part 3)
- The toddler’s introduction to Heap exploitation — Use After Free & Double free (Part 4)
- The toddler’s introduction to Heap Exploitation, FastBin Dup to Stack (Part 4.1)
Back to our topic, a consolidation is performed by the
malloc_consolidate which is a specialised version of the free() function:
This function will iterate the FastBin list merging a free chunk to its next and/or previous ones (4766–4783) and the result chunk will be added to the unsorted bin list (4784). A consolidation can be triggered by the
malloc function, when special conditions occur:
It is also triggered by the
malloc_init_state, malloc_trim, __libc_mallopt as well as the
free function if the size of the freed chunk is ≥ 64KB:
We’ll stick to the malloc for this post as it is the most straightforward way to trigger the Fastbins consolidation.
FastBin Dup Consolidate
We are going to use the following program:
Although the code above is pretty much self-explanatory, let’s take some time to highlight few points:
Lines 11–14we fill the tcache list in order to force the FastBin usage.
Lines 16–20freeing p1 will add the corresponding chunk to the FastBin list since the tcache list is already full for this size (0x40).
- The next allocation (
Line 22) will trigger the consolidation of the chunks in the FastBin list. The p3 pointer though will point to the same address as p1 due to the fact that the p1 chunk has been merged.
- Freeing p1 (again at
Line 22) will add the chunk to the tcache even though it is still referenced by the p3.
Line 33we request a size which can be satisfied by the tcache’s last addition (
0x400). So p4 will now point to the same address as p3.
Let’s load the program in gdb to see everything in action:
Set a breakpoint after the
free(p1) and after hitting it check the heap bins:
Now step into the
malloc up to the
_int_malloc function, where we notice a call to the
On a subsequent branch, _int_malloc will check if the requirement can be satisfied by the fastbins (using the
As the we requested a size of 0x400 bytes, this check will fail thus we will end up to the
Right after this call the chunk at
0x5555555598e0 has been merged:
Now malloc will return the
0x5555555598e0 as the new chunk address reference to satisfy the allocation (see last before the top chunk below):
The double free of p1 will move the chunk to the tcache:
Finally, the last call to malloc will assign the already allocated chunk to p4 (see $rax below) and this completes our proof of concept: