0%

heap

bins

0

global_max_fast

glibc(GNU C Library)中动态内存分配器(ptmalloc2) 的一个关键全局变量,用于控制 fast bins(快速分配区) 的最大内存块大小。

fast bin

单向链表

32位下fast bin范围为16到64

64位下fast bin范围为32到128

从块分配器的角度来看,fastbin 中的块被视为已分配的块。它们仅在 malloc_consolidate 中批量与相邻对象合并。

double free

1
2
3
4
5
6
7
_int_free
-> if ((size) <= get_max_fast ())
-> unsigned int idx = fastbin_index(size);
-> fb = &fastbin (av, idx);
-> mchunkptr old = *fb, old2;
-> if (old == p)
-> malloc_printerr ("double free or corruption (fasttop)");

这里对double free漏洞的检查:

获取fastbin链表中最后入链的old,然后判断即将释放的fastbin和old的指针是否相同

unsorted bin

unsorted bins的bk和fd指向的是一个指针,而这个指针指向的是top chunk的地址,这个地址又储存在main_arena的0x58偏移处

main_arena - 0x10即为__malloc_hook的,__malloc_hook又是调用malloc时会调用的指针,所以可以通过劫持__malloc_hook来劫持程序控制流

然后通过fastbin attack将下一个堆块改为__malloc_hook - 0x23处,因为只有改为这处,视为堆块的此处的size位置才为正确的数据

binmap

Binmap的底层结构

  1. 物理存储
    binmapmalloc_state结构体中的一个数组(unsigned int binmap[BINMAPSIZE]),每个元素为32位无符号整数(unsigned int)。

    总长度:固定为4个int(即128位,对应63个large bin的索引需求)

    分组逻辑:每个int(32位)称为一个block,每个block负责管理32个连续的large bin状态

计算main_arena

  1. 通过上面的泄露unsorted_bin的fd指针

  2. 通过__malloc_trim函数直接获得

    “比如把 .so 文件放到 IDA 中,找到 malloc_trim 函数,就可以获得偏移了。” -–ctfwiki

tcache

glibc 2.26后

两个结构体

tcache dup

仅限glibc2.26,可以直接对其进行double free

tcache_entry

1
2
3
4
5
6
/* We overlay this structure on the user-data portion of a chunk when
the chunk is stored in the per-thread cache. */
typedef struct tcache_entry
{
struct tcache_entry *next;
} tcache_entry;

一个单向链表

tcache_perthread_struct

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* There is one of these for each thread, which contains the
per-thread cache (hence "tcache_perthread_struct"). Keeping
overall size low is mildly important. Note that COUNTS and ENTRIES
are redundant (we could have just counted the linked list each
time), this is for performance reasons. */
typedef struct tcache_perthread_struct
{
char counts[TCACHE_MAX_BINS];
tcache_entry *entries[TCACHE_MAX_BINS];
} tcache_perthread_struct;

# define TCACHE_MAX_BINS 64

static __thread tcache_perthread_struct *tcache = NULL;

通过counts记录tcache_entry上空闲的chunk数目