Dance In Heap(三):一些堆利用的方法(中)
0x00 前面的話
在前一篇堆的利用方法裡面,我們簡單的提了一下UAF,並主要對從 bin 中釋放 chunk 的操作,即 unlink 巨集、unsortedbin attack,進行了利用。那麼在本篇中,我們主要討論如何將對一個對一個chunk進行復用來進行某種攻擊。
在這裡面我們要當心,chunk size的計算是個需要小心的地方,因為這裡包括了 prev_size的複用,以及根據不同系統考慮的對齊情況,還有 chunk 的size位表示的是包括chunk header在內的size,而實際可用的size與此不同,它是減去chunk header後的大小。
本篇文章目錄
0x01 fastbin attack 0x02 overlapping chunk 1 0x03 overlapping chunk 2 0x04 小結
0x01 fastbin attack
還記不記得我們在第一篇中那個介紹 fastbin 中 dobule free的例子
#include <stdio.h>
#include <stdlib.h>
int main() {
char *a=malloc(24);
char *b=malloc(24);
free(a);
free(b);
free(a);
}
這個執行是沒有問題的,但是想象一下,這樣做之後,現在的 fastbin 中是什麼樣子
------- ------- ------- ------- ------- | 頭結點 |-> | a |-> | b |-> | a |->| null | ------- ------- ------- ------- -------
其中的指向關係由chunk的 fd 指標標識。此時我們再從 fastbin中 malloc 出一個 chunk
c = malloc(24);
此時的 fastbin
------- ------- ------- -------
| 頭結點 |-> | b |-> | a |-> | null |
------- ------- ------- -------
現在我們得到了一個chunk,並且這個 chunk 同時在 fastbin中也存在,那麼此時如果我們修改 c 的 fd 指標位置為任意地址,那麼 fastbin 中 a 的指向也會發生改變
------- ------- ------- -------
| 頭結點 |-> | b |-> | a |-> |任意地址|
------- ------- ------- -------
我們之後連續 malloc 兩次
malloc(24);
malloc(24);
現在的 fastbin
------- -------
| 頭結點 |-> |任意地址|
------- -------
那我們再次 malloc 時,就可以在任意地址建立一個 chunk 了,但是要注意的是,我們在之前提到過,從 fastbin 中取出 chunk 的時候會對 chunk 的size 做檢查,也就是這個任意位置的 chunk 的 size 位必須構造。我們可以在棧中構造
int stack = 0x30 // 24 + header = 0x28 ,0x10 對齊後 0x30
這個變數作為size位,我們可以將任意地址填充為 &stack - 8,然後 malloc 之後會返回這個地址的 chunk,在棧中變數無法溢位時,我們可以向 chunk 裡面寫入資料來造成棧溢位。
d = malloc(24);
d[20] = 0xdeadbeef //控制rip
fastbin attack 中令人興奮的一點是,它不需要對 chunk 進行溢位就可以進行攻擊,這在一些對輸入長度檢查嚴格的地方可以得到奇妙的應用。
0x02 overlapping chunk 1
幸運的是,並不是所有的程式都會對輸入長度有嚴格的約束,當我們能夠溢位到下一個 chunk 時,我們可以修改它的 size 位來造成 chunk 的覆蓋。
首先,我們建立三個chunk,考慮 prev_size 的複用和 0x10位元組對齊,我們將 malloc(0x100-8), 系統會給我們(0x100-8)+0x10-0x8,即0x100(0x10對齊)的空間,實際可用的空間正好是0x100-8,並沒有多分配,而要是malloc(0x100)的話,你會看到實際可用的空間是0x108(這個不是必須的,只是向大家強調一下 chunk 大小的計算)
a = malloc(0x100-8);
b = malloc(0x100-8);
c = malloc(0x100-8);
然後 free 掉 b,b就會放到 unsortedbin 中 ,這個bin只有一個連結串列,並不對size進行區分,所以我們可以放入0x100的chunk,修改為size為0x180後就可以拿出0x180的chunk
free(b);
然後我們利用a溢位到b的size位
*(a+0xf8) = 0x181 // 0x01標識a為inuse狀態
現在我們malloc一個0x180的 chunk,系統就會將從b開始的0x180大小的空間返還,這其中包括c
d = malloc(0x180-8);
ok,現在我們就可以更改利用d更改c中的內容,如果c中包含某個函式指標,我們也可以去改變它,當然
0x03 overlapping chunk 2
我們在前面先釋放再修改size來獲得了一個覆蓋掉後面chunk 的 chunk,那麼如果我們先修改size為一個大值,然後free會怎樣呢?
首先我們建立4個chunk
a = malloc(0x100-8);
b = malloc(0x100-8);
c = malloc(0x100-8);
d = malloc(0x100-8);// 第四個為了防止被top chunk 合併,以及應對 free的檢查
我們通過a溢位到b的size
*(a+0xf8) = 0x201 // 0x1為inuse標識
我們這裡講b的size擴大到了c,由於free時需要檢查下一個chunk的size,所以我們預留了d,並且防止free後直接與top chunk合併,之後我們free掉b,然後再次malloc就又包括了c
free(p);
e = malloc(0x200-8);
然後就可以可以像0x02一樣去利用。
0x04 小結
除了這些之外,我們還可以根據不同的條件去構造不同的chunk複用,像是隻利用一個位元組溢位(off-by-one)來使chunk size減小,以此來構造的poison_null_byte 漏洞等等。瞭解chunk複用的原理,就是去改變 size 位來使系統對錯誤的長度進行 malloc、free,這就是我們的目的。