Переполнение буфера в heap. 1 серия

kas1e

Xakep, номер #057, стр. 057-074-4


Эти 4 функции и есть "костяк". Правда, существует и много других, работающих с heap вообще: cfree(), tmpnam(), getenv(), strdup(), atexit() и т.д. Для примера "распотрошим" malloc() функцию:

malloc() использует brk syscall (поднимает планку для хипа). Если либу компильнуть статически и отдебажить malloc, то станет видно, что после всех своих действий она вызывает этот самый brk(). malloc также и "выравнивающая функция". Причем, помимо обычных данных, под которые мы выделяем память, она добавляет некоторые другие значения: размер области, указатель на следующую область и т.д. (см. структуру malloc_chunk{}). Т.е. функция malloc выделяет несколько больше памяти, чем указано в ее аргументе. Посмотрим простенький пример:

#include <unistd.h>

int main()

{

int buf1, buf2;

buf1=malloc(0); // в первый буфер выделяем 0

buf2=malloc(0); // во второй буфер выделяем 0

printf("buf1 = %p\nbuf2 = %p\n",buf1,buf2); // покажем разницу в адресах

}

Компильнем и запустим:

[root@heap_part1]# gcc test_malloc.c -o test_malloc

[root@heap_part1]# ./test_malloc

buf1 = 0x8049660

buf2 = 0x8049670

[root@heap_part1]#

Вроде из heap мы выделили себе 0 байт, a автоматом произошло выравнивание и засовывание нужных самой malloc() данных. Эти самые данные представлены такой структурой:

#define INTERNAL_SIZE_T size_t

struct malloc_chunk

{

INTERNAL_SIZE_T prev_size;

INTERNAL_SIZE_T size;

struct malloc_chunk * fd;

struct malloc_chunk * bk;

};

Вот что находится в этой структуре:

- размер предыдущего куска

- размер текущего куска

- struct fd

- struct bk

Далее расположилось место непосредственно под переменную и метку окончания куска. Фактически, как некоторые уже наверно догадались, эксплуатация заключается в подделке этих malloc() данных. И вот теперь, когда мы выяснили, что такое heap и как с ним работают функции, рассмотрим реальный пример.

Классическое переполнение

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

А теперь рассмотрим простейший пример:

/* ---heap_overflow_base.c--- */

/* переполнение буфера в heap */

#include <stdio.h>

main()

{

char *buf1;

char *buf2;

// создадим buf1 и buf2 в хипе (через malloc()) размером в 16 байт

buf1=(char *)malloc(16); // 16

buf2=(char *)malloc(16); // 16

// заполним вторую переменную 16 ascii символами 'A'

memset(buf2, 'A', 16);

// покажем содержимое buf2 до переполнения

printf("before overflow: buf2 = %s\n", buf2);

// заполним buf1 25 символами B (под первый буфер было отведено только 16 байт!)

// 25, т.к. 16 сам по себе буфер + 8 байт данные malloc() и 1 тот, который

// запрется на втором буфере (т.е. переполнит его)

memset(buf1, 'B', 25);

// покажем содержимое buf2 после переполнения

Назад на стр. 057-074-3  Содержание  Вперед на стр. 057-074-5