热门课程

免费试听

上课方式

开班时间

当前位置: 首页 -   文章 -   新闻动态 -   正文

二进制安全之堆溢出(系列)——堆基础 & 结构(一)

2024-08-09 11:07:54
0

  二进制安全之堆溢出(系列)第二期来啦

  鉴于本期干货够多

  知了姐怕大家一时间消化不了,

  特意帮大家拆分成了四节内容

  以下为“堆基础 & 结构”第一节

  堆基础

  堆的概念

  l  在程序运行过程中,堆可以提供动态内存的分配,允许程序申请大小未知的内存。

  l  堆其实就是在程序虚拟地址空间的一块连续的线性区域,它由低地址向高地址生长。

  l  我们一般称管理堆的那部分程序为堆管理器。

  l  堆管理器位于用户程序和内核中间,主要负责 :

  1.    double free : 当p已经被释放后再次释放,造成乱七八糟的现象。

  2.    malloc

  3.    free

  l  请求堆

  1.    响应用户的申请内存请求,向操作系统申请内存,然后返回给用户程序。为了保持内存管理的高效性,内核一般会预先分配很大的一块连续的内存。

  l  释放堆

  1.    管理用户释放的内存。用户释放的内存并不是直接返还给操作系统,而是由堆管理器进行管理。这些释放的内存可以用来响应用户新申请的内存的请求。

  堆的历史

  l  Linux中早期的堆分配和回收由Doug lea实现,但它在并行处理多个线程时,会共享进程的堆内存空间。因此为了安全性,一个线程使用堆时,会进行加锁。

  l  然而,加锁会导致其他线程无法使用堆,降低了内存分配和回收的高效性。在多线程使用时,没能正确控制,也可能引起内存分配和回收的正确性。

  l  Wolffram Gloger在Doug Lea的基础上进行改进使其可以支持多线程,这个堆分配器就是ptmalloc。在glibc-2.3.x之后,glibc中集成了ptmalloc2.ptmalloc2主要通过malloc/free函数来分配和释放内存块。

  堆的实现

  l  dlmalloc : Genral purpose allocator

  l  ptmalloc2   : glibc

  l  jemalloc     : Freebsd and Firefox

  l  tcmalloc     : Google

  l  libumen      : Solaris

  l  主要以ptmalloc2中堆的实现为主

  内存管理

  l  只有当真正访问一个地址的时候,系统才会在虚拟内存和物理页面的映射关系。

  l  所以操作系统已经给程序分配了很大的一块内存,但是这开内存其实只是虚拟内存。只有当用户使用到相应的内存时,系统才会真正分配物理内存给用户使用。

  系统调用

  l  malloc和free在动态申请或释放内存时,主要是调用(s)brk和mmap,unmmap函数实现的。

  l  (s)brk函数机制

  # include # include # icclude int main() {  void *cuur_bkr,*tmp_brk = NULL;  printf("%d\n",getid());  tm_brk = curr_brk = sbrk(0);//给当前程序一个brk  printf("%p\n",curr_brk);  getchar(); brk(curr_brk+4096);//设置结尾位置,即分配了4096字节的堆块  curr_brk=sbrk(0);  printf("%p\n",curr_brk);  getchar();  brk(tmp_brk);  curr_brk=sbrk(0);  printf("%p\n",curr_brk);  getchar();  return 0; }

  1.    初始时,堆的起始地址start_brk以及堆的当前末尾brk指向同一地址。根据是否开启ALSR,两者的具体位置会有所不同。

  2.    不开启ASMR时,start_brk以及brk会指向data/bss段的结尾。

  3.    开启ASMR时,start_brk以及brk也会指向同一位置,只是这个位置是在data/bss段结尾后的随机偏移处。

  4.    sbrk创建的chunk紧邻数据段

  l  mmap函数机制

  1.    malloc会使用mmap来创建独立的匿名映射段。

  2.    匿名映射的目的主要是可以申请以0填充的内存,并且这块内存仅被调用进程所使用,这块内存为系统随机分配。

  3.    munmap用于释放内存。

  4.    mmap创建的chunk紧邻libc

  data/bss

  l  bss段通常是指用来存放程序中未初始化的全局变量的一块内存区域。

  l  data段通常是指用来存放程序中已初始化的全局变量的一块内存区域。

  多线程支持

  l  在原来的dlmalloc实现中,当两个线程同时要申请内存时,只有一个线程可以进入临界区申请内存,而另外一个线程必须等待直到临界区中不再有线程。

  l  这是因为所有的线程共享一个堆。

  l  在glibc和ptmalloc实现中,支持了多线程的快速访问,在新的实现中,所有的线程共享多个堆。

  堆数据结构

  l  宏观结构:包括堆的宏观信息,通过这些数据结构索引堆的基本信息

  l  宏观结构主要是堆块之间的连接

  l  微观结构:主要用于处理堆的分配与回收中的内存块

  l  malloc & free

  宏观结构

  arena & main_arena

  l  主线程对应main_arena,管理所有堆块的结构体

  l  多线程的子线程对应arena,存在于线程的控制块plt中

  不是每个线程都会有对应的arena

  因为每个系统的核数有限,当线程数大于核数的二倍时,就必然有线程处于等待状态,所以没有必要为每个线程分配一个arena

  32bit --> arena_num = 2 * core

  64bit --> arena_num = 8 * core

  l  chunk_size的倒数第三个标志位NON_MAIN_ARENA,多线程时为1.主线程为0

  l  子线程的堆和主线程的堆不一样

  l  每个线程会预分配一个堆空间

  1.   线程会从这个对空间创建top_chunk和堆块

  2.   当malloc的空间超过预分配的大小,会回到main_arena之前再次分配一个空间

  3.  如果线程的堆存在溢出,可以之前的chunk越界写堆的arena结构

  l  定位子线程的chunk的技巧

  1.   向子线程的堆块输入特殊值:"0xdeadbeef"

  2.   在gdb使用 search -4 0xdeadbeef

  3.   搜索出来的地址即堆的地址

  l  多线程利用思路

  1.  在子线程中找到堆空间的地址空间A

  2.  在A中找到恢复线程的arena的结构

  3. 通过arena的结构尝试堆利用

  top_chunk

  l  当一个chunk处于一个arena的最顶部(最高内存地址)的时候,称之为top_chunk

  l  当系统当前所有的bin都无法满足用户请求的内存大小的时候,将此chunk分配给用户使用

  main_arena    ---> sbrk

  thread arena   ---> mmap

  l  如果top_chunk比用户请求的大小要大的话,就将该top_chunk分为两部分

  1.   用户请求的chunk

  2.   剩余的部分成为新的top_chunk

  l  否则需要扩展heap获分配新的heap,原来的top_chunk划入unsortedbin

  l  top_chunk漏洞利用

  1.   当当前的top_chunk的空间不够的时候,系统就会新创建一个top_chunk

  2.   原来的top_chunk被分配到到unsortedbin里面

  3.   在题目中没有free函数的时候,则无法将块进入bin链

  4.   off by one --> 在top_chunk之上构建一个0x88的堆块,改写top_chunk的size大小

  5.  // [漏洞学名]:house of orange

  bins

  l  作用:管理free的malloc_chunk

  l  种类:按照free的chunk大小划分

  u  fastbin :0x20-0x80  :注意fastbin不属于bins,是ptmalloc单独用来管理0x20-0x80的堆块的数据结构,如果free的chunk大小在0x20-0x80之间,会优先进入fashbin,

  u  smallbin :0x20-0x400

  u  unsortedbin : free掉的chunk优先进入unsortedbin,除了fastbin管理的堆块

  ²  存在整理过程,将所有放在unsortedbin链上的堆块按照大小整理到其它链上

  ²  将fastbin上的碎片整理到unsorted,再有unsorted整理到其他bin链

  u  largebin :0x400以上

  l  对于small bins,large bins,unsorted bins来说,ptmalloc将它们维护在同一个数组中,对应的数据结构在malloc_state中

  #define NBINS 128 // bins总共有128个,除了fastbin

  mchunkptr bins[NBINS * 2 - 2]  //mchunkptr 是指向chunk头的指针,bin = fd+bk

  l  管理流程

  1.   malloc/free --> glibc --> arena --> fastbin/bins  -->smallbin/largebin/unsortedbin

  2.   从glibc找到main_arena

  3.   在main_arena的管理结构体malloc_state通过固定偏移中找到fastbinsY[NFASTBINS],用以管理fastbin。

  4.   找到bins[NBINS * 2 - 2],用以管理unsortedbin。

  l  bin的放置顺序

  索引为1的是unsortedbin,这里面的chunk没有进行排序,比较杂乱。

  索引从2到63的bin称为small bin,同一个small bin链表中的chunk的大小相同。两个相邻索引的small bin链表中的chunk大小为2个机器字节,即32-->4字节,64-->8字节。

  索引从64到126的bin被称为large bin。large bins中的每一个bin都包含一定范围内的chunk,其中的chunk按fd指针的顺序从大到小排列,最靠近bin头的越大,相同大小的chunk按照最近使用顺序排列。

  l  任意两个物理相邻的空闲chunk不能在一起,否则会合并。

  l  free之后的chunk,与top_chunk相邻的,会与top_chunk合并,不与之相邻的,会根据其大小进入到不同的bin

  小的进入fastbin,大的进入unsortedbin

  此时,释放掉的chunk不会马上归还系统,ptmalloc会统一管理heap和mmap映射区域的空闲的chunk。

  当用户再一次请求分配内存时,ptmalloc分配器会试图在空闲的chunk中挑选一块合适的给用户,这样可以避免频繁的系统调用,减少内存分配的开销。

  l  需要注意的是,并不是所有的chunk被释放之后立即放到bin中。ptmalloc为了提高分配的速度,会把一些小的堆块先放到fast bin的容器内。而且fast bin容器中的chunk的使用标记总是被置为1的,所以不会自动合并。


大家都在看

OPENAI放开限制,ChatGPT无需注册即可...

2024-08-09 浏览次数:0

网络安全工程师哪家培训机构好?成都汇智知了堂引领...

2024-08-09 浏览次数:0

你为什么连实习都找不到...

2024-08-09 浏览次数:0

汇智知了堂网络安全75班晨会:深入探索NAS应用...

2024-08-09 浏览次数:0

Java18班开班——蜕变从这里开始

2024-08-09 浏览次数:0

2024年,IT行业下一个就业风口会是什么?

2024-08-09 浏览次数:0
最新资讯
二进制安全之堆溢出(系列)——...   二进制安全之堆溢出(系列)第二期来啦  鉴于本期干货够多  知了姐怕大家一时间消化不了,  特意...
【干货】二进制安全之堆溢出(系... 知了堂禁卫实验室全新上线!!