Hello everybody, today I’ll try to exploit a fastbin duplication attack, it is an attack pretty common in capture the flag events these days if I understand correctly and it will help me get into heap exploitation. This attack is pretty simple in theory so it can be easily explained.
How does the attack work?
Basically, as I said in some previous blog post, once you free a chunk between 16 to 80 bytes, it will be sent to the fastbins for faster usage. Here’s a quick file demonstrating the attack from how2heap by shellphish:
This code will allocate three chunks (I think it is allocating the “c” chunk to avoid a coalescing problem but I’m not sure), free(a), free(b) then free(a). This part will allow the code to free(a) twice without triggering a double free error which would crash the program. After executing the 3 free, the freelist will contain [a, b, a], meaning that if we try to allocate 3 new objects, 2 a will be returned (on the first and last malloc) and one b will be returned.
With that in mind, you can imagine that having control of two pointer pointing to the same address could lead to interesting things (use-after-free (?), control over a pointer, …)
Challenge
Once again I won’t be able to post the solution because it is a public challenge and they won’t allow me to post the exact solution but I had a challenge where I had to corrupt the fastbins. Basically the program ha a structure like that:
struct structure { int value; char *name; }
Once we want to create a structure, it will allocate the structure, ask for a name then do a malloc(strlen(name)) for the structure->name. What’s interesting is that since we can control the name size, we will be able to write to a different (or same) fastbin.
Here’s what I want to do:
a = malloc(16); // Creation 1 a->name = malloc(80); b = malloc(16); // Creation 2 b->name = malloc(80); free(a->name); // Free 1 free(a); free(b->name); // Free 2 free(b); free(a->name); // Free 3 free(a); malloc(16); // Creation 3 ->name malloc(80); malloc(16); // Creation 4 ->name malloc(16)
Doing something like that will, I think, create two object where the creation_4->name pointer will point to the same chunk as creation_3 pointer. Meaning that by changing the name of creation_4, we would be able to write directly inside the structure of creation_4 and overwrite the pointer of creation_4->name, changing the name then would allow us to have an arbitrary write into the memory!
My test worked. I did leak 0x400801 (because I couldn’t use any null byte since I write using strcpy). Here’s my output:
It means I did effectly overwrite the name pointer with an arbitrary address and, as long as the address doesn’t have a null byte, I can write anything to it using the change entry option.
What I will try to do now is overwrite the got value of a function to point it to another function (such as libc system).
How to leak a libc address to get the offset of system
Alright, now what I want to do is replace a .got pointer to system. For that I’ll first get the libc location using ldd:
I’ll then use objdump -R and get a .got address existing in the binary, from there I’ll leak a libc address by doing:
leaked_address - libc_function_offset = base_libc
I’ll then add the offset of system and voilà. Since I got the confirmation I can leak a value, I should be able to do that. Output of objdump -R binary:
I will use printf for my tests. Here is its offset inside libc:
And when I try to leak the value at 0x602048:
What’s interesting is that every time I launched my program, it would always leak something starting with “@” or 0x40. Let’s take a look at the randomization of libc base address.
As you can see, the last byte never gets randomized, neither does the first two. Meaning that if we were trying to leak the address of libc printf, the address would always end with 0x40 (or “@”), we did successfully leak the address of libc! Now that we know that, calculating the address of system is easy (in our case, leak – printf_offset + system_offset).
For my exploitation I tried to overwrite free, I will let the reader do the exercise themselves.
I couldn’t rewrite free in my challenge however since the program did a strlen at a time to choose the size of string to get and that prevented us to overwrite free because the address of free would end in a null byte:
I decided to change my exploit to rewrite strcpy and updated all my offset to write a string containing “/bin/sh” first, then do a “change” to trigger strcpy (now system) on /bin/sh. I could’ve chosen strlen as well for example.
First heap exploitation, done! Thank you so much for reading!
What did I learn today?
- How fastbin duplication (double free) work
- How to get the got address of various functions (objdump -R or -D, the address pointed at in the .plt)
- Getting the libc version using ldd (or refreshing my memory at least)
- Calculating the libc base address depending on a leak
- Using readelf -s on libc to get the offset of a function
- I should always verify if the program ends with a null byte