攻防世界PWN之Supermarket题解

首先 , 看一下程序的保护机制 。看起来还不错
然后 , 我们用IDA分析一下
分析出程序大概有这样的一个结构体
{[16];;;char*;}Node;
用来输入的函数

攻防世界PWN之Supermarket题解

文章插图
最多只能输入n-1个字符 , 因此 , 也不能溢出
删除功能 , 也对Node指针设置了NULL
一切的检查的比较充分 , 然而 , 这里出现的漏洞
【攻防世界PWN之Supermarket题解】让我们先看看的知识
根据百度百科
原型是 void *(void *,int );
先判断当前的指针是否有足够的连续空间 , 如果有 , 扩大指向的地址 , 并且将返回 , 如果空间不够 , 先按照指定的大小分配空间 , 将原有数据从头到尾拷贝到新分配的内存区域 , 而后释放原来所指内存区域(注意:原来指针是自动释放 , 不需要使用free) , 同时返回新分配的内存区域的首地址 。即重新分配存储器块的地址 。
本程序中 , 后 , 并没有把返回值重新赋值给node0-> , 因此 , 当的大于原来的size时 , 原来区域的空间会被free掉 , 由于没有把返回地址赋给node0-> , 因此存在UAF漏洞 。
并且 , 由于创建node时 , 是先 node结构体 , 然后再 的空间 , 所以 , 当我们再次申请创建一个node时 , 如果满足条件 , node结构体就会申请到node0-> , 然后 , 我们编辑node0的就是编辑node1的结构体 , 我们把node1的指向atoi的got表 , 我们就可以实现泄露atoi的地址以及修改atoi的GOT表 。
注意 , 我们的node0的的大小必须为 bin , 因为 , 这样我们才能让node2的结构体申请到node0->处 , 因为结构体空间大小为0x1C , 刚好满足小于node0->地址处空间的大小 , 可以从中切割区域 。如果要使用的话 , 是不可行的 , 因为是当要申请的空间大小和空闲的空间大小一模一样时 , 才能分配到那个空闲的块处 , 假如我们设置的大小为0x1C , 但是本题的用来获取输入的函数最多只能输入n-1个字符 , 最后一个字符会强制设置为0 , 而我们要把atoi的got表地址覆盖到node2-> , 由于该字段位于结构体最后 , 因此 , 我们将会覆盖不完整 。所以 , 我们使用 bin 。(请仔细思考一下)
当我们成功修改了node2的结构体时 , 我们就成功了八成了 。只要我们把node2->指向atoi的got表 , 那么我们编辑node2的时就是在编辑atoi的got表
综上 , 我们最终的exp脚本如下
#:*rt*#sh=(' 。/')sh=('111 。198 。29 。45',55879)elf=ELF(' 。/')=elf 。got['atoi'](index,size,):sh 。('>>','1')sh 。('name:',str(index))sh 。('price:','10')sh 。(':',str(size))sh 。(':',)(index):sh 。('>>','2')sh 。
('name:',str(index))():sh 。('>>','3')(index,size,):sh 。('>>','5')sh 。('name:',str(index))sh 。(':',str(size))sh 。(':',)#(0,0x80,'a'*0x10)#node1 , 只用来做分隔作用 , 防止块合并(1,0x20,'b'*0x10)#->#注意不要加任何数据 , 因为我们发送的数据写入到的是一个被free的块(仔细思考一下这句话) , 这会导致后面时出错edit(0,0x90,'')#现在node2将被分配到node0的原处(2,0x20,'d'*0x10)='2' 。