glibc2.31下的新double free手法/字节跳动pwn题gun题解

本文详细介绍了glibc2.31中的double free漏洞新手法,特别是Tcache的检查机制和Stash机制。通过fastbin double free和Tcache的Stash,可以在glibc2.31环境下实现任意写,从而引发安全问题。Bytectf2020-pwn-gun题目作为案例,展示了漏洞利用过程。
摘要由CSDN通过智能技术生成

回顾double free手法

  • 在glibc2.27之前,主要是fastbin double free:
    • fastbin在free时只会检查现在释放的chunk,是不是开头的chunk,因此可以通过free(C1), free(C2), free(C1)的手法绕过
    • 并在在fastbin取出时,会检查size字段是不是属于这个fastbin,因此往往需要伪造一个size
  • glibc2.27~glibc2.28,主要是tcache double free
    • 相较于fastbin double free,tcache完全没有任何检查,只需要free(C1), free(C1)就可以构造一个环出来
  • glibc2.29~glibc2.31,tcache加入了检查机制,如何进行doubel free就是本文的核心

Tcache的设计目的

tcache全称是Thead Cache的意思

在多线程情况下,ptmalloc会遇到抢占的问题,分配区被占用时只能等待或者申请一个非主分配区,效率低下

针对这种情况,ptmalloc为每个线程设置了一个缓冲区,这个缓冲区也就是tcache

因此tcache指针实际上位于TLS区域内,是各个线程独有的

glibc2.31下的Tcache检查

对于每一个tcache中的chunk,增加了一个key指针,用于指向所属的tcache结构体

typedef struct tcache_entry
{
  struct tcache_entry *next;  //链表指针,对应chunk中的fd字段
  /* This field exists to detect double frees.  */
  struct tcache_perthread_struct *key;  //指向所属的tcache结构体,对应chunk中的bk字段
} tcache_entry;

当chunk被放入时会设置key指针

static __always_inline void
tcache_put(mchunkptr chunk, size_t tc_idx)
{
  tcache_entry *e = (tcache_entry *)chunk2mem(chunk);

  /* Mark this chunk as "in the tcache" so the test in _int_free will
     detect a double free.  */
  e->key = tcache;  //设置所属的tcache

  e->next = tcache->entries[tc_idx];//单链表头插法
  tcache->entries[tc_idx] = e;  

  ++(tcache->counts[tc_idx]); //计数增加
}

在free时,会进行检查,最笨的方法就是对于每一个chunk,我都遍历一遍链表,这种方法正确,但是会大大影响效率

ptmalloc使用了一种更机智的方法,在不影响效率的前提下,完成了对double free的检查,详细的看注释

    size_t tc_idx = csize2tidx(size);
    //只要tcache不为空,并且这个chunk属于tcache管辖范围,那么这个chunk就有可能已经在tcache中了,所以需要double free检查
    if (tcache != NULL && tc_idx < mp_.tcache_bins)
    {
      /* Check to see if it's already in the tcache.  */
      tcache_entry *e = (tcache_entry *)chunk2mem(p);

      /*
        如果是double free,那么put时key字段被设置了tcache,就会进入循环被检查出来
        如果不是,那么key字段就是用户数据区域,可以视为随机的,只有1/(2^size_t)的可能行进入循环,然后循环发现并不是double free
      */
      if (__glibc_unlikely(e->key == tcache))//剪枝
      {
        tcache_entry *tmp;
        LIBC_PROBE(memory_tcache_double_free, 2, e, tc_idx);
        for (tmp = tcache->entries[tc_idx]; tmp; tmp = tmp->next)
          if (tmp == e)
            malloc_printerr("free(): double free detected in tcache 2");
      }

      if (tcache->counts[tc_idx] < mp_.tcache_count)  //通过检查,放入
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值