堆块Unlink的理解

unlink

程序里肯定会有指向堆块的地址. 而在我们的组织堆块的链表里面也是保存的堆块地址, 能否让堆块以为程序里这保存的地址是其他的堆块指向他的呢?

在双向链表里面, 堆块们通过链表的形式排队. 当有堆块要离开的时候, 他就要进行工作交接, 否则一走了之的话链表就断了.

工作交接具体是两个内容, 和前面的链表说, 你后面的兄弟不再是我了, 我要走了, 这是我后面的兄弟, 它以后才是你后面的兄弟了, 向后找的时候去找它. 同样和后面的兄弟说要照顾好原来自己前面的堆块 也就是让forword块保管好自己的back指针, 让back块保管好自己的forward指针.

由于堆块经常被骗, 他们只好长个心眼, 不能改了别人的指针. 让后面的堆块照顾好自己前面的堆块时, 需要修改的是后面的堆块的fd指针, 这个指针原来的值就是堆块自己. 让前面的堆块照顾好自己后面的堆块时, 需要修改的是前面的堆块的bk指针, 这个指针原来的值就是堆块自己. 如果不是自己, 就肯定是被骗了, 这时候堆块就报警了, 程序就报错了

这里先讲一个任意地址写的故事, 程序会分配堆块, 自己保存好堆块指针, 需要数据就根据堆块指针去找, 如果我们能够随意改写堆块指针, 不就可以达到想写(读)哪里就写哪里的效果了吗? 那怎么改写呢? 我们先放开这个问题

但是unlink, 并没有这么简单, 我们接下来仔细分析一下 程序里面指向堆块的指针和libc里用的不太一样, 程序里是指向堆块的内容, 而libc里则是堆块结构体的头部, 向前偏移了0x10字节. 另外就是一般利用的是前向合并时的unlink. 当free一个堆块, 会前后检查free的堆块, 合并起来, 这样就不会有相邻的free块. 而free的块肯定都是在bins里的, 而且不是fastbin, 因为fastbin的块没有标成free. 所以free一个堆块的时候, 前向合并前一个堆块的时候, 就要把前面的堆块从链表里拿出来, 合并完再放到合适的链表里. 利用unlink时, 我们利用堆溢出漏洞, 修改unlink块溢出到下一块, 去除previous in use bit, 并伪造prev size, 这里伪造的size要小0x10字节, 刚好是用户内容域, 伪造的堆块小10字节也是为了和程序内指向堆块内容的指针合作. 这样free后面的块的时候, 就会对前面的伪造的小一号的堆块进行unlink, 所以unlink时伪造堆块的fd和bk指针指向哪里? 回顾之前的知识, 可以知道, fd 的bk(+0x18) = 自己(堆块指针) bk 的fd(+0x10) = 自己(堆块指针) 反过来 fd = 自己指针 - 0x18 bk = 自己指针 - 0x10

效果就是把自己指针先改成自己的bk, 再改成自己的fd, 即自己的指针指向了 自己指针 - 0x18 这个地址可不得了, 不是堆段了, 而是程序数据域了, 旁边很可能就是其他堆块的指针, 去改他们就可以任意地址写了

作用: UAF->溢出 要求: 修改free的堆块, 知道另外一处指向堆块的指针

虚假堆快

需要能错位header, 再使用fastbin attack

错位到main_arena 改写top chunk地址, 达到任意分配堆块的目的