2017-02-04 8 views
0

Редактировать: Мой оригинальный вопрос больше не точен, поэтому я переписал его.Почему это выделяется в стеке вместо кучи?

Так что я пишу программу, чтобы продемонстрировать кучу спрея в C (что я знаю необычно). Я выделяю огромный буфер (100 МБ) с помощью malloc, но он выделяет сегмент с отображением, а не [кучу], и я не могу понять, почему.

Мой код:

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); 

Выход VMMap с помощью GDB-ПЕДА взяты из точки останова, установленной на вызове 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, который находится в верхнем сопоставляются сегменте.

Интересно, что сегмент [heap] исчезает, если я удалю звонок до printf. Итак, мои вопросы, почему присутствие сегмента [heap] зависит от вызова printf и почему это печатный адрес в отображенном сегменте, а не в сегменте [heap]? Благодарю.

+0

Что карты памяти выглядят как * перед * свободным (HeapBuf) '? –

+0

Это до освобождения. Он берется с точки останова прямо перед выполнением 'free'. – Cryptomancer

+0

Кажется, что ваш рабочий стол работает как «root». Не делай этого. – zwol

ответ

1

Там две вещи, происходящие здесь, и, прежде чем попасть в них, я должен предупредить вас, что на основании наличия строки /lib/i386-linux-gnu/libc-2.24.so на выходе вашей карты, я выводил, что операционная система, на которой выполняется ваша программа, использует ядро ​​Linux и библиотеку GNU C («glibc»). Некоторые из того, что я собираюсь вам рассказать, очень важны для этих компонентов.

Во-первых: по историческим причинам существует два разных способа распределения памяти на операционных системах, которые квалифицируются как «Unix» (в первом порядке: все, что все еще использует, кроме Windows): системные вызовы sbrk и mmap. sbrk гораздо более ограничен; он может управлять только размером одной области памяти в определенном месте, тогда как mmap (и его коллега munmap) может выделять и освобождать независимые блоки памяти в любом месте адресного пространства.В файле Linux /proc/PID/maps используется метка [heap] для области памяти, управляемой sbrk. Независимые блоки памяти, выделенные mmap, обозначены как «сопоставленные».

Во-вторых, реализация GLibC по malloc использует sbrk для небольших распределений и mmap для больших распределений (см обсуждение M_MMAP_THRESHOLD в mallopt manpage). Порог по умолчанию между «малым» и «большим» равен 128 килобайт; вы выделили 0x6400000 байт = 100 мегабайт, что, очевидно, намного больше. Линия ваших отображений дамп чтение

0xb19fd000 0xb7dfe000 rw-p mapped 

ровно одна страница больше, чем то, что вы просили - расхождение связано с malloc принимая какое-то дополнительное пространство для собственной информации бухгалтерию.

[heap] сегмент появляется, когда вы звоните printf, потому что - опять-таки, это причуда Glibc - самый первый раз, когда вы делаете что-либо с stdout, некоторая память получает выделяется внутри, используя malloc. Это выделение меньше, чем 128kB, поэтому он попадает в область sbrk, и вот вы где.

(В зависимости от того, какую атаку «кучей спрей» вы пытаетесь имитировать, либо вам все равно, что ваш 100MB попал в свое собственное распределение mmap, потому что вы просто пытаетесь охватить достаточно общего адреса пространство, которое имеет дикий указатель, имеет достаточный шанс указать там или вам нужно выделить большое количество небольших объектов, каждый из которых имеет такой же размер, как и некоторые ключевые фрагменты данных в уязвимом приложении, так что у вас есть неплохая возможность из-за того, что ваши распределения перепутаны с приложением.)

+0

Это отличная информация. Спасибо. – Cryptomancer

2

HeapBuf находится в стеке, как и любые другие int с, long с, char с содержащимся в вашем коде, потому что сам указатель является просто числом. Но память, на которую указывает, действительно выделяется в куче.

+0

В этом процессе нет даже кучного сегмента. Также я проверил содержимое HeapBuf, и они находятся в диапазоне адресов карты [stack]. Я могу предоставить доказательство, если вы хотите. – Cryptomancer

+0

реализация glibc 'malloc' будет использовать' mmap' непосредственно для распределений этого большого размера. Единственная запись в карте, которая кажется достаточно большой для этого выделения, - «0x989fd000 0xb7dfe000 rw-p mapped». Это НЕ на стеке; стек слишком мал. – zwol

+0

Хорошо, спасибо @zwol, это действительно отвечает на мой вопрос. – Cryptomancer

1

Я не могу дублировать результаты OP. Тем не менее, я работаю на ядре x86-64 и 64-битных двоичных файлах, в отличие от OP.

Вот небольшая тестовая программа, test.c:

#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; 
} 

Если я скомпилировать и запустить его с помощью

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] 

Поскольку версия библиотеки GNU C, которую я использую, использует сопоставление памяти для распределений la rger чем 130 кБ или так, HeapBuf в отображении своих собственных:

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