Linux下堆溢出利用 2-House of force基本原理
1 前言
House of Force 是一种堆利用方法,可以实现内存地址的读写,个人认为难理解的点有两个:
- 如何通过溢出已经分配的chunk,准确覆盖top chunk中的size字段;
- 要将top chunk的偏移到我们想要的目标地址(本文中是全局变量bss_var),该如何计算新申请chunk的偏移量大小。
2 基础知识
2.1 Top Chunk的分割机制
在堆内存管理中top chunk是作为后备堆空间,在各bin中没有chunk可提供时,分割出一个chunk提供给用户。那么这个分割过程是怎样的呢?我们来参照一份源码:
victim = av->top;
size = chunksize(victim);
if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE))
{
remainder_size = size - nb;
remainder = chunk_at_offset(victim, nb);
av->top = remainder;
set_head(victim, nb | PREV_INUSE |
(av != &main_arena ? NON_MAIN_ARENA : 0));
set_head(remainder, remainder_size | PREV_INUSE);
check_malloced_chunk(av, victim, nb);
void *p = chunk2mem(victim);
alloc_perturb(p, bytes);
return p;
}
- 首先是libc会检查用户申请的大小,top chunk是否能给的起;
- 如果给得起,就由top chunk的head处,以用户申请大小所匹配的chunk大小为偏移量,将top chunk的位置推到新的位置,而原来的top chunk head处就作为新的堆块被分配给用户了;
- 如果我们能控制top chunk在这个过程中偏移到任意位置,也就是说,如果我们能控制用户申请的大小为任意值,我们就能将top chunk劫持到任意内存地址,然后就可以控制目标内存。
2.2 溢出top chunk的方法
当我们malloc一个空间的时候,在申请到的这个chunk的后面就是top chunk,然而当我们输入的数据大小超过我们申请的范围,就会溢出到top chunk的位置。我们直接让top chunk 的size字段非常大就可以通过检查了,通常我们会传入-1,因为ptmalloc的源码中对于size使用unsigned long进行强转抓换,负数用补码表示,将-1当成无符号数为0xffffffffffffffff,已经非常大了,用于绕过if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE)) 验证。
2.3 利用条件
- 需要有办法能够更改到top chunk大小;
- 需要能够知道当前位置和要写位置的差值;
- 需要能够自由控制将要分配的chunk的大小,也就是malloc的参数值。
3 程序和调试环境准备
3.1 实验环境
- Linux ubuntu 16.04.1
- gdb 7.11.1
- pwndbg 1.1.0
3.2实验目标
我们提前定义了全局字符串变量bss_var,通过house of force 修改内存空间,改写其内容。
在实际应用场景中,可以用同理技术劫持malloc_hook、got等表指针,实现堆溢出攻击。
3.3演示程序
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
char bss_var[] = "This is a string that we want to overwrite.";
int main(int argc , char* argv[])
{
fprintf(stderr, "\nbss_var为全局变量,指向数据段内存地址为:[%p],通过House of force修改内存,改写其内容.\n", bss_var);
intptr_t *chunk1 = malloc(0x100);
fprintf(stderr, "\nchunk1的mem位置为:[%p];chunk1头的位置为:[%p].\n",chunk1,chunk1 - 2);
intptr_t chunk1_size = *(chunk1-1);
chunk1_size &= 0xffffff0;
fprintf(stderr, "已分配的chunk大小:[0x%x].",chunk1_size);
intptr_t *ptr_top = (intptr_t *) ((char *)chunk1 + chunk1_size-2*sizeof(long));
*(intptr_t *)((char *)ptr_top + sizeof(long)) = -1;
unsigned long evil_size = (unsigned long)bss_var - sizeof(long)*4 - (unsigned long)ptr_top;
void *new_ptr = malloc(evil_size);
void* ctr_chunk = malloc(100);
strcpy(ctr_chunk, "'Hacked!!'");
fprintf(stderr, "\nbss_var已经被改写成新字符串:[%s].\n", bss_var);
}
3.4编译命令
sudo gcc -o hof hof.c -g
需要安装插件 pwndbg进行程序调试
4 程序调试
在程序开始下断点,运行
b main
r
去0x601060看一下,这里存放着字符串"This is a string that we want to overwrite."
p 14
r
此时chunk1已经申请完毕,地址为0x602010。
输入:x/20xg 0x602000,看一下chunk1的结构
p 17
r
*(p1-1)是取出本chunk的size字段,看一下现在值是0x111
因为64位机器是16字节对齐,后四位是标志位,我们用chunksize &= 0xffffff0进行后四位清零。
intptr_t *ptr_top = (intptr_t *) ((char *)chunk1 + chunk1_size-2*sizeof(long));
这行代码是要计算top chunk的头节点地址,具体见下图:
*(intptr_t *)((char *)ptr_top + sizeof(long)) = -1;
将top chunk的size字段赋值为-1,赋值前后的对比。
计算偏移地址方法1:
- 继续执行,下一步需要申请一个new chunk,使top chunk偏移到我们的目的地址bss_var;
- 严格来说应该写成:evil_size = bss_var-ptr_top-2sizeof(long)-2sizeof(long),第一个2*sizeof(long)是申请的大chunk的头系统会自动添加,所以需要减去;
- 要写目的地址,需要再申请一个chunk,使其mem正好是目的地址(下文中的 void* ctr_chunk = malloc(100);),故这个chunk的头也需要预留出来,所以才减去第二个2*sizeof(long)。
计算偏移地址方法2:
要申请一个evil_size大小的堆,使top chunk的mem部分扩展到0x601060(bss_var地址)处,即chunk地址要偏移到bss_adr-0x10处,则:
ptr_top+0x10+evil_size=bss_adr-0x10
0x602030+0x10+evil_size=0x601060-0x10 = 0x601050
evil_size=0x601060-0x602030-0x20
p 24
r
这时top chunk 的位置为0x601050。
对ctr_chunk写入数据,全局变量bss_var被成功改写,over!
5 总结
通过以下6步实现了对全局变量bss_var的改写,
- 先申请一个chunk1;
- 根据堆的内存分配机制定位到top chunk的位置ptr_top;
- 改写top chunk的size字段为-1,从而绕过验证 if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE)) 检查;
- 根据目的地址(bss_var)和top chunk的地址计算偏移evil_size,注意要预留出两个chunk头的空间;
- 申请evil_size大小的内存空间,此时top chunk的位置已经到了: 目的地-0x10;
- 再次malloc内存空间,其mem地址正好为目的地址,可以进行任意读写。
在实际应用中可用同理技术劫持malloc_hook、got等表指针,实现get shell。
6 参考链接
- https://blog.youkuaiyun.com/aaa15893831716/article/details/102408213
- https://blog.youkuaiyun.com/qq_35519254/article/details/76986169
- https://bbs.pediy.com/thread-222924.htm