本题主要考察对堆的利用,需要有一定的背景知识,本文也参考了几篇大佬的Writeup,让本文尽可能详细。
题目分析
checksec:
本题的RELRO是完全开启的,意味着我们不能通过修改GOT表来进行攻击
以下是源代码:
main函数
delete函数:
这里可以看到free之后没有把指针置空,可能有UAF或者Dubble Free
edit函数:
在本函数中,没有检测大小就直接写入,明显的堆溢出漏洞
总的来说,本题的漏洞比较明显,不过对于漏洞的利用还是有点复杂
基础知识
chunk结构
本题是64位程序,按64位说明,32位自行转化一下即可。
allocated chunk:指针指向数据部分,chunk大小为分配空间大小加上0x10(pre_size和size都是8bytes)
free chunk:指针指向fd(如果未置空,因此能够修改chunk的结构)
在size中,最后一位为0表示前一个chunk为free,为1表示allocated
__malloc_hook
前面已经说过,本题无法利用修改GOT表进行攻击,因此我们考虑修改__malloc_hook来执行shellcode。只要我们能把__malloc_hook的值修改为shellcode的地址即可实现。
那么, __malloc_hook在什么地方呢?
malloc机制中的unsorted bin、small bins以及large bins中的双向链表中的第一个chunk以及最后一个chunk中的 fd\bk 字段,都指向了一个结构(类型为malloc_state,变量名称为arena)的固定偏移的位置,在本题中,当我们free一个unsorted bin时,它的fd指针会指向libc中main_arena+0x58地址处。而在这个结构之上的固定偏移位置,则是 __malloc_hook 的地址(其值被默认设置为null)
漏洞利用
本题的漏洞利用思路为利用堆溢出修改chunk的结构,通过unlink修改buf数组中指向的位置,利用edit函数然后把shellcode写入bss段,然后再利用edit函数修改__malloc_hook为bss段地址来执行shellcode,详细过程如下
- 调用add函数在堆上创建两个chunk,此时堆结构如下:
. - 使用edit函数修改chunk0的数据区,在其中伪造一个chunk,并通过堆溢出修改chunk 1的pre_size,此时堆机构如下:
这样,当我们delete buf[1]时,由于我们伪造了一个chunk,并且的状态为free,就会把chunk1和伪造的chunk合并,合并会执行unlink操作,具体过程如下:
伪造chunk->fd->bk == 伪造chunk->bk;
伪造chunk->bk->fd == 伪造chunk->fd;
unlink函数
>void unlink(malloc_chunk *P, malloc_chunk *BK, malloc_chunk *FD)
{
FD = P->fd;
BK = P->bk;
if (__builtin_expect (FD->bk != P || BK->fd != P, 0))
malloc_printerr(check_action,"corrupted double-linked list",P);
else
{
FD