книги хакеры / Защита_от_взлома_сокеты,_эксплойты,_shell_код_Фостер_Дж_
.pdf
|
|
|
|
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 |
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
|
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;