先来了解一点,在STL容器里面,如果在容器里的内容是一个指针,那么在将其删除的时候,就会调用其自身的析构函数,而指针的析构函数又什么都不会做。造成的结果就是指针指向的内容不会被释放。
以下全是俺胡乱分析的,没看过底层源码,没分析过内存管理(毕竟宁看题目源码能看出个屁)
👴怀疑,在new操作,然后push_back的时候,这玩意儿进行了两步实现这个功能。
第一步就是先⛏一个堆块,把你的data保存在里面
第二步才是所谓的push_back,俺以为的就是把这个copy过去,再delete了第一步产生的堆块
这也就解释了,为什么IDA里面进行new的时候,会出现调用析构函数的情况(大概)
好了,上面的不大重要。俺们来分析分析漏洞出现的原因。
De1的源码里调用的是erase函数,那俺们就来康康erase函数的源码
1 | iterator erase(iterator position) { |
分析前,先提提vector,能够对vector内的任意位置元素进行插入和删除操作。
vector的底层管理是这样的,先是存在一块内存,里面存储着vector当前的size大小 (begin和end两处指针) 以及最大的size大小,也是指针。跟进begin指针,里面就是vector储存的内容了。
而我们这题,vector的内容储存的是指针,这就出现一丢丢问题了。主要观察源码里面的destroy()这块地方,它是析构的最后一个元素,当我们进行free (0)的时候,虽然vector也还是会进行删除操作,将数据整体往前移,当然,这里也是本题漏洞点之一,不过先留到下面讲。我们也说了,虽然进行了删除操作,但是实际上底层对其进行的析构还是对于最后一个元素的,也就是第二个的指针,对其进行析构。所以才会出现free(0)
的情况,实际上被放入bin的是1。
上面是第一个原因,接下来是第二处。
vector容器对于删除某一处内存后,会进行copy操作,将该处内存到final的内容整体往前copy。因为是指针,所以第二个的指针就被copy到第一个,此时free(0)也就刚好是再次将其析构。这样就构成了我们所测试出的double free的结果。
1 | from pwn import * |