global_max_fast

文章来源:https://xz.aliyun.com/t/5082#toc-8

global_max_fast

此次的源码是基于libc-2.23的,后续的版本加入了tcache,该机制相对来说比较简单与独立,所以还是基于2.23进行相应的分析,在64位系统上进行。
global_max_fast这个全局变量的作用是用来标志fastbin的大小的阈值,小于这个值的堆块会被认为是fastbin,使用fastbin的相应机制进行管理。看下它的定义:

1
2
3
4
#define set_max_fast(s) \
global_max_fast = (((s) == 0) \
? SMALLBIN_WIDTH : ((s + SIZE_SZ) & ~MALLOC_ALIGN_MASK))
#define get_max_fast() global_max_fast

set_max_fast初始化函数开始是在malloc_init_state调用的,可以看到这个宏定义的作用是设置global_max_fast默认值,默认值是0x80。

然后看malloc中对于fastbin的处理,fastbin处理很简单,就是找到对应的fastbin的单链表,并从中取出堆块,如果size检查通过就将该堆块返回:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
if ((unsigned long) (nb) <= (unsigned long) (get_max_fast ()))
{
idx = fastbin_index (nb);
mfastbinptr *fb = &fastbin (av, idx); ## 找到对应的单链表
mchunkptr pp = *fb;
do
{
victim = pp;
if (victim == NULL)
break;
}
while ((pp = catomic_compare_and_exchange_val_acq (fb, victim->fd, victim))
!= victim);
if (victim != 0)
{
if (__builtin_expect (fastbin_index (chunksize (victim)) != idx, 0)) ## 检查size
{
errstr = "malloc(): memory corruption (fast)";
errout:
malloc_printerr (check_action, errstr, chunk2mem (victim), av);
return NULL;
}
check_remalloced_chunk (av, victim, nb);
void *p = chunk2mem (victim);
alloc_perturb (p, bytes);
return p; #返回
}
}

查看free中的fastbin相关的处理源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
if ((unsigned long)(size) <= (unsigned long)(get_max_fast ())

...
## 对size进行基本的检查
if (__builtin_expect (chunk_at_offset (p, size)->size <= 2 * SIZE_SZ, 0)
|| __builtin_expect (chunksize (chunk_at_offset (p, size))
>= av->system_mem, 0))
{
...
## 对next chunksize进行检查
if (chunk_at_offset (p, size)->size <= 2 * SIZE_SZ
|| chunksize (chunk_at_offset (p, size)) >= av->system_mem;
}))
{
errstr = "free(): invalid next size (fast)";
goto errout;
}
...

## 获取对应的fastbin index
unsigned int idx = fastbin_index(size);
fb = &fastbin (av, idx);

...

do
{
/* Check that the top of the bin is not the record we are going to add
(i.e., double free). */
if (__builtin_expect (old == p, 0))
errstr = "double free or corruption (fasttop)";
goto errout;
}
...
p->fd = old2 = old;
}

对于fastbin的free过程主要包括如下:

  1. 对释放的堆块的size进行基本的检查。
  2. 对释放堆块的下一个堆块的size进行基本的检查。
  3. 获取释放堆块所对应的fastbin链表对应的索引。
  4. 检查是否是double free。
  5. 释放进单链表。

fastbin的单链表管理是比较简单的,与global_max_fast相关且需要注意的代码则是 fastbin 所对应的 index 获取以及 index所对应的指针获取的代码,即fastbin_index宏以及fastbin宏,对应代码如下:

1
2
3
4
#define fastbin_index(sz) \
((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2)

#define fastbin(ar_ptr, idx) ((ar_ptr)->fastbinsY[idx])

可以看到这两个宏仅仅是利用偏移来定位数组的指针,但是 arena 所对应的malloc_state中 fastbins 数组相关的定义为:

1
2
3
mfastbinptr fastbinsY[NFASTBINS]

#define NFASTBINS (fastbin_index (request2size (MAX_FAST_SIZE)) + 1)

到这里问题就比较明显了,如果可以改写global_max_fast为一个较大的值,然后释放一个较大的堆块时,由于fastbins数组空间是有限的,其相对偏移将会往后覆盖,如果释放堆块的size可控,就可实现往fastbins数组(main_arena)后的任意地址写入所释放堆块的地址。

即利用global_max_fast进行相关的攻击

利用场景

对于global_max_fast的利用首先要解决的事情是如何覆盖global_max_fast。适用的场景应是存在任意地址写的漏洞,但是写入的值却是不可控的(也是一个比较大的值),因为如果写入的值也是可控的话就不需要使用这个方法就能解决了,最典型的应该是unsorted bin attack,可实现往任意地址写入main_arena中的地址。

前置条件我想大概可能是需要泄露一个libc的地址,否则的话可能会像heap_master中一样需要爆破4bit的地址。

实现任意地址写的方式是:通过地址与fastbin数组的偏移计算出所需free的堆块的size,然后释放相应的堆块,即可实现往该地址写入堆块的地址以进一步利用。

计算偏移的代码可以如下:

1
2
3
fastbin_ptr = libc_base + libc.symbols['main_arena'] + 8
idx = (target_addr-fastbin_ptr)/8
size = idx*0x10 + 0x20
1
size = (target_addr - main_arena - 0x18) * 2 + 0x20

此时要解决的事情是往哪里写以达到实现利用的目的。可能有很多的地方,理论上来说只要是main_arena结构体后面的是函数指针或是结构体指针的地址都可以,目前很容易能够预想到的是:

  • _IO_list_all
  • stdout
  • stdin
  • stderr
  • __free_hook

复写前面四个就是使用IO_file攻击那一套方法,伪造结构体来实现任意读任意写或者伪造 vtable 来实现house of orange攻击。

复写__free_hook的话则需要一次uaf来把fd改成system或者one gadget,再将堆块申请出来,从而实现将__free_hook改写成system或者one gadget。因为在 malloc 的时候会把 fastbinsY 的链表头部取出,并且把其 fd 位置的内容作为链表头部写入到 fastbinsY 数组中,而在这个过程中没有对可控堆块的 fd 位置的内容的合法性做检查。

小结

global_max_fast的一些相关场景包括:

  • 可能能够得到libc地址。
  • 能够控制free堆块的size。
  • 能往任意地址写但是却无法控制写的内容。

以此来实现往main_arena后面的任意地址写堆块地址的效果,以实现后续的利用,相关的漏洞利用方式包括unsorted bin attack以及 house of orange(IO file)等。

查看评论