堆溢出(2.23)
堆溢出
原理
1.溢出原理:add两个堆块(大小要符合fastbin大小,小于0x80),free掉后面的堆块使其进入fastbin中,然后填满前面的堆块之后就能溢出到后面的堆块,再把fastbin中被修改的堆块申请出来,该堆块就被我们修改成了指定的内容。有一些要注意的点:(1)一个堆块的大小要加上前面0x10的pre size和size字段,同时会向下取整,比如我们malloc一个0x68大小的堆块,要先加上前面0x10的字段,0x78向下取整也就是实际上申请了0x70大小的堆块。(2)在修改一个堆块时,我们是从fd指针开始写的,也就是说我们控制不了当前堆块的pre size和size字段,但是当我们溢出到下一个堆块的时候(注意下一个堆块一定要是fastbin中的才可以达到修改的目的),我们是从pre size字段开始写的,所以当我们伪造堆块的时候,可以用gdb先观察一下溢出之前后面堆块的pre size值和size值,溢出的前0x10字节一模一样的抄上去,然后再来修改fd指针的内容。
2.getshell原理:使用了钩子函数(malloc_hook函数 或 free_hook函数),别的师傅说在2.23版本貌似只有malloc_hook-0x23可以满足fastbin的大小,有一个规则是我们修改的地址的大小要在fastbin大小范围内,我们用0x68申请堆块,那么fastbin的大小就是0x70,那我们修改的地址大小就需要在0x70~0x7f之间,而malloc_hook-0x23恰好是0x7f。malloc_hook函数的作用是,如果我们什么都不做,正常运行malloc,但如果把malloc_hook设置成别的地址,那么每次调用malloc,就会跳去该地址执行,那我们就可以把这个地址改为后门函数,system或者one_gadget即可拿到shell。
例题
一个经典的增删改查的菜单,我们先把交互菜单写出来
之后我们首先要拿到libc基地址,那么如何泄露libc地址呢,当我们free一个堆块而这个堆块比fastbin也就是0x80大的时候,它会首先进入到unsorted bin中,这时候我们再申请一个小于0x80的堆块,就会从unsorted bin中切割,而这个从unsorted bin切割出来的堆块的fd指针处就会残留libc地址,我们算出残留libc地址-当前进程中libc基地址的偏移,接收这个libc地址-算出来的偏移就得到了libc基地址,然后就可以得到malloc_hook和one_gadget的地址了。需要注意的是,我们申请了两个0x90的堆块,然后free掉了0号堆块,那1号堆块的作用是什么,是隔离0号堆块和top chunk,如果没有1号堆块,我们释放掉0号堆块进入到unsorted bin后就会和top chunk合并,那unsorted bin中就没有可分割的堆块了。
得到libc基地址后,我们开始堆溢出,再申请两个堆块3和4,大小位0x68,释放后会存在fastbin中,我们free掉4号堆块,就可以修改3号堆块的内容来溢出到4号堆块了,在这之前我们先要用gdb看一下4号堆块的pre size和size字段,我们不能改变这0x10大小的值,在delete(4)后设断点gdb.attach(r),然后输入bins发现fastbin中的4号堆块,查看该堆块的内存
发现前0x8都是0,后0x8的第一个字节是’\x71’,后面7个也是0,我们修改3号堆块的值,把它fd开始后面的0x60填满,再把4号堆块的前0x10一模一样的搬进去,最后在4号堆块的fd指针处填入malloc_hook-0x23的值
把gdb.attach(r)放在修改3号堆块之后,发现fd指针已经修改成了0x00007f4f9ce71aed,即malloc_hook-0x23的地址,那么这个地址就是伪造的下一个堆块的地址
我们发现它的大小是0x7f,是满足0x70~0x7f这个范围的
此时的fastbin的0x70处,应该为0xea71b0 —▸ 0x7f4f9ce71aed,由于fastbin中后进先出的规则,我们再来申请两次0x68大小的堆块
完整exp:










