• how2heap学习(一)


      接下来的时间会通过how2heap学习堆的知识,这个系列可能会更新很多篇,因为每天学习到的东西要保证吸收消化,所以一天不会学习很多,但是又想每天记录一下。所以开个系列。

    first_fit

      此题的源码经过简化,如下:

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <string.h>
     4 int main() {
     5     char* a = malloc(512); //0x200
     6     char* b = malloc(256); //0x100
     7     char* c;
     8     fprintf(stderr, "1st malloc(512): %p
    ", a);
     9     fprintf(stderr, "2nd malloc(256): %p
    ", b);
    10     strcpy(a, "AAAAAAAA");
    11     strcpy(b, "BBBBBBBB");
    12     fprintf(stderr, "first allocation %p points to %s
    ", a, a);
    13     fprintf(stderr, "Freeing the first one...
    ");
    14     free(a);
    15     c = malloc(500);
    16     fprintf(stderr, "3rd malloc(500): %p
    ", c);
    17     strcpy(c, "CCCCCCCC");
    18     fprintf(stderr, "3rd allocation %p points to %s
    ", c, c);
    19     fprintf(stderr, "first allocation %p points to %s
    ", a, a);
    20 }

      用gcc进行编译处理,命令:gcc -g first_fit1.c

      运行一下看输出结果:

      这个程序想让我们明白的是假如我先malloc了一个比较大的堆,然后free掉,当我再申请一个小于刚刚释放的堆的时候,就会申请到刚刚free那个堆的地址。还有就是,我虽然刚刚释放了a指向的堆,但是a指针不会清零,仍然指向那个地址。这里就存在一个uaf(use_after_free)漏洞,原因是free的时候指针没有清零。

      接下来再放一些学习资料上面话,比较官方,比较准确。

     

    fastbin_dup

      还是先放一下程序源码:

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <string.h>
     4 int main() {
     5     fprintf(stderr, "Allocating 3 buffers.
    ");
     6     char *a = malloc(9);
     7     char *b = malloc(9);
     8     char *c = malloc(9);
     9     strcpy(a, "AAAAAAAA");
    10     strcpy(b, "BBBBBBBB");
    11     strcpy(c, "CCCCCCCC");
    12     fprintf(stderr, "1st malloc(9) %p points to %s
    ", a, a);
    13     fprintf(stderr, "2nd malloc(9) %p points to %s
    ", b, b);
    14     fprintf(stderr, "3rd malloc(9) %p points to %s
    ", c, c);
    15     fprintf(stderr, "Freeing the first one %p.
    ", a);
    16     free(a);
    17     fprintf(stderr, "Then freeing another one %p.
    ", b);
    18     free(b);
    19     fprintf(stderr, "Freeing the first one %p again.
    ", a);
    20     free(a);
    21     fprintf(stderr, "Allocating 3 buffers.
    ");
    22     char *d = malloc(9);
    23     char *e = malloc(9);
    24     char *f = malloc(9);
    25     strcpy(d, "DDDDDDDD");
    26     fprintf(stderr, "4st malloc(9) %p points to %s the first time
    ", d, d);
    27     strcpy(e, "EEEEEEEE");
    28     fprintf(stderr, "5nd malloc(9) %p points to %s
    ", e, e);
    29     strcpy(f, "FFFFFFFF");
    30     fprintf(stderr, "6rd malloc(9) %p points to %s the second time
    ", f, f);
    31 }

      同样的gcc编译运行后看一下运行结果:

      程序做了哪些事呢?

      1.malloc申请了三个堆,并赋值。

      2.free了第一个堆。

      3.free了第二个堆。

      4.再次free了第一个堆。

      5.malloc又申请了三个堆。

      发现:第五步malloc申请堆的时候,第一个堆申请到了free第一次的位置,第二个堆申请到了free第二次的位置,第三个堆又申请到了free了第一次的位置。

      

      说白了就是连着free两次一个堆是不被允许的,但是假如再其中加一个free其他堆,那么就可以对一个堆free两次。这样再我们malloc再申请的时候,就可以申请到两个指针指向同一个堆块了。

      为了方便理解,我们试着在pwndbg里面看看:

      首先在11行的位置下了断点:

      可以看到我们申请的三个堆,接下来我们在看一下free(a)、free(b)、再次free(a)时的情况:

    --------------------------------------------------------------------------------------------------------

     

       可以看到fastbins形成了一个环,但是其实应该是栈的样子的,但是由于我们绕过了检测,就可以形成环。

      |Chunk A| -> |chunk B| -->| chunk A|

      

      大概如上个图,这样我们就成功绕过了 fastbins 的double free检查。原因如下:

      fastbins 可以看成一个 LIFO 的栈,使用单链表实现,通过 fastbin->fd 来遍历 fastbins。由于 free 的过程会对 free list 做检查,我们不能连续两次 free 同一个 chunk,所以这里在两次 free 之间,增加了一次对其他 chunk 的 free 过程,从而绕过检查顺利执行。然后再 malloc 三次,就在同一个地址 malloc 了两次,也就有了两个指向同一块内存区域的指针。

      上面的情况是在libc-2.23版本做的实验,但是好像版本不同的时候会有其他情况。这里就直接拿资料上的东西了。

    -----------------------资料----------------------------------------------

      看一点新鲜的,在 libc-2.26 中,即使两次 free,也并没有触发 double-free 的异常检测,这与 tcache 机制有关,以后会详细讲述。这里先看个能够在该版本下触发double-free 的例子:

      

    #include <stdio.h>
    #include <stdlib.h>
    int main() {
        int i;
        void *p = malloc(0x40);
        fprintf(stderr, "First allocate a fastbin: p=%p
    ", p);
        fprintf(stderr, "Then free(p) 7 times
    ");
        for (i = 0; i < 7; i++) 
            {
            fprintf(stderr, "free %d: %p => %p
    ", i+1, &p, p);
            free(p);
            }
        fprintf(stderr, "Then malloc 8 times at the same address
    ");
        int *a[10];
        for (i = 0; i < 8; i++) 
            {
            a[i] = malloc(0x40);
            fprintf(stderr, "malloc %d: %p => %p
    ", i+1, &a[i], a[i]);}
            fprintf(stderr, "Finally trigger double-free
    ");
        for (i = 0; i < 2; i++) 
            {
            fprintf(stderr, "free %d: %p => %p
    ", i+1, &a[i], a[i]);
            free(a[i]);
            }
        }

      首先先malloc申请了一个堆,接着连续free了7次。

      然后malloc同样大小的堆块,申请了8次。

      接下来又free了申请的前两个申请的堆块。

      我们看一下运行结果:

     

      可以从输出看到,8次重新申请的堆块都指向一个我们第一次申请的地址。

       后记:最后这个列子我还是没看出有啥可以学习到的。。。但是我疑惑的是,free了7次,为什么第8次malloc的时候,还是指向了第一次malloc的地址。

  • 相关阅读:
    自解代理模式
    顺时针打印二维方阵
    Dom4j官网解释实例
    Eclipse快捷键大全
    MyEclipse快捷键大全
    SQL语句的增删改查(详细)
    MySQL用户权限详细汇总
    从表中随机返回n条记录
    证件照(1寸2寸)拍摄处理知识汇总
    java 实现文件内容的加密和解密
  • 原文地址:https://www.cnblogs.com/bhxdn/p/12934279.html
Copyright © 2020-2023  润新知