堆溢出

原理

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。

例题

image-20250722140854874

一个经典的增删改查的菜单,我们先把交互菜单写出来

image-20250722141107080

之后我们首先要拿到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中就没有可分割的堆块了。

image-20250722141648401

得到libc基地址后,我们开始堆溢出,再申请两个堆块3和4,大小位0x68,释放后会存在fastbin中,我们free掉4号堆块,就可以修改3号堆块的内容来溢出到4号堆块了,在这之前我们先要用gdb看一下4号堆块的pre size和size字段,我们不能改变这0x10大小的值,在delete(4)后设断点gdb.attach(r),然后输入bins发现fastbin中的4号堆块,查看该堆块的内存

image-20250722142534073

image-20250722142643161

发现前0x8都是0,后0x8的第一个字节是’\x71’,后面7个也是0,我们修改3号堆块的值,把它fd开始后面的0x60填满,再把4号堆块的前0x10一模一样的搬进去,最后在4号堆块的fd指针处填入malloc_hook-0x23的值

image-20250722143010338

把gdb.attach(r)放在修改3号堆块之后,发现fd指针已经修改成了0x00007f4f9ce71aed,即malloc_hook-0x23的地址,那么这个地址就是伪造的下一个堆块的地址

image-20250722143257609

我们发现它的大小是0x7f,是满足0x70~0x7f这个范围的

image-20250722143610184

此时的fastbin的0x70处,应该为0xea71b0 —▸ 0x7f4f9ce71aed,由于fastbin中后进先出的规则,我们再来申请两次0x68大小的堆块image-20250722144032857第一次5号堆块是把0xea71b0也就是之前free掉的4号堆块申请出来,第二次6号堆块申请出来的就是我们伪造的堆块0x7f4f9ce71aed了,这个堆块存放了malloc_hook的地址,现在我们来定位一下,由刚才3号的溢出覆写可得0x00007f4f9ce71aed处存放着malloc_hook-0x23,那么malloc_hook的地址就是0x00007f4f9ce71aed+0x23了,而由上一个查看内存的图中也可以看出,这个地址是伪造的堆块,它也是有前0x10的pre size和size字段的,我们修改6号堆块,从fd开始写,只需覆盖0x13个字节即可到达malloc_hook的地址,将其该为one_gadget的地址,再执行一次malloc即可调用one_gadget。

image-20250722144718092

完整exp:

image-20250722144835574