首页
社区
课程
招聘
The House of Mind
发表于: 2022-2-18 22:34 22682

The House of Mind

2022-2-18 22:34
22682

  其实不光是"The House of Mind",在学习各种堆溢出漏洞的利用方法之前,都必须对glibc malloc()/free()的逻辑,有相当程度的了解,《Glibc内存管理--Ptmalloc2源代码分析》这份文档,通过129页的篇幅,已经分析的非常深刻和详细(如果没有积分下载文档,也可以去看作者的博客:https://www.iteye.com/blog/user/mqzhuang),也可以看看我发过的一个帖子:https://bbs.pediy.com/thread-271331.htm,先从外围了解glibc malloc()/free()的本质和设计目标,瞄一眼宏观的地形,再深入到茫茫的内部实现中,应该可以少迷点路。
  另外,本文是对phrack杂志中一篇神作的总结和补充,所以exploit code和更完整的分析过程,请阅读原文:http://phrack.org/issues/66/10.html

  "The House of Mind"是一种堆溢出漏洞的利用方法(为什么叫这个名称我目前还不知道),可以通过构造输入数据,让漏洞程序执行攻击者期望的任意代码(不过,不是所有存在堆溢出漏洞的程序,都可以利用这种方法进行攻击,需要漏洞程序满足一定条件,稍后具体说明)。
  再具体一点就是,在应用程序分配到的内存周围,很多都是glibc内部使用的内存,程序存在漏洞,攻击者就有机会通过构造输入数据,溢出glibc内部使用的变量,进一步控制malloc()/free()的执行逻辑,最终借glibc之手,修改某个函数对应的got表项(可以理解为函数指针,感兴趣也可以看看我的另外一个帖子:https://bbs.pediy.com/thread-246373.htm),使其指向一段shell code(同样通过用户输入构造),这样,当漏洞程序后续执行该函数时(比如.dtors()函数,它会在main()函数结束后执行),就会触发shell code执行。

  为了满足"The House of Mind"的利用条件,作者提供了一个用于演示的漏洞程序(现实中这类漏洞当然会隐蔽的多,几乎不会存在这么饥渴难耐的想被宰割的程序)。

  fread(ptr, 1024 * 1024, 1, stdin)这行代码,使攻击者有机会往0x804a008之后的1M内存,写入任意数据,这块内存中,有很多地方保存的是chunk->size,由glibc内部使用,通过构造溢出数据,控制这些地方的值,就可以达到欺骗glibc的效果,甚至还可以进一步欺骗glibc,将部分user data也当作自己内部使用的内存,为此,作者构造出了上述内存布局图(右)中的数据,当漏洞程序执行free(ptr2)时,glibc就会按照攻击者欺骗的流程执行。

(3) fake_arena->bins[2] = DTORS_END-12
根据布局图可以看出,fake_arena开始的8个字节,都被构造为0x102,剩余部分全部构造为DTORS_END-12,根据malloc_state结构的定义可知,这样构造肯定可以使fake_arena->bins[2] = DTORS_END-12。

使fake_arena->bins[2] = DTORS_END-12,是为了欺骗glibc修改got[.dtros]:

关于unsorted_chunks()函数返回&fake_arena->bins[0]的设计意图,可以进入这篇帖子:https://bbs.pediy.com/thread-271331.htm,看看其中的bin结构图。

  上述已经将攻击流程介绍完毕,但是实际能否成功,还要看到底能不能将glibc欺骗到"fwd->bk = p;"这一行代码上。

  随着各种攻击技术的出现,glibc其实一直都在改造,以上看到的这些判断,很多就是为了缓解攻击,但glibc的改造,是受限于两个因素的:

  所以,glibc只能缓存攻击,根本避免被攻击,在业务层的源头就要开始防范。

/*
 * K-sPecial's vulnerable program
 */
 
#include <stdio.h>
#include <stdlib.h>
 
int main (void) {
   char *ptr  = malloc(1024);        /* First allocated chunk */
   char *ptr2;                       /* Second chunk          */
   /* ptr & ~(HEAP_MAX_SIZE-1) = 0x08000000 */
   int heap = (int)ptr & 0xFFF00000;
   _Bool found = 0;
 
   printf("ptr found at %p\n", ptr);  /* Print address of first chunk */
 
   // i == 2 because this is my second chunk to allocate
   for (int i = 2; i < 1024; i++) {
     /* Allocate chunks up to 0x08100000 */
     if (!found && (((int)(ptr2 = malloc(1024)) & 0xFFF00000) == \
                                           (heap + 0x100000))) {
       printf("good heap allignment found on malloc() %i (%p)\n", i, ptr2);
          found = 1; /* Go out */
          break;
       }
 
   }
        malloc(1024); /* Request another chunk: (ptr2 != av->top) */
        /* Incorrect input: 1048576 bytes */
        fread (ptr, 1024 * 1024, 1, stdin);
 
        free(ptr);   /* Free first chunk  */
        free(ptr2);  /* The House of Mind */
        return(0);   /* Bye */
}
/*
 * K-sPecial's vulnerable program
 */
 
#include <stdio.h>
#include <stdlib.h>
 
int main (void) {
   char *ptr  = malloc(1024);        /* First allocated chunk */
   char *ptr2;                       /* Second chunk          */
   /* ptr & ~(HEAP_MAX_SIZE-1) = 0x08000000 */
   int heap = (int)ptr & 0xFFF00000;
   _Bool found = 0;
 
   printf("ptr found at %p\n", ptr);  /* Print address of first chunk */
 
   // i == 2 because this is my second chunk to allocate
   for (int i = 2; i < 1024; i++) {
     /* Allocate chunks up to 0x08100000 */
     if (!found && (((int)(ptr2 = malloc(1024)) & 0xFFF00000) == \
                                           (heap + 0x100000))) {
       printf("good heap allignment found on malloc() %i (%p)\n", i, ptr2);
          found = 1; /* Go out */
          break;
       }
 
   }
        malloc(1024); /* Request another chunk: (ptr2 != av->top) */
        /* Incorrect input: 1048576 bytes */
        fread (ptr, 1024 * 1024, 1, stdin);
 
        free(ptr);   /* Free first chunk  */
        free(ptr2);  /* The House of Mind */
        return(0);   /* Bye */
}
#define heap_for_ptr(ptr) \
((heap_info *)((unsigned long)(ptr) & ~(HEAP_MAX_SIZE-1)))
#define arena_for_chunk(ptr) \
(chunk_non_main_arena(ptr) ? heap_for_ptr(ptr)->ar_ptr : &main_arena)
#define heap_for_ptr(ptr) \
((heap_info *)((unsigned long)(ptr) & ~(HEAP_MAX_SIZE-1)))
#define arena_for_chunk(ptr) \
(chunk_non_main_arena(ptr) ? heap_for_ptr(ptr)->ar_ptr : &main_arena)
struct malloc_state {
/* Serialize access.  */
mutex_t mutex;
// Should we have padding to move the mutex to its own cache line?
#if THREAD_STATS
/* Statistics for locking.  Only used if THREAD_STATS is defined.  */
long stat_lock_direct, stat_lock_loop, stat_lock_wait;
#endif
/* The maximum chunk size to be eligible for fastbin */
INTERNAL_SIZE_T  max_fast;   /* low 2 bits used as flags */
/* Fastbins */
mfastbinptr      fastbins[NFASTBINS];
/* Base of the topmost chunk -- not otherwise kept in a bin */
mchunkptr        top;
/* The remainder from the most recent split of a small request */
mchunkptr        last_remainder;
/* Normal bins packed as described above */
mchunkptr        bins[NBINS * 2];
/* Bitmap of bins */
unsigned int     binmap[BINMAPSIZE];
/* Linked list */
struct malloc_state *next;
/* Memory allocated from the system in this arena.  */
INTERNAL_SIZE_T system_mem;
INTERNAL_SIZE_T max_system_mem;
};
struct malloc_state {
/* Serialize access.  */
mutex_t mutex;
// Should we have padding to move the mutex to its own cache line?
#if THREAD_STATS
/* Statistics for locking.  Only used if THREAD_STATS is defined.  */
long stat_lock_direct, stat_lock_loop, stat_lock_wait;
#endif
/* The maximum chunk size to be eligible for fastbin */
INTERNAL_SIZE_T  max_fast;   /* low 2 bits used as flags */
/* Fastbins */
mfastbinptr      fastbins[NFASTBINS];
/* Base of the topmost chunk -- not otherwise kept in a bin */
mchunkptr        top;
/* The remainder from the most recent split of a small request */
mchunkptr        last_remainder;
/* Normal bins packed as described above */
mchunkptr        bins[NBINS * 2];
/* Bitmap of bins */
unsigned int     binmap[BINMAPSIZE];
/* Linked list */
struct malloc_state *next;
/* Memory allocated from the system in this arena.  */
INTERNAL_SIZE_T system_mem;
INTERNAL_SIZE_T max_system_mem;
};
  } else
clear_inuse_bit_at_offset(nextchunk, 0);
 
  /*
Place the chunk in unsorted chunk list. Chunks are
not placed into regular bins until after they have
been given one chance to be used in malloc.
  */
 
  bck = unsorted_chunks(av);  // 返回:&fake_arena->bins[0]
  fwd = bck->fd;  // fd位于malloc_chunk结构体8字节偏移处
                  // 所以fwd = bck->fd = fake_arena->bins[2] = DTORS_END-12
  p->bk = bck;
  p->fd = fwd;
  bck->fd = p;    // fake_arena->bins[2] = p
  fwd->bk = p;    // bk位于malloc_chunk结构体12字节偏移处
                  // 所以这里会将p,写到DTORS_END指向的内存单元,即:got[.dtors] = p
 
  set_head(p, size | PREV_INUSE);
  set_foot(p, size);
 
  check_free_chunk(av, p);
}
  } else
clear_inuse_bit_at_offset(nextchunk, 0);
 
  /*
Place the chunk in unsorted chunk list. Chunks are
not placed into regular bins until after they have
been given one chance to be used in malloc.
  */
 
  bck = unsorted_chunks(av);  // 返回:&fake_arena->bins[0]
  fwd = bck->fd;  // fd位于malloc_chunk结构体8字节偏移处
                  // 所以fwd = bck->fd = fake_arena->bins[2] = DTORS_END-12
  p->bk = bck;
  p->fd = fwd;
  bck->fd = p;    // fake_arena->bins[2] = p
  fwd->bk = p;    // bk位于malloc_chunk结构体12字节偏移处
                  // 所以这里会将p,写到DTORS_END指向的内存单元,即:got[.dtors] = p

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 3
支持
分享
打赏 + 100.00雪花
打赏次数 1 雪花 + 100.00
 
赞赏  Editor   +100.00 2022/03/21 恭喜您获得“雪花”奖励,安全圈有你而精彩!
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//