Large Bin基本结构
Large Bin的每个Bin中的chunk的大小都属于同一范围,Large Bin的每个chunk位于两个双向链表中。相比较其它chunk,Large Bin中的chunk多出了fd_nextsize
和bk_nextsize
两个字段,分别指向前一个/后一个与当前chunk大小相邻的不同大小的第一个空闲块(不包括bin头指针)。
Put Unsorted Bin into Large Bin
在malloc
时,如果Unsorted Bin中的victim的大小无法满足申请所需且属于Large Bin,将会被置入Large Bin中。
1 | victim_index = largebin_index(size); // 计算bin数组下标 |
从源码中可以看出,Large Bin在更新链表的时候,没有freed chunk中的链表数据的进行任何的安全检查,利用这一点,可以向指定地址写入堆地址数据。利用对齐的特性向堆上写入0x56开头的堆地址,则可以在特定位置制造一个空闲的0x56大小的chunk。当申请0x48大小的chunk时(并触发unsorted bin一系列操作后),特定位置的chunk将会被取出。
同时,利用这个漏洞,也可向特定位置写入特定数值。
0x55与0x56
64位下,PIE和randomize_va_space对地址的影响:
- 0表示关闭地址空间随机化
- 1表示对mmap的基地址、栈地址和vdso地址随机化
- 2表示在1的基础上对堆地址随机化
当程序开启PIE且系统支持地址随机化时,堆地址的非零最高位会在0x55和0x56之间随机。这两个数字对于calloc()
来说,只有0x56能够通过检查。
1 | assert (!mem || chunk_is_mmapped (mem2chunk (mem)) || |
0ctf2018 heapstorm2
明显的off-by-null
漏洞。
1 | input_string(chunk, size); |
利用off-by-null
来制造堆块重叠,从而修改已释放的chunk的链表指针数据。通过将Unsorted Bin中的Large Chunk放入Large Bin的操作,向特定地址写入0x56开头的堆地址,使得再次申请chunk时,获得特定地址的chunk,从而改写关键数据以进一步getshell。