pwn - Heap Exploitation
堆
今天整理了一下Heap部分的一些笔记,小汇总一下
在程序运行过程中,堆可以提供动态分配的内存,允许程序申请大小未知的内存。堆是程序虚拟空间地址的一块连续的线性区域,由低
地址向高
地址上增长
堆题漏洞一般在delete()函数上,多半是指针未清空导致成为野指针,从而可以进行UAF
等
实现堆利用的方法
- ptmalloc2 - glibc
- dlmalloc - General purpose allocator
- jemalloc - Firefox and FreeBSD
- tcmalloc - Google
- libumem - Solaris
ps:与系统交互的函数主要是(s)brk
函数以及mmap
,munmap
函数,不是malloc或者free
malloc
malloc(size_t
n
)
- malloc返回对应大小字节的内存块的指针,此外,该函数对一些异常进行了处理
- n = 0 , 返回当前系统允许的堆的
最小内存块
- 当n为负数时,由于在大多数系统上,
size_t
是无符号常数,所以会系统会申请很大的内存空间,但通常来说都会失败,因为系统没有那么多的内存可以分配
- n = 0 , 返回当前系统允许的堆的
free
free(void*
p
)
- free函数会释放由p指向的内存块,这个内存块可能是通过malloc得到的,也可能是通过相关函数realloc得到的
- 对异常的处理
- 当p为
空指针
时,函数不执行任何操作 - 当p被释放后,
再次释放
会出现乱七八糟的效果,即double free - 除了被禁用
mallopt
的情况下,当释放很大的内存空间时,程序会将这些内存空间还给系统,以便于减小程序所使用的内存空间
- 当p为
(s)brk
操作系统提供了brk函数,glibc库提供了sbrk函数,我们可以通过增加brk的大小来向操作系统申请内存
- 堆的起始地址
start_brk
和堆的当前末尾brk
指向同一地址,根据是否开启ASLR两者的具体位置会有所不同- 不开启ASLR:start_brk和brk会指向data/bss段的结尾
- 开启ASLR:start_brk和brk,也会指向同一位置,只是这个位置会在data/bss段的结尾后随机偏移
chunk
- 结构其实就是header段+data段
- size_alignment = 0x10的倍数(malloc
0x18
会拿到0x20
的大小) - 整个memory大小为header(0x10) + data
由malloc申请的内存为chunk,这块内存在ptmalloc内部用malloc_chunk结构体表示,当程序申请的chunk被free掉后,会加入到相应的空闲管理列表
- chunk结构统一,无论大小,处于分配还是释放状态
- 根据是否被释放,表现形式会有所不同
字段 | 释意 |
---|---|
prev_size | 如果该chunk物理相邻的前一个地址chunk(两个指针的地址差值为前一个chunk大小)是空闲的话,那该字段记录的是前一个chunk的大小,否则记录前一个chunk(低地址chunk)的数据 P->PREV_INUSE(P):上一个chunk是否使用中 M->MMAPED(M):chunk是否通过mmap生成 NON_MAIN_AREA(N):该chunk是否不属于main area |
size | chunk的大小必须是2*SIZE_SZ的整数倍;32位SIZE_SZ大小为4,64位SIZE_SZ大小为8 |
fd | chunk处于分配状态,fd开始是用户数据;若chunk空闲,则fd指向下一个(非物理相邻)的空闲chunk.,bk指向上一个(非物理相邻)的空闲chunk;通过fd,bk将空闲的chunk块加入到空闲的chunk块链表进行统一管理 |
bin
用户释放掉的chunk不会马上返回给系统,会由ptmalloc管理heap和mmap映射区域中空闲的chunk,ptmalloc管理器会挑一块适合的给用户,这样可以避免频繁的系统调用,降低内存分配的开销
根据chunk的大小和使用状态将chunk初步划分为4类:fast bins,small bins,large bins,unsorted bins
除了fast bin是单链表,其余(small bin,large bin,unsorted bin)都是双链表
堆溢出
程序向堆块中写入的字节数超过了堆块本身可使用的字节数(可利用的字节数都不小于用户申请的字节数),因而导致了数据溢出,并覆盖到物理相邻的高地址的下一个堆块
Fast Bin
- chunk的大小在32字节-128字节(0x20 - 0x80)的chunk称为fast chunk(大小为内存中struct_malloc_chunk的大小)
- Fastbin链表个数为10个
- 快速地进行小内存的分配和释放
- 单链表(使用fd指针,bk没有用到),故fastbin中增添或者删除fast chunk都是在对
链表尾
进行操作 - fastbin链表的每个chunk大小相同,不同链表之间的chunk不同
- LIFO(Last In First Out)
- 被free掉的时候会将下一块chunk p设置成为0
Unsorted Bin
- 释放较小或较大的chunk时,如果系统没有将他们添加到对应的bins中,系统就会将这些chunk添加到unsorted bin中去
- 为了
glibc mallc机制
有第二次
机会利用最近释放的chunk(第一次是fastbin
),加快内存的分配和释放,不再花费额外的时间去查找额外的chunk - Unsortedbin链表个数为1个
- free chunks组成的循环双链表
- 对大小没有限制
- FIFO
Small Bin
- 小于1024字节(0x400)的chunk称之为small chunk,small bin用于管理small chunk
- smallbin链表个数62个
- 相邻的free chunk需要进行合并操作,合并成一个大free chunk
- 内存分配速度:fas tbin < small bin < large bin
- free chunks组成的循环双链表
- FIFO
- small bin链表中每个chunk大小相同,不同链表之间chunk大小不同
- free:small chunk free之后,会检查该chunk相邻的chunk是否free,如果是的话将进行合并操作,将这些chunks合并成为新的chunk,然后将它们从small bin中移除,最后将新的chunk添加到unsorted bin中,之后unsourted bin进行整理再添加到对应的bin链上
Large Bin
- 大小等于1024字节(0x400)的chunk称为large chunk
- largebin链表个数为63个,分为6组
- 用fd_nextsize , bk_nextsize连接起来
- 其合并类似于small bin
- 同一个largebin链表每个chunk可以不一样(从大到小排序)
- large chunk可以添加,删除在large bin中的任何一个位置
Unsorted Bin
- 双向链表(Circular doubly linked list)
- free的chunk size > fastbin时,不会直接放到对应的bin里,会先丢到Unsorted Bin
- malloc fastbin size大小时会先去fastbin list里找,若没有则会到unsorted bin找,如果找到一样大小的则回传,若无但找到大小大于所需大小的chunk则会切割回传,剩下的部分都会丢回unsorted bin,最后实在没有会从top chunk切出来回传