Fastbin Attack



Fastbin Attack是fastbin在存储管理时,为保证快速分配,回收内存的需要,在内存管理的机制中出现的问题,进而造成的漏洞,能够通过漏洞改写main_arena上的FasbinY指针数组,从而获得“特定”(需要满足一定条件)地址的写权限。

原理

要想了解fastbin_Attack的原理需要熟悉ptmalloc中对fastbin的管理

fastbin_dup

程序分配了3个heap,由于大小只有8个字节,所以都属于fastbin
fastbin用于快速的分配与释放的小内存,所以它的结构与其他的bin不同,是一个LIFO的单项链表,chunk上只有*fd指针。
其头指针fastbinY[index] (index是根据chunk大小分配到哪一个队列中)指向链表头节点,无论是fastbin的插入还是删除都只对该单链表的链表头操作,即FastbinY[i]指向的chunk
若上述程序在free(a),free(b),free(c)后分配的堆空间应当如下:

fastbin_free

malloc上关于fastbin的free的源代码如下:

sourcecode有详细的注释,基本的原理如下:
free的chunk通过 P->FD = *FB; *FB = P操作添加到fastbin 的队列中,位于队列的头节点,实现链表的加入,并且在free的时候会做下面这个判断

如果我们刚刚free(p),它被加入了相对应的fastbin链表中,fastbinY[i]指针指向它,再次free(p)就会造成指针直接指向的的chunk与我们将要free的chunk相同,glibc的patch判断其为double free,程序Aborted
所以我们需要在free(p)后再次free其他的一个chunk让它进入链表头取代p,再free(p)就能绕过Patch,从而实现p的UAF,上述代码中也是这样利用的
在实际调试过程中,free一个新的chunk后,会更改单链表的头指针fastbinY[i]指向这个新的chunk,其代码实现在sourcecode中是

在汇编层面,是这样实现的

这是Linux Kernel 下的汇编指令,是cpu为了能够实现原子操作而单独设计的汇编指令
cmpxchg(void* ptr, int old, int new)
如果ptr和old的值一样,则把new写到ptr内存,否则返回ptr的值。
在Intel CPU下,会用lock cmpxchg来实现,这里的lock个人理解是锁住内存总线,这样如果有另一个线程想访问ptr的内存,就会被block住,主要因为main_arena这个临界资源上锁了,修改fastbinY表时需要解锁,并且不能够在这个过程中被中断等等,所以在硬件层面上,Intel就设计了这样的汇编指令进行原子操作(无法被打断)

fastbin_malloc

如果malloc的chunk恰好在fastbin[Y]链表中,则就会从中进行选择链表头的chunk返回给用户,并且同样在catomic_compare_and_exchange_val_acq (fb, victim->fd, victim))!= victim处修改fastbinY[index]指针的内容为该chunk的fd指针(下一chunk的内容),相当于实现fastbin单链表的删除,Fastbin_Attack就是利用libc中这个对FastBinY”草率的任意写”进行的
试想,如果我们通过UAF恶意构造了*fd指针的内容(mem指针的位置,chunk+0x08/chunk+0x10,就是用户输入的起始位置),malloc时,libc误以为fd指针指向的是fastbin链表中下一个chunk的内容,则再次malloc就会分配heap到一个任意地址。
这里也有相应的检查

判断释放的chunk的大小是否在fastbinY[idx]的范围内,防止别有用心的人构造fake chunk,但显然我们设计好大小就能够绕过该检查,这是fastbin利用比较有技巧的地方

通过fastbin_malloc 与fastbin_free的分析,我们可以知道对于fastbin,由于它是这样一个LIFO,并且都只对头结点进行操作,我们free(p)后再次malloc(p)得到的chunk就是刚刚释放的
这样就不难理解fastdup.c中的freelist为什么是那样排布,并且再次malloc到为什么是相同的地址了
程序运行的结果如下:

所以,对于fastbins,如何进行uaf,如何进行double free是fastbin attack的难处

漏洞利用

shellphish how2heap中的fastbin_dup_intostack程序,我个人稍微进行了修改,实现了更加直观的攻击效果

从原理中我们已知,可以利用fastbin_dup的实现对chunk的uaf,在上述代码中,如同fastbin_dup所示,我们再次malloc时能够重新利用到a指针,它位于fastbin的单链表头结点,malloc两次后fastbin中链表变成右图

由于我们能够通过第一个malloc:unsigned long long *d = malloc(8)得到的指针修改A中fd指针
我们通过这样方式恶意修改fd指针的内容为*d = (unsigned long long) (((char*)&stack_var) – sizeof(d))
这样我们再次malloc(8)时,即从fastbin中删除chunk A,原本的fastbinY[0]单链表头指针

由于这样一个原子操作写内存

被更改为了栈上地址,就是stack_var-8的地址,如下图

这样当我们再次malloc时,fastbin检查到该位置为&stack_var-0x8就会将(&stack_var-0x8)的地址(glibc认为这是一块fastbin)分配给用户,用户返回地址(&stack_var-0x8)+0x10 =&stack+0x8(mem指针)
这样我们获得的*attack指针实际上就指向了stack_var附近的地址,我们对它的内容进行修改,也就反应到了该栈中
在利用过程中,我们将stack_var = 0x20改成了0x20,让glibc错误认为这是该chunk的size,绕过了fastbin_malloc中的fastbin_index (chunksize (victim)) != idx, 0 大小检查,这也是为什么我们写入的时特意控制为&stack_var-0x8,因为此处地址值可控,用以让过glibc的检查

通过上述手段,精心构造,我们相当于能够得到任意地址的指针,最终在栈中写入了字符串”AAA”
程序的运行结果:

要点

  1. 最后一次malloc分配的heap chunk可以不对齐,只要通过相应的检查即可
  2. 需要寻找满足条件的地址,使得fastbin_index (chunksize (victim)) != idx, 0绕过malloc中的大小检查,这也是fastbin attack能够使用的主要限制因素,所以一般我们可以构造,将fastbin劫持到可控位置。

发表评论