0x00 前言
这篇文章是看过安全客上的一篇文章后自己做了一些总结,在此分享,下面贴出原文链接 how2heap总结上。
不过在学习这些利用知识之前还是先推荐看一下华庭写的Glibc内存管理-Ptmalloc2源码分析。
0x01 测试环境
Ubuntu 16.04.3 LTS x64
GLIBC 2.23
0x02 目录
firtst_fit
fastbin_dup
fsatbin_dup_into_stack
unsafe_unlink
0x03 first_fit
源码:
1 |
|
输出:
个人总结
如果有一个空闲的且足够大的chunk,malloc会优先分配这个chunk。use-after-free
就是这种机制的一个利用场景。
0x04 fastbin_dup
源码:
1 |
|
输出:
个人总结:
这个程序展示了double-free
的攻击。我们发先连续free两次a,程序就会报错,因为这个时候这块内存刚好在对应free-list的顶部,再次free这块内存的时候就会被检查到。但是free掉a后再free b然后再free a程序就不会报错。因为这个时候a并不在链表顶部。
三次free后链表结构如下
其实应该是个循环结构
0x05 fastbin_dup_into_stack
源码:
1 |
|
输出:
个人总结
首先malloc了三次
1 | int *a = malloc(8); |
紧接着free a
-> free b
-> free a
随后d = malloc(8)
,这时返回给d的地址与a相同
继续malloc(8)
,这时链表结构中只剩下了a,此时a仍在fastbin里是空闲的,但是我们现在已经可以随意修改a的fd指针等其它结构了。
*d = (unsigned long long) (((char*)&stack_var) - sizeof(d));
这条语句修改了a中的fd指针使其指向stack中的位置,伪造了一个chunk
再次连续malloc两次我们就可以成功返回栈地址了
0x06 unsafe_unlink
源码:
1 |
|
输出:
个人总结:
这个攻击方式的条件是要有在bss段上可以覆盖到的全局指针变量
1 | chunk0_ptr = (uint64_t*) malloc(malloc_size); //chunk0 |
首先malloc两次,取得两块chunk
1 | chunk0_ptr[2] = (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*3); |
然后开始在chunk0中伪造一个chunk P,为了unlink时绕过P->fd-bk == P && P->bk->fd == P
的检测,设置了fd和bk指针。
1 | chunk1_hdr[0] = malloc_size; |
fake chunk的size字段和下一个堆块的presize字段(fd->presize)的值是一样的.
经过了这个设置,就可以过掉“(chunksize(P) != prev_size (next_chunk(P)) == False”的校验了.
因此,我们设置fake chunk的size字段为chunk0_[-3]:0x00000000
1 | chunk1_hdr[1] &= ~1 |
把chunk1设置为空闲状态,然后free掉chunk1,因为这时chunk0也是处于free状态,且这两个chunk相邻,所以就会unlink我们的fake chunk,然后修改chunk_ptr.
然后我们就可以利用chunk_ptr,自己改自己的值然后实现任意地址写。