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 | |
set_max_fast初始化函数开始是在malloc_init_state调用的,可以看到这个宏定义的作用是设置global_max_fast默认值,默认值是0x80。
然后看malloc中对于fastbin的处理,fastbin处理很简单,就是找到对应的fastbin的单链表,并从中取出堆块,如果size检查通过就将该堆块返回:
1 | |
查看free中的fastbin相关的处理源码:
1 | |
对于fastbin的free过程主要包括如下:
- 对释放的堆块的size进行基本的检查。
- 对释放堆块的下一个堆块的size进行基本的检查。
- 获取释放堆块所对应的fastbin链表对应的索引。
- 检查是否是double free。
- 释放进单链表。
fastbin的单链表管理是比较简单的,与global_max_fast相关且需要注意的代码则是 fastbin 所对应的 index 获取以及 index所对应的指针获取的代码,即fastbin_index宏以及fastbin宏,对应代码如下:
1 | |
可以看到这两个宏仅仅是利用偏移来定位数组的指针,但是 arena 所对应的malloc_state中 fastbins 数组相关的定义为:
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 | |
1 | |
此时要解决的事情是往哪里写以达到实现利用的目的。可能有很多的地方,理论上来说只要是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)等。
- 本文作者:ShouCheng
- 本文链接:http://shoucheng3.github.io/2022/03/03/2022-01-12-global-max-fast/index.html
- 版权声明:本博客所有文章均采用 BY-NC-SA 许可协议,转载请注明出处!