How to exploit a heap Overflow

究竟什么是堆?malloc()的作用是什么?
  你可能在编程的时候,经常需要使用到很多内存,这是你可能会使用到堆。使用malloc分配内存使用后,你需要把这些内存段释放掉,但是你可能并不知道程序是怎么获得内存空间或者释放掉内存的。
  在讨论malloc之前,让我们先来了解一下进程获得内存空间的方式。
  主要是通过mmap和brk两种方式,这些都是系统调用,这意味着我们直接请求了内核。mmap请求内核给我们一些新的虚拟地址空间,基本上请求的是一个新的内存段。除了mmap之外,还有brk,可以用来改变已使用内存段的大小。
  进程不关心这些内存是怎样实现的,如果进程有自己的内存段,那么将在什么地方存储它们?或者你没有足够的内存空间时,你将会看到一个SWAP文件。进程都不会在意这些东西的实现方式。而是通过内核和硬件进行处理,并且将该内存映射到进程中。进程不需要知道内核和硬件的处理过程,像空气一样,看不见摸不着。

使用strace ./heap1查看程序的系统调用情况,你将会看到进程是如何调用mmap去初始化内存区域的。
在这里插入图片描述
在最后,进程使用brk来设置堆空间。
  思考,我们为什么不直接使用"mmap"或"brk"为我们的进程获得更多的内存而还要使用malloc呢?为什么我们谈论堆的时候,会谈到malloc和free呢?
  malloc只是一个函数封装,用来隐藏brk或mmap的操作,让代码看起来更简洁并且使用更方便一点。如果堆不存在或太小,malloc将调用mmap或brk获得更多内存。但最重要的是它将帮助我们组织和管理内存。在我们看到的例子上,都是用很少的堆空间,并且我们不会看到任何额外的内存映射区域。
  
  为了简起见,我们把堆看作一大块固定的内存。并且在这段内存中我们可以为所欲为。所以当我们提到堆的时候,我们实际上指的是这块内存区域。

我们通过protostar中的heap1来探索一下堆,内存分配的情况。
heap1.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

struct internet{
	int priority;
	char *name;
};

void winner(){
	printf("and we have a winner @ %d\n", time(NULL));
}
int main(int argc, char **argv){
	struct internet *i1, *i2, *i3;
	 i1 = malloc(sizeof(struct internet));
	 i1->priority = 2;
	 i1->name = malloc(8);

	i2 = malloc(sizeof(struct internet));
	i2->proiority = 1;
	i2->name = malloc(8);

	strcpy(i1->name, argv[1]);
	strcpy(i2->name, argv[2]);

	printf("and that's a wrap folks!\n"); 
}

通过这个例子来看看malloc在实际环境中是如何运作的,先来看一些上面这段代码,目标函数似乎是winner(),我们需要重定向代码执行到这个函数。在最上面有一个结构体叫internet,里面有个int类型的成员变量叫priority,而第二个成员变量是一个char类型的而指针叫name, 这意味着name是一个指向某个位置的字符串指针。结构体就像类一样,至少提供一个结构和不同的成员属性。main()中定义了3个internet结构体类型的指针变量,但只有两个被使用,i1、i2.
  这里需要强调的是"internet"指针,因为这3个"internet"对象没有存储在堆栈上。只有地址,存储在i1,i2,i3几个指针中。总之,它将开始在堆上为这些对象分配内存空间。首先调用了malloc给i1分配足够的内存空间。sizeof()将返回该结构所需要的字节数。在这里这个字节数是8,因为int型所占的内存大小是4个字节,并且char指针是一个地址,同样是4字节,因为我们是在32位的机器上。我们知道malloc返回堆上的地址,我们现在可以使用它。i1指向内存中8字节的开始处。现在我们要将priority设置为1,这将把1写入到我们分配的第一个4字节空间。然后分配另外的8字节的内存空间,然后将这个内存空间的地址存储到名为name的char指针中。char指针的位置是在i1对象的偏移地址+4的位置。接下来的i2和前边一样。
  接下来是两个strcpy(),这里看起来有些问题,这里没有看到所要拷贝的字符串长度标识,我们写入的数据可能会超过已经拥有的空间的大小(溢出)。

堆溢出测试利用的简单步骤:

  • 利用GDB在malloc和strcpy调用的地方进行断点设置
  • 使用define hook-stop配置断点处要执行的动作,(这里显示堆空间的实际存储情况)
  • run “/bin/echo -ne "AAAABBBBCCCCDDDDEEEEFFFFF"” 00001111222233334444
  • 尝试运行测试堆空间存储情况
  • 寻找溢出点并寻求可能的利用途径,大概就是这样,描述比较俗
    在这里插入图片描述  可以看到一个意料中错误,第二个参数作为第一个参数最后指定地址的位置的输入,然后用puts全局偏移表的地址替换"FFFF",
    在这里插入图片描述
    这是一个段错误,0x30303030刚好是ascii的0000,当我们使用infor register时开一看到EIP地址指向了0x30303030,这意味着可以将代码重定向到我们想要的地方,这里,我们想要调用winner
    在这里插入图片描述
    and we have a winner @…
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值