z在刚才,晚上十一点半,我突然意识到了数据结构的重要性。
首先,链表,链表的应用在我现在接触到的无非就是pwn中的堆溢出了,在堆被FREE后,free的堆都被存放在相关的bins中,并且以链表的方式进行管理,以链表中节点进行类比的话,free的chunk中的FD就是指向前一个被free的chunk指针,而BD就是指向后一个被free的chunk的指针,如此的话,对bin的管理无非就是增加和删除,对应的链表形式无非就是FD和BD的变化,这一点如果对数据结构的链表很熟悉的话,对于从bin中的chunk链表删除一个chunk时FD和BK的变化应该是显而易见的。
后悔没有把数据结构认真学好啊
什么是链表 <------不知道链表点他
浅谈链表(2)——节点的插入与删除 《-----------点他也可以
关于堆溢出的学习,这次我选择先打牢固基础,在进阶。
链表,链表结点的增添,链表节点的删除。
接着说堆溢出攻击,如果在内存中,伪造一个chunk,类比链表无非就是在一处地址对齐的地方,创造一个node,这个node的前一个节点的指针和后一个指针写好就行了。换成堆溢出就是FD和BK要写好,然后再加上prev_size和size和标志位等数据,这样一个假的chunk就创建成功了。
关于doublefree 这个是我今晚刚刚查的,其实就是在free一个chunk后再次free一个相同的chunk,这样的话链表中的结构就类似于这样了
记忆的时候,一定记清楚,fd就是forward,指的是之前释放的堆,也就是前一个
(下面的这张手绘图可能不对,因为我是按照以前的调试和记忆写的)
在各种bins中,其实就是个单链表和双链表的关系。(推荐看数学之美这本书,这里就体现到了数据结构的作用)
了解了这一点,我相信在学习中是很有z用处的。
实验demo1
#include <stdio.h>
int main()
{
int *p=malloc(0x30);
int *p1=malloc(0x30);
int *p2=malloc(0x30);
int *t=malloc(0x40);
int *t1=malloc(0x40);
int *t2=malloc(0x40);
sleep(2);
free(p);
free(t);
free(p1);
free(t1);
free(p2);
free(t2);
return 0;
}
经过调试后知道。
fastbin中freechunk的插入位置在红箭头标志处,即在该链表的头部,应该可以类比为头插法。
在新的malloc时,如果chunk大小在与某一fastbin链表匹配,则把该链表的第一个即最近新释放的chunk释放给新的malloc
这样如果伪造一个chunk的话,也很简单啊就拿下面的图中链表结构来说。
上面链表原来是这样heap->0x602080 —▸ 0x602040 —▸ 0x602000
如果在地质上伪造一个chunk的话,只需要这样做就可以了,如我在0xffddff80处伪造一个chunk
并且我向插在下图黄标处,
那只需这样,1,创建一个假的chunk(结点),chunk的fd内容为0x602040,就想单链表插入一个结点一样。
然后让0x602080chunk(结点)的fd为0xffddff80即指向假的chunk(插入的结点),如下
这就是单链表插入结点的原理,只不过还要注意size位和标志位和其他一些东西,但都很简单,
如果是shortbin或者largebin伪造一个假的chunk,那么把单链表插入结点换成双链表插入结点的方式就好了。
到这里,突然就觉的堆溢出没那么难了。
无论fastbin攻击,doublefree,UAF,还是ONE-BY-ONE,无非就是利用了chunk的FD指针任意指向漏洞,然后在目的地址处配合一些数据达到攻击。知其然要知其所以然。堆的主要维护就是创建和free。如何创建以及如何free就决定着堆攻击的方法。free后由bins维护,但是bins是链表数组,数组的每一个数据位都是一个链表的head结点这样理解。这样在对chunk的malloc和free时,就有了攻击的机会。
无论难不难,还是要继续学习,虚心请教,2019/12/8
上面仅仅是一个小面,需要配合malloc机制的好多。
这里,malloc源码选择性查看:malloc源码点这里
后续。。。。。