how2heap學習(一)


  接下來的時間會通過how2heap學習堆的知識,這個系列可能會更新很多篇,因為每天學習到的東西要保證吸收消化,所以一天不會學習很多,但是又想每天記錄一下。所以開個系列。

first_fit

  此題的源碼經過簡化,如下:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 int main() {
 5     char* a = malloc(512); //0x200
 6     char* b = malloc(256); //0x100
 7     char* c;
 8     fprintf(stderr, "1st malloc(512): %p\n", a);
 9     fprintf(stderr, "2nd malloc(256): %p\n", b);
10     strcpy(a, "AAAAAAAA");
11     strcpy(b, "BBBBBBBB");
12     fprintf(stderr, "first allocation %p points to %s\n", a, a);
13     fprintf(stderr, "Freeing the first one...\n");
14     free(a);
15     c = malloc(500);
16     fprintf(stderr, "3rd malloc(500): %p\n", c);
17     strcpy(c, "CCCCCCCC");
18     fprintf(stderr, "3rd allocation %p points to %s\n", c, c);
19     fprintf(stderr, "first allocation %p points to %s\n", a, a);
20 }

  用gcc進行編譯處理,命令:gcc -g first_fit1.c

  運行一下看輸出結果:

  這個程序想讓我們明白的是假如我先malloc了一個比較大的堆,然后free掉,當我再申請一個小於剛剛釋放的堆的時候,就會申請到剛剛free那個堆的地址。還有就是,我雖然剛剛釋放了a指向的堆,但是a指針不會清零,仍然指向那個地址。這里就存在一個uaf(use_after_free)漏洞,原因是free的時候指針沒有清零。

  接下來再放一些學習資料上面話,比較官方,比較准確。

 

 

 

 

fastbin_dup

  還是先放一下程序源碼:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 int main() {
 5     fprintf(stderr, "Allocating 3 buffers.\n");
 6     char *a = malloc(9);
 7     char *b = malloc(9);
 8     char *c = malloc(9);
 9     strcpy(a, "AAAAAAAA");
10     strcpy(b, "BBBBBBBB");
11     strcpy(c, "CCCCCCCC");
12     fprintf(stderr, "1st malloc(9) %p points to %s\n", a, a);
13     fprintf(stderr, "2nd malloc(9) %p points to %s\n", b, b);
14     fprintf(stderr, "3rd malloc(9) %p points to %s\n", c, c);
15     fprintf(stderr, "Freeing the first one %p.\n", a);
16     free(a);
17     fprintf(stderr, "Then freeing another one %p.\n", b);
18     free(b);
19     fprintf(stderr, "Freeing the first one %p again.\n", a);
20     free(a);
21     fprintf(stderr, "Allocating 3 buffers.\n");
22     char *d = malloc(9);
23     char *e = malloc(9);
24     char *f = malloc(9);
25     strcpy(d, "DDDDDDDD");
26     fprintf(stderr, "4st malloc(9) %p points to %s the first time\n", d, d);
27     strcpy(e, "EEEEEEEE");
28     fprintf(stderr, "5nd malloc(9) %p points to %s\n", e, e);
29     strcpy(f, "FFFFFFFF");
30     fprintf(stderr, "6rd malloc(9) %p points to %s the second time\n", f, f);
31 }

  同樣的gcc編譯運行后看一下運行結果:

  程序做了哪些事呢?

  1.malloc申請了三個堆,並賦值。

  2.free了第一個堆。

  3.free了第二個堆。

  4.再次free了第一個堆。

  5.malloc又申請了三個堆。

  發現:第五步malloc申請堆的時候,第一個堆申請到了free第一次的位置,第二個堆申請到了free第二次的位置,第三個堆又申請到了free了第一次的位置。

  

  說白了就是連着free兩次一個堆是不被允許的,但是假如再其中加一個free其他堆,那么就可以對一個堆free兩次。這樣再我們malloc再申請的時候,就可以申請到兩個指針指向同一個堆塊了。

  為了方便理解,我們試着在pwndbg里面看看:

  首先在11行的位置下了斷點:

  可以看到我們申請的三個堆,接下來我們在看一下free(a)、free(b)、再次free(a)時的情況:

--------------------------------------------------------------------------------------------------------

 

 

 

   可以看到fastbins形成了一個環,但是其實應該是棧的樣子的,但是由於我們繞過了檢測,就可以形成環。

  |Chunk A| -> |chunk B| -->| chunk A|

  

  大概如上個圖,這樣我們就成功繞過了 fastbins 的double free檢查。原因如下:

  fastbins 可以看成一個 LIFO 的棧,使用單鏈表實現,通過 fastbin->fd 來遍歷 fastbins。由於 free 的過程會對 free list 做檢查,我們不能連續兩次 free 同一個 chunk,所以這里在兩次 free 之間,增加了一次對其他 chunk 的 free 過程,從而繞過檢查順利執行。然后再 malloc 三次,就在同一個地址 malloc 了兩次,也就有了兩個指向同一塊內存區域的指針。

  上面的情況是在libc-2.23版本做的實驗,但是好像版本不同的時候會有其他情況。這里就直接拿資料上的東西了。

-----------------------資料----------------------------------------------

  看一點新鮮的,在 libc-2.26 中,即使兩次 free,也並沒有觸發 double-free 的異常檢測,這與 tcache 機制有關,以后會詳細講述。這里先看個能夠在該版本下觸發double-free 的例子:

  

#include <stdio.h>
#include <stdlib.h>
int main() {
    int i;
    void *p = malloc(0x40);
    fprintf(stderr, "First allocate a fastbin: p=%p\n", p);
    fprintf(stderr, "Then free(p) 7 times\n");
    for (i = 0; i < 7; i++) 
        {
        fprintf(stderr, "free %d: %p => %p\n", i+1, &p, p);
        free(p);
        }
    fprintf(stderr, "Then malloc 8 times at the same address\n");
    int *a[10];
    for (i = 0; i < 8; i++) 
        {
        a[i] = malloc(0x40);
        fprintf(stderr, "malloc %d: %p => %p\n", i+1, &a[i], a[i]);}
        fprintf(stderr, "Finally trigger double-free\n");
    for (i = 0; i < 2; i++) 
        {
        fprintf(stderr, "free %d: %p => %p\n", i+1, &a[i], a[i]);
        free(a[i]);
        }
    }

  首先先malloc申請了一個堆,接着連續free了7次。

  然后malloc同樣大小的堆塊,申請了8次。

  接下來又free了申請的前兩個申請的堆塊。

  我們看一下運行結果:

 

 

  可以從輸出看到,8次重新申請的堆塊都指向一個我們第一次申請的地址。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

   后記:最后這個列子我還是沒看出有啥可以學習到的。。。但是我疑惑的是,free了7次,為什么第8次malloc的時候,還是指向了第一次malloc的地址。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM