Unlink攻击的理解与应用
Unlink攻击的理解与应用
原理
1.简介
unlink,俗称脱链,就是将链表头处的free堆块从unsorted bin中脱离出来,然后和物理地址相邻的新free堆块合并(向前合并或者向后合并)成一个大堆块,再放入unsorted bin 中。
2.危害原理
通过为伪造free状态的fake_chunk,伪造fd和bk指针,通过绕过unlink的检测来实现unlink,unlink就会往p所在位置写入p-0x18(具体怎么计算的在后面会有详细解释),从而实现任意地址写的漏洞。
3.漏洞产生原因
修改了堆块头的pre_in_use位,例如off by null,off by one ,堆溢出。
现在来看下具体实现unlink操作的源码(在看源码前建议将堆块头的标志位作用再重新熟悉一遍)
#!c
/*malloc.c int_free函数中*/
/*这里p指向当前malloc_chunk结构体,bck和fwd分别为当前chunk的向后和向前一个free chunk*/
if (!prev_inuse(p)) {
prevsize = p->prev_size;//注意在源码中是通过prevsize字段找前一个堆块的位置
size += prevsize;
//修改指向当前chunk的指针,指向前一个chunk。
p = chunk_at_offset(p, -((long) prevsize));
unlink(p, bck, fwd);
}
// 相关函数说明:
#define chunk_at_offset(p, s) ((mchunkptr) (((char *) (p)) + (s)))
/* unlink操作的实质就是:将P所指向的chunk从双向链表中移除,这里BK与FD用作临时变量 */
#define unlink(P, BK, FD) {
FD = P->fd;
BK = P->bk;
if (__builtin_expect (FD->bk != P || BK->fd != P, 0))//条件FD->bk==BK->fd==p
malloc_printerr(check_action, "corrupted double-linked list", P, AV);
FD->bk = BK;
BK->fd = FD;
}
源码后两行个人感觉有点难理解,FD和BK是怎么寻址找到FD->bk和BK->fd的呢?
FD->bk = BK; BK->fd = FD;答案就是偏移,在一个堆结构的结构体中,是通过变量类型对应的大小找相应的偏移的。回顾堆结构,fd在相对于堆0x10的位置,bk在相对于堆0x18的位置。
因此
FD->bk<==>*(FD+0x18) BK->fd<==>*(BK+0x10)
图示

second_chunk进行unlink操作,效果:

绕过和利用
题目常常会用一个全局数组或者链表记录各个堆块的位置,这里以指针数组list为例,假如有list依次记录着各个堆块的起始位置。
heaparray[n] = malloc(size);
创建了三个堆块
add(0x40,b'aaaa')#chunk 0
add(0x80,b'bbbb')#chunk 1
add(0x40,b'cccc')#chunk 2
效果
现在在堆块0里创建一个已经free的fake chunk,伪造如下:
chunk=0x6020c0#fake chunk在chunk 0中,chunk 0在chunk中(*chunk==chunk0)
fd=chunk-0x18# 为什么这么构造下面说
bk=chunk-0x10
效果

此时delete chunk1,就会对chunk1触发unlink 操作。
为什么fd=chunk-0x18,bk=chunk-0x10呢?因为这样才能绕过FD->bk==BK->fd==p检查
FD=chunk-0x18=0x6020a8
BK=chunk-0x10=0x6020a0
FD->bk=FD+0x18=0x6020c0=chunk
BK->fd=BK+0x10=0x6020c0=chunk
这样就绕过了这个检查,然后
FD->bk = chunk=0x6020c0
BK=0x6020a0
==> *chunk=BK,即chunk->BK->...
BK->fd =chunk=0x6020c0
FD=0x6020a8
==> *chunk=FD,即chunk->FD->...
因此最终效果就是*chunk=chunk-0x18.即chunk里面写入了chunk-0x18的值
如图

这时候由于我们没有释放chunk 0,因此我们仍然可以通过list数组寻址chunk0进行修改,但这时候我们就不是在堆里面进行修改了,而是在我们上面对chunk进行修改后,里面写入的chunk-0x18的地方。
我们在chunk-0x18的地方写入然后再次覆盖chunk的值,这样就实现了任意地址写。
效果

还有最后一个问题是为什么很多unlink攻击要创建4个堆块,四个堆块分别有什么要注意的地方?
chunk0;能写入fake chunk
chunk1:要满足能放入unsorted bin大小的堆块
chunk2:防止chunk1释放后也和top chunk直接合并
chunk3:防止堆块重叠

浙公网安备 33010602011771号