Linux下fastbin利用小結——fd覆蓋與任意地址free(House of Spirit)

Ox9A82發表於2016-09-12

linux下的fastbin是ctf中pwn題的重點出題點。去年(2015)中,XCTF就有兩站是使用fastbin的利用作為pwn400的壓軸題來出現,這也是我剛開始接觸fastbin的利用,參考了k0sh1師傅寫在freebuf上的一篇文章。我寫了幾個demo來說明問題。

目錄

1.關於fastbin

2.覆蓋fd指標實現利用

3.任意地址free實現利用(House of Spirit)

 

1.關於fastbin

我們一般熟悉的堆都是雙連結串列的chunk,但是對於大小為(16 Bytes~ 64 Bytes)的堆塊來說則是使用fastbin來進行管理的。

fastbin的堆塊結構與常規的chunk是完全一樣,除了使用的是單連結串列。

如上圖就是一個正在使用中的fastbin塊的結構

這是未被使用fastbin塊。

通過這兩幅圖可以看出,原本是雙連結串列(fd和bd)的位置現變成了單連結串列(fd)。

而fastbin就是依靠單連結串列來組織的,堆管理結構始終維護一個指向最後一個chunk的指標。這個指標決定了下一次要分配的chunk地址。

未被使用的chunk被鏈入單連結串列中,單連結串列的第一個chunk成員的fd值為NULL。

具體的連結串列情況如下:

 其中最上面的是指向單連結串列最後chunk塊的指標,chunk3因為是第一個chunk所以fd=0。

 

2.覆蓋fd指標實現利用

當一個fastbin堆塊存在堆溢位的時候,這種方法就可以使用了。簡要的過程就是通過溢位覆蓋一個在單連結串列中的chunk塊的fd指標,當再次分配後(至少分配兩次),就會在被覆蓋的fd處分配fastbin chunk塊,從而實現向任意地址分配堆塊。

下面詳細解釋一下:

1.成功利用的條件

  • 存在可被溢位的fastbin chunk塊,要求可以使chunk塊的fd能被控制
  • 欲被分配的地址,要求此地址的內容可控(存在size域)

2.如何利用

  1. 分配兩個fastbin chunk
  2. 使用第一個(位於低地址)覆蓋第二個(位於高地址)的fd指標。注意,第一個應該是已被分配的,不然就沒法寫入導致溢位。第二個應該是未被分配的,不然就不存在fd也不存在分配的問題了。
  3. 在欲分配的地址,比如bss段上構造一個偽chunk結構,比如l32(0x0)+l32(41)+l32(0x0)(即前塊正在使用中+本塊大小為40+fd為0)
  4. 進行分配即可得到任意地址分配堆塊的效果。從而可以實現任意地址寫任意值的效果。

    tips:指向的應為堆頭的地址,而不是malloc返回的使用者指標的位置

3.演示demo

 1 int BufForTst[100];
 2 
 3 int main(int argc, char *argv[]) 
 4 {
 5     void *buf0,*buf1,*buf2,*buf3;
 6     BufForTst[1]=0x29;
 7     buf0 = malloc(32);
 8     buf1 = malloc(32);
 9     printf("正常的chunk1、chunk2被分配\n");
10     free(buf1);
11     printf("chunk2被釋放\n");
12     printf("break\n");//for debug
13     read(0, buf0, 64);//overflow 
14     buf2 = malloc(32);
15     buf3 = malloc(32);
16     printf("發生溢位的chunk2被分配\n%p\n溢位改寫的fd地址被分配\n%p\n",buf2,buf3);
17     return 0;
18 }

這個例程展示瞭如何通過覆蓋fd指標實現向bss段分配堆塊

 1 from zio import *
 2 
 3 io=zio('./tst',timeout=9999)
 4 #io.gdb_hint()
 5 io.read_until('break')
 6 
 7 sc='a'*32+l32(0x0)+l32(0x29)+l32(0x804A060)
 8 #sc='abcd'
 9 io.writeline(sc)
10 io.read()

這個exp配合使用。命令如下

gcc tst.c -o tst
python exp.py

 

1 #define fastbin_index(sz) \
2   ((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2)
3 ...
4 if (__builtin_expect (fastbin_index (chunksize (victim)) != idx, 0))
5   {
6     errstr = "malloc(): memory corruption (fast)";

注意,因為檢查中沒有進行對齊處理。所以可以利用錯位來構造一個偽size結構以實現fasbin attack

3.任意地址free實現利用(House of Spirit)

當可以通過某種方式(比如棧溢位)控制free的引數時,就可以使用House of Spirit實現利用。大概的思路是free你要任意分配的地址,然後這個地址就會在再次分配的時候被分配到,但是要任意分配的地址要提起構造好偽chunk結構。

下面詳細解釋一下:

1.成功利用的條件

  • free的引數可控,可以指向欲分配的地址。
  • 欲分配的地址要求內容可控,可以提前構造偽chunk

2.如何利用

  1. 在欲分配的地址上構造偽chunk。由於堆的檢驗機制,要求構造連續的兩個偽chunk。比如l32(0x0)+l32(41)+'aaaa'*8 +l32(0x0)+l32(41)
  2. 控制free的引數,指向chunk的地址
  3. 再次分配就可以在指定地點分配chunk了

     tips:free的地址為malloc的地址,也就是堆頭+8的地址。

3.演示demo

 1 int TstBuf[100];
 2 int main(int argc, char *argv[])
 3 {
 4     void *p;
 5     int i;
 6     TstBuf[1]=0x29;//為什麼是0x29?因為32+8+FLAG位
 7     TstBuf[11]=0X29;//
 8     p=malloc(32);
 9     printf("正常的堆分配:%p\n",p);
10     p=(int *)0x804A068;
11     free(p);
12     printf("free了一個任意地址\n");
13     p=malloc(32);
14     printf("再次分配堆,可以看到分配到了任意地址上:%p\n",p);
15 }

成功的把堆塊分配到了bss上,為了方便我硬編碼了,可以根據自己的情況修改。

相關文章