堆漏洞利用
堆漏洞利用
一. 介绍
堆溢出是一种特定的缓冲区溢出(还有栈溢出, bss 段溢出等)。但是其与栈溢出所不同的是,堆上并不存在返回地址等可以让攻击者直接控制执行流程的数据,因此我们一般无法直接通过堆溢出来控制 EIP 。
二. 利用策略
-
覆盖与其物理相邻的下一个 chunk 的内容。
-
prev_size
-
size,主要有三个比特位,以及该堆块真正的大小。
- NON_MAIN_ARENA
- IS_MAPPED
- PREV_INUSE
- the True chunk size
-
chunk content,从而改变程序固有的执行流。
-
-
利用堆中的机制(如 unlink 等 )来实现任意地址写入( Write-Anything-Anywhere)或控制堆块中的内容等效果,从而来控制程序的执行流。
三. 相关函数
通常来说堆是通过调用 glibc 函数 malloc 进行分配的,在某些情况下会使用 calloc 分配。calloc 与 malloc 的区别是 calloc 在分配后会自动进行清空,这对于某些信息泄露漏洞的利用来说是致命的。
calloc(0x20);
//等同于
ptr=malloc(0x20);
memset(ptr,0,0x20);
除此之外,还有一种分配是经由 realloc 进行的,realloc 函数可以身兼 malloc 和 free 两个函数的功能。
#include <stdio.h>
int main(void)
{
char *chunk,*chunk1;
chunk=malloc(16);
chunk1=realloc(chunk,32);
return 0;
}
realloc 的操作并不是像字面意义上那么简单,其内部会根据不同的情况进行不同操作
-
当 realloc(ptr,size) 的 size 不等于 ptr 的 size 时
-
如果申请 size > 原来 size
- 如果 chunk 与 top chunk 相邻,直接扩展这个 chunk 到新 size 大小
- 如果 chunk 与 top chunk 不相邻,相当于 free(ptr),malloc(new_size)
-
如果申请 size < 原来 size
- 如果相差不足以容得下一个最小 chunk(64 位下 32 个字节,32 位下 16 个字节),则保持不变
- 如果相差可以容得下一个最小 chunk,则切割原 chunk 为两部分,free 掉后一部分
-
-
当 realloc(ptr,size) 的 size 等于 0 时,相当于 free(ptr)
-
当 realloc(ptr,size) 的 size 等于 ptr 的 size,不进行任何操作
四. 注意点
- 计算我们开始写入的地址与我们所要覆盖的地址之间的距离。 一个常见的误区是 malloc 的参数等于实际分配堆块的大小,但是事实上 ptmalloc 分配出来的大小是对齐的。这个长度一般是字长的 2 倍,比如 32 位系统是 8 个字节,64 位系统是 16 个字节。但是对于不大于 2 倍字长的请求,malloc 会直接返回 2 倍字长的块也就是最小 chunk,比如 64 位系统执行
malloc(0)
会返回用户区域为 16 字节的块。实际上 ptmalloc 分配内存是以双字为基本单位,以 64 位系统为例,分配出来的空间是 16 的整数倍,即用户申请的 chunk 都是 16 字节对齐的。 - 注意用户区域的大小不等于 chunk_head.size,chunk_head.size = 用户区域大小 + 2 * 字长
- 用户申请的内存大小会被修改,其有可能会使用与其物理相邻的下一个 chunk 的 prev_size 字段储存内容。chunk 的 pre_size 仅当它的前一块处于释放状态时才起作用。所以用户这时候其实还可以使用下一个 chunk 的 prev_size 字段