Please let me know, if I start to sound weird….
The Author
The specific attack was initially introduced on October 11th 2005, on the bugtraq mailing list by Phantasmal Phantasmagoria, with the title The Malloc Maleficarum. The idea is very simple and got even simpler with the introduction of the Thread Local Cache (tcache):
The general idea involves overwriting a pointer that was previously returned by a call to malloc(), and that is subsequently passed to free(). This can lead to the linking of an arbitrary address into a fastbin. A further call to malloc() can result in this arbitrary address being used as a chunk of memory by the application. If the designer can control the applications use of the fake chunk, then it is possible to overwrite execution control data [1].
Simply said, assume that you have a pointer to a chunk that you are able to overwrite in order to point to an arbitrary address that you control its contents. Then it is possible to “fool” the allocator to use your address as a pointer to a free chunk and add it to the fastbins list. When malloc is called again and your chunk suits the requirements, the memory address returned will point to your controlled memory area.
After free:
And finally, after malloc:
Before the introduction of the tcache bin, the attacker had to craft adjacent fake chunks with proper size values (due to the double linking of the particular bin) in order to pass the validity check of the allocator. The tcache bin (single linked) made things more simple, thus crafting a single fake chunk will pass the validity checks.
As always, please find below the references to my previous posts relative to heap exploitation:
Tcache was introduced in glibc 2.26 back in 2017 in order to speed up the heap management. In regards to the house of spirit attack, this addition made things easier due to the single-list nature of this bin.
Let’s see a simple example:
We call malloc at Line 6 to initialise the heap and subsequently (at Line 7)we declare a pointer to an unsigned long long (ull). At line 8, we declare an array of ulls and cause the compiler to allocate its members on a 16-byte boundary (similar to a chunk boundary). This array will imitate a chunk, with its header starting at the address of fake_chunk[0]. More specifically, we have the following correspondence:
fake_chunk[0] → mchunk_prev_size, fake_chunk[1] →mchunk_size (recall the chunk structure to get a better understanding of this concept):
The statement fake_chunks[1] = 0x40;
at line 10, will set the size of the fake chunk to 0x40. If so far so good, assume that the attacker is able to overwrite the address where a points to. This assumption is represented by the a = &fake_chunks[2];
statement at line 12. Finally, the free(a)
at line 14 will add the fake chunk to the tcache bin, thus the next call to malloc (of size 0x30), will return a pointer to the attacker-controlled chunk. Remember that the size of the fake chunk is also controlled by the attacker, thus the requested malloc size wouldn’t be an issue to the exploitation. Let’s load the program to gdb, to get a deeper understanding:
At main+57
we will have the following values at $rbp-0x30
:
$rax
after main+57
will point to the data section of the fake chunk:
The call to free with the address of $rax in $rdi, will move the fake chunk to tcache:
At this point the fake chunk will be assigned to the next malloc(0x30). To make things a bit more interesting, add the following lines to our initial program (Line 16 onwards):
The strcpy equates the attacker’s capability to control the fake_chunk and so where str points to:
This is it for now…see you in the next post.
[1] https://dl.packetstormsecurity.net/papers/attack/MallocMaleficarum.txt