2017-02-04 64 views
0

编辑:我原来的问题不再准确,所以我重写了它。为什么这个分配堆栈而不是堆?

因此,我正在编写一个程序来演示C语言中的堆喷(我知道这是不常见的)。我使用malloc分配一个巨大的缓冲区(100MB),但它分配到标记为映射的段而不是[堆],我找不到原因。

我的代码:

int NOPSize = 960; 
int ShellcodeSize = 64; 
int PayloadSize = NOPSize + ShellcodeSize; 
char Payload[PayloadSize]; 
char* HeapBuf = (char*)malloc(0x6400000); //104,857,600 (100MB) 

for (int x = 0; x < PayloadSize; x++) 
    Payload[x] = (x <= NOPSize) ? '\x90' : '\x41'; 

for (int x = 0; x < 0x6400000; x++) 
    HeapBuf[x] = Payload[x % PayloadSize]; 

printf("%x\n", HeapBuf); 
free(HeapBuf); 

使用GDB-PEDA的VMMap的输出从设定在该呼叫的断点视为free

0x80000000 0x80001000 r-xp /root/Documents/a.out 
0x80001000 0x80002000 r--p /root/Documents/a.out 
0x80002000 0x80003000 rw-p /root/Documents/a.out 
0x80003000 0x80024000 rw-p [heap] 
0xb19fd000 0xb7dfe000 rw-p mapped 
0xb7dfe000 0xb7faf000 r-xp /lib/i386-linux-gnu/libc-2.24.so 
0xb7faf000 0xb7fb1000 r--p /lib/i386-linux-gnu/libc-2.24.so 
0xb7fb1000 0xb7fb2000 rw-p /lib/i386-linux-gnu/libc-2.24.so 
0xb7fb2000 0xb7fb5000 rw-p mapped 
0xb7fd4000 0xb7fd7000 rw-p mapped 
0xb7fd7000 0xb7fd9000 r--p [vvar] 
0xb7fd9000 0xb7fdb000 r-xp [vdso] 
0xb7fdb000 0xb7ffd000 r-xp /lib/i386-linux-gnu/ld-2.24.so 
0xb7ffe000 0xb7fff000 r--p /lib/i386-linux-gnu/ld-2.24.so 
0xb7fff000 0xb8000000 rw-p /lib/i386-linux-gnu/ld-2.24.so 
0xbffdf000 0xc0000000 rw-p [stack] 

printf输出0xb19fd008这是在顶映射段。

有趣的是,如果我删除printf的呼叫,则[heap]段会消失。所以我的问题是,为什么[heap]段的存在取决于对printf的调用,为什么映射段中的打印地址而不是[heap]段?谢谢。

+0

在free(HeapBuf)之前,内存映射看起来像什么样? –

+0

这是免费的。它是在'free'执行之前从断点取得的。 – Cryptomancer

+0

您似乎正在以“root”身份运行桌面。不要这样做。 – zwol

回答

1

有两件事情怎么回事,之前我进入他们,我有基于字符串的存在提醒你/lib/i386-linux-gnu/libc-2.24.so在你的地图输出中,我推断你正在运行你的程序的操作系统使用Linux内核和GNU C库('glibc')。我要告诉你的一些内容对于这些组件非常特别。首先:出于历史原因,有两种不同的方式可以在操作系统上分配符合“Unix”标准的内存(第一顺序:任何人仍然使用,除Windows外):系统调用sbrkmmapsbrk更有限;它只能在预定位置管理单个存储器区域的大小,而mmap(及其对应的munmap)可以在地址空间中的任何地方分配和解除分配独立存储块。Linux的/proc/PID/maps文件使用[heap]标签作为由sbrk管理的内存区域。分配有mmap的独立内存块被标记为“映射”。

二:的glibc的实施malloc使用sbrk用于较小的分配和mmap为大的分配(见M_MMAP_THRESHOLDmallopt manpage的讨论)。 “小”和“大”之间的默认阈值是128 千字节;你分配了0x6400000字节= 100 兆字节,这显然要大得多。你映射的行转储读取

0xb19fd000 0xb7dfe000 rw-p mapped 

正好为一个页面比你的要求较大 - 这种差异是由于malloc考虑为自己的记账信息的一些额外的空间。再次,这是glibc的一个怪癖 - - 你做任何stdout的第一次,一些内存被内部分配,使用malloc

[heap]段,当你调用printf因为出现。该分配是更小比128kB,因此它被放在sbrk区域,你在那里。 (根据您试图模拟的“堆喷”攻击的类型,要么你不关心你的100MB在自己的mmap分配中结束,因为你只是想覆盖整个地址空间,野指针有一个很好的机会指向那里,或者你需要分配大量的对象,每个对象的大小与易受攻击的应用程序中的一些关键数据相同,以便你有一个不错的机会)

+0

这是非常好的信息。谢谢。 – Cryptomancer

2

HeapBuf驻留在堆栈,就像任何其他int S,long S,char是你在你的代码有因为指针本身仅仅是一个数字。但它指向的内存确实分配在堆上。

+0

在这个过程中甚至没有堆段。我也检查了HeapBuf的内容,它们在[stack]地图的地址范围内。如果你愿意,我可以提供证明。 – Cryptomancer

+0

glibc的'malloc'实现将直接使用'mmap'来分配这么大的空间。唯一的映射条目似乎足够大,用于此分配的是'0x989fd000 0xb7dfe000 rw-p映射'。它不在堆栈上;这个堆栈太小了。 – zwol

+0

好的,谢谢@zwol,这实际上回答了我的问题。 – Cryptomancer

1

我不能重复OP的结果。但是,我运行的是x86-64内核和64位二进制文​​件,与OP不同。

这里是一个小的测试程序,test.c的:使用

gcc -Wall -O2 test.c -o test 

./test 

我得到的输出

Payload = 0x7fff3122b6b0 
HeapBuf = 0x7f378806a010 

00400000-00401000 r-xp 00000000 08:07 4587700    /.../test 
00600000-00601000 r--p 00000000 08:07 4587700    /.../test 
00601000-00602000 rw-p 00001000 08:07 4587700    /.../test 
022c3000-022e5000 rw-p 00000000 00:00 0      [heap] 
7f378806a000-7f378e46b000 rw-p 00000000 00:00 0 
7f378e46b000-7f378e62a000 r-xp 00000000 08:05 1966262  /lib/x86_64-linux-gnu/libc-2.23.so 
7f378e62a000-7f378e82a000 ---p 001bf000 08:05 1966262  /lib/x86_64-linux-gnu/libc-2.23.so 
7f378e82a000-7f378e82e000 r--p 001bf000 08:05 1966262  /lib/x86_64-linux-gnu/libc-2.23.so 
7f378e82e000-7f378e830000 rw-p 001c3000 08:05 1966262  /lib/x86_64-linux-gnu/libc-2.23.so 
7f378e830000-7f378e834000 rw-p 00000000 00:00 0 
7f378e834000-7f378e85a000 r-xp 00000000 08:05 1966245  /lib/x86_64-linux-gnu/ld-2.23.so 
7f378ea2c000-7f378ea2f000 rw-p 00000000 00:00 0 
7f378ea57000-7f378ea59000 rw-p 00000000 00:00 0 
7f378ea59000-7f378ea5a000 r--p 00025000 08:05 1966245  /lib/x86_64-linux-gnu/ld-2.23.so 
7f378ea5a000-7f378ea5b000 rw-p 00026000 08:05 1966245  /lib/x86_64-linux-gnu/ld-2.23.so 
7f378ea5b000-7f378ea5c000 rw-p 00000000 00:00 0 
7fff3120c000-7fff3122d000 rw-p 00000000 00:00 0    [stack] 
7fff3126c000-7fff3126e000 r--p 00000000 00:00 0    [vvar] 
7fff3126e000-7fff31270000 r-xp 00000000 00:00 0    [vdso] 
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0  [vsyscall] 

因为

#include <stdlib.h> 
#include <string.h> 
#include <stdio.h> 

void self_maps(void) 
{ 
    FILE *in; 
    int c; 

    in = fopen("/proc/self/maps", "r"); 
    if (!in) 
     return; 

    /* Let the C library handle the buffering. */ 
    while ((c = getc(in)) != EOF) 
     putchar(c); 

    fclose(in); 
} 

int main(void) 
{ 
    size_t NOPSize = 960; 
    size_t ShellcodeSize = 64; 
    size_t PayloadSize = NOPSize + ShellcodeSize; 
    size_t BufferSize = 0x6400000; 
    size_t i; 

    char Payload[PayloadSize]; 
    char *HeapBuf; 

    HeapBuf = malloc(BufferSize); 
    if (!HeapBuf) { 
     fprintf(stderr, "Out of memory.\n"); 
     return EXIT_FAILURE; 
    } 

    printf("Payload = %p\n", (void *)Payload); 
    printf("HeapBuf = %p\n", (void *)HeapBuf); 

    for (i = 0; i < NOPSize; i++) 
     Payload[i] = '\x90'; 

    for (i = NOPSize; i < PayloadSize; i++) 
     Payload[i] = '\x41'; 

    for (i = 0; i < BufferSize; i++) 
     HeapBuf[i] = Payload[i % PayloadSize]; 

    printf("\n"); 
    self_maps(); 

    free(HeapBuf); 

    return EXIT_SUCCESS; 
} 

如果我编译并运行它我正在使用的GNU C库的版本使用内存映射进行分配la rger超过130 KB左右,HeapBuf是在自己的映射:

7f378806a000-7f378e46b000 rw-p 00000000 00:00 0