泄露堆块残留libc地址的特殊手法

我们之前泄露libc地址的手法是先让一个堆块进入到unsorted bin中,再切割一部分出来,那么新切割出来的这个堆块的fd指针上就残留了libc地址,我们调用show函数即可完成泄露。那如果我们遇到这样一种情况,当我们add时函数自动在添加的内容后面放置一个’\x00’,当我们泄露libc地址的时候,末尾三位的大小可以是任意值,所以我们之前只给内容填一个’\n’,只会影响末尾两位,那如果在后面放一个’\x00’,这个’\x00’会在末尾三位和四位的位置,打印数据的时候先到’\x00’,就会自动截断,打印不出后面的四个字节。或者还有一种情况,那就是add函数中用了calloc函数开辟空间,自动给堆空间填满’\x00’。在这些情况下,我们不能用之前的方法来泄露libc,下面通过一道题来讲解。

例题

一道buu上的题目,add函数里用的calloc,另外需要注意开辟空间的序号不是我们指定的,遍历数字,如果该数字不存在堆块,那么就将此数字作为该堆块的序号。比如我们add了三个堆块,现在三个堆块的序号是0,1,2,如果我delete(1)把1号堆块free掉,再申请一个新的堆块,那么这个堆块的序号不是3,而是1。

image-20250813162753786

我们先来开辟几个堆空间,0号堆块的作用是修改2号堆块,3号堆块的作用是修改4号堆块,5号堆块的作用是隔离top chunk,那么1号堆块就看起来有点多余,其实1号堆块的作用是调整堆块序号,到后面自然就清楚了。首先delete1号和2号堆块,让1号和2号堆块进入fastbin中

image-20250813162352872

接下来是最重要的一步,我们利用edit函数来打堆溢出,编辑0号堆块,将它填满后接着给1号堆块的pre size和size填上正确的大小值,再填满1号堆块,接着填2号堆块的pre size和size,我们这个堆溢出的作用是修改2号堆块的fd指针,所以1号堆块整体都保持不变,那么我们给2号堆块的fd指针填什么呢,我们要将4号堆块的地址挂载进2号堆块,如何操作,只需把4号堆块的大小写成p8(0x80)变成一个字节填入fd指针即可,原因是堆地址高位基本固定,低位1-2个字节不同,而0x80这个值与4号堆块的地址低字节一致。

我们这样做的目的是想伪造一个4号堆块再申请出来,这样我们就有了两个4号堆块,那之后的利用手法就显而易见了。完成了这一步修改,我们要想真正意义上free掉4号堆块,应该把4号堆块的大小改为和2号堆块一样的大小,于是我们利用3号堆块打堆溢出,修改4号堆块的size位为0x21。

之前fastbin中为 2->1,那么现在就是2->4

image-20250813163753663

现在我们add两个0x10大小的堆块,注意之前一开始说的建立序号的机制,第一个申请回来的堆块其实是之前的2号堆块,但它现在的序号是1,第二个申请回来的堆块是我们伪造的4号堆块,它现在的序号是2,这也就是一开始申请1号堆块的作用了,多提供一个序号供伪造的4号堆块,但其实也大可不必,顺着数字往后延也可以。那么现在,这个新的2号堆块和4号堆块的指针其实可以看作同一个堆块了,我们想要拿到libc地址,要先通过堆溢出把4号堆块的大小改回去,大于0x80,释放4号堆块,这时候4号堆块进入unsortd bin,那么2号堆块的fd指针上也就有了libc地址。之后就正常获取libc基地址了。

image-20250813164703041

之后的打法就是常规的堆溢出了,注意序号问题

image-20250813170905685