chunk extend的利用手法是基于plmalloc对于堆块的各种宏定义 其是通过计算chunk首地址和size大小来推断出上一个chunk或者是下一个chunk的地址
/* Ptr to next physical malloc_chunk. */ |
获取下一个chunk的地址既是通过当前chunk地址加上当前chunk大小
/* Size of the chunk below P. Only valid if prev_inuse (P). */ |
获取上一个chunk的地址则是通过当前chunk的地址减去前一个chunk的大小
也就是说 只要我们修改了chunk的size域和prev_size域 就可以使plmalloc误判chunk
堆溢出覆盖下一个chunk的size域
这个手法主要有两种适用的题型 一种是有伴随堆块的情况下 并且没有堆溢出 通过这种手法可以修改伴随堆块的内容
第二种是libc2.27的情况下 tcachebin的存在会使得我们打unsortedbin造成很大的影响 要么就是填满链表要么就是申请一个超过tcachebin大小的chunk并释放 有的题目会对这两种解决办法进行限制 这个时候就可以利用这种办法来合并chunk 从而获得一个超过tcachebin范围的堆块
下面来分别演示一下
环境:ubuntu22 (二进制文件依赖的libc2.27) 目测2.23以上的版本都可以
add(0x20,b'aaaa') |
首先申请三个堆块 chunk1用来堆溢出 覆盖chunk2的size域 chunk3用来和chunk2合并
唯一要注意的是覆盖size域的值 需要包括两个堆块的prev_size域和size域
所以此时用来覆盖chunk2的size域的数值应为0x51
add(0x20,b'aaaa') |
此时chunk2就和chunk3合并了
此时chunk2的指针指向的仍然是chunk2的首地址 但是plmalloc已经误判了chunk2 原本其是一个0x31大小的chunk 此时plmalloc误判其还包含了chunk3 所以释放chunk2就会一并释放chunk3
可以看到一并放入了tcache 这里之所以没有和top chunk合并 是因为tcache中的chunk Inuse位仍然为1
此时我们申请一个0x40大小的chunk 就可以获得原本chunk3的空间 从而对chunk3的内容进行任意修改
此外还有一种情况 如果chunk2先被释放进入tcachebin后再更改size域会发生什么呢
add(0x20,b'aaaa') |
此时注意 chunk2不能位于fastbin或者是tcachebin中 如果位于二者中 下一个chunk的Inuse位就不会为0 这样就不会合并
gdb动调看一下是否合并成功
环境: ubuntu16 二进制依赖libc2.23
这类的利用手法被称为overpadding
你可以理解为反方向的合并 刚才是由chunk2吞并chunk3 修改的是chunk2的size域 现在我们来修改chunk3的prev_size域和size域 从而使得chunk2合并chunk3
这里的知识点其实和unlink有点相似 unlink也是通过构造fake chunk 伪造好next chunk的prev_size和size
add(0x80,b'aaaa') #0 |
首先申请四个chunk 前三个用来负责合并 第四个用来保证不和top chunk合并
我们以chunk1来为堆溢出的起点 覆盖chunk2的prev_size和size域 不过在此之前还需要先释放chunk0到unsortedbin中(只要不是fastbin和tcachebin就可以) 这样才能使得后面的合并生效
add(0x80,b'aaaa') |
注意一下chunk2的size域 Inuse位一定要为0 否则不会合并
此时我们释放chunk2 来看看是否合并成功
这种一般是伴随堆块先申请的情况可以利用 从而获取到低地址处堆块任意写的机会