欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]Large bin attack--LCTF2017-2ez4u--writeup

[原创]Large bin attack--LCTF2017-2ez4u--writeup

Large bin attack--LCTF2017-2ez4u--writeup

技巧性很强的一道题,当时自己写的思路和官方的不一样,后面看着官方的wp看了半天才把思路看懂。

large bin 分配的过程

这道题很关键的一个点在于伪造large bin chunk,并将该chunk分配出来,从而实现空间复用,所以先解释下large bin分配的过程,源代码如下:

/*

         If a large request, scan through the chunks of current bin in

         sorted order to find smallest that fits.  Use the skip list for this.

       */

      if (!in_smallbin_range (nb))

        {

          bin = bin_at (av, idx);

          /* skip scan if empty or largest chunk is too small */

          if ((victim = first (bin)) != bin &&  //获取链表的第一个chunk

              (unsigned long) (victim->size) >= (unsigned long) (nb))

            {

              victim = victim->bk_nextsize;  //反向遍历,chunk size链表,直到找到第一个大于等于所需chunk大小的chunk退出循环

              while (((unsigned long) (size = chunksize (victim)) <

                      (unsigned long) (nb)))

                victim = victim->bk_nextsize;

              /* Avoid removing the first entry for a size so that the skip

                 list does not have to be rerouted.  */

              if (victim != last (bin) && victim->size == victim->fd->size)

                victim = victim->fd;

              remainder_size = size - nb;

              unlink (av, victim, bck, fwd); //large bin的unlink操作

              /* Exhaust */

              if (remainder_size < MINSIZE)

                {

                  set_inuse_bit_at_offset (victim, size);

                  if (av != &main_arena)

                    victim->size |= NON_MAIN_ARENA;

                }

              /* Split */

              else

                {

                  remainder = chunk_at_offset (victim, nb);

                  /* We cannot assume the unsorted list is empty and therefore

                     have to perform a complete insert here.  */

                  bck = unsorted_chunks (av);

                  fwd = bck->fd;

      if (__glibc_unlikely (fwd->bk != bck))

                    {

                      errstr = "malloc(): corrupted unsorted chunks";

                      goto errout;

                    }

                  remainder->bk = bck;

                  remainder->fd = fwd;

                  bck->fd = remainder;

                  fwd->bk = remainder;

                  if (!in_smallbin_range (remainder_size))

                    {

                      remainder->fd_nextsize = NULL;

                      remainder->bk_nextsize = NULL;

                    }

                  set_head (victim, nb | PREV_INUSE |

                            (av != &main_arena ? NON_MAIN_ARENA : 0));

                  set_head (remainder, remainder_size | PREV_INUSE);

                  set_foot (remainder, remainder_size);

                }

              check_malloced_chunk (av, victim, nb);

              void *p = chunk2mem (victim);

              alloc_perturb (p, bytes);

              return p;

            }

        }

有关堆的管理与结构不多说,需要强调下的是,large bin数组里的不再是存储大小一样chunk,而是可以存储等差数列变化的chunk块。large bin chunk结构体中的fd_nextsize和bk_nextsize俩个字段是有意义的,large bins中空闲chunk是按照大小排序的,但同一个大小的chunk可能有多个,增加这俩个字段可以加快遍历空闲chunk,fd_nextsize指向下一个比当前chunk大小大的第一个空闲块,bk_nextsize指向前一个比当前chunk大小小的第一个空闲chunk。

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功