bin地址
0x00问题所在
- free后的堆指针没用置空
- free没有对flag进行判断是否已经free过了
0x01unlink
发生在free一个chunk,发现相邻的chunk处于free状态,从bin双链表取出来的时候,合并至少两个free chunk。前一个chunk的状态通过
p->presize
的最低位来判断,后一个chunk的状态通过(p+p->size+(p+size)->size)->presize
的最低位来判断。unlink的检查:
p->fd->bk == p && p->bk->fd == p
绕过:寻找
*ptr == p
((p+p->size)->presize)&0x1 == 0 && ((p+p->size)->preseize) == p->size
绕过:覆盖nextchunk的presize
unlink
1
2
3
4
5
6
7
8
9
10
11//定义:
FD = p->fd;
BK = p->bk;
FD->bk = BK;
BK->fd = FD;
//方法:
p->fd = ptr-0x8*3;
p->bk = ptr-0x8*2;
//效果:
*ptr = p->fd;
//*ptr = ptr-0x8*3
0x02分析
堆指针依次保存在
0x6020e0
中,记为list
1
2
3unsigned long int list;
list[i*2] = chunkp;
list[i*2+1] = flag;
利用
unlink
篡改堆指针,因为构造一次unlink
只能修改ptr
处的值,而且ptr
必需保存unlink
对象堆的指针,所以尽量把他修改为保存堆指针list
中的某处地址,然后伪造list中的数据,再利用edit,修改list中伪造地址的数据构造
unlink
的fd, bk
,要使ptr-0x8*3
落在list
地址的范围,同时ptr
还要保存unlink
对象堆地址,也就是list[i*2],取ptr == list+0x18+0x8 == list[4]
,即unlink(chunk2)
,配合unlink
还需要一个相邻的堆,所以考虑先获得两个堆的指针。
0x03利用
首先申请两个0x100的堆再释放,目的是保存两个堆的指针,接着申请0x100*2+0x10(chunk header size)的堆,这个堆应该填充在先前释放的两个堆的位置。
然后free后面一个实际上不存在,但是有个残留指针的堆,触发前一个堆的
unlink
, 导致*ptr == list[4]
修改为ptr-0x8*3 == list+0x18+0x8-0x8*3 == list[1]
即chunk1的flag处。利用edit(chunk2)修改
list
的数据,从chunk1的flag处开始,修改list[2] = free@got; list[4] = read@got
利用edit(chunk1)修改
free
函数地址为puts
函数地址,然后free(chunk2)就会打印read
函数的地址利用动态链接库计算
system
函数的地址,并用edit(chunk1)修改free(puts)
函数地址为puts
函数地址任意申请一个堆存入
/bin/sh\x00
,调用free即触发system
0x04code
1 | # use to save two pointers in list, not fastbin |