Защита от хакеров корпоративных сетей
Шрифт:
/* Begin sniffing */
pcap = pcap_open_live(dev, 65535, promisc, 5, NULL);
if (pcap == NULL) {
perror(“pcap_open_live”);
exit(EXIT_FAILURE);
}При отсутствии ошибок открывается окно главного интерфейса с указанием спецификаций максимально возможного захвата без учета размера захватываемых данных. Перехватываются все доступные этому интерфейсу пакеты независимо от того, адресованы они одобренному ядром операционной системы MAC-адресу или нет. Для синтаксического анализа пакетов используется минимальная задержка, понижающая риск возможных ошибок:
if (ioctl(pcap_fileno(pcap), BIOCIMMEDIATE, &immediate)) {
/*perror(“Couldn’t set BPF to Immediate Mode.”); */
}Прежде чем пакет будет передан на обработку, устанавливается задержка 5 мс. Это специально сделано для успешного завершения
Опция IOCTL настолько сильно улучшает производительность, что просто непонятно, каким образом на некоторых платформах можно обходиться без нее. В целом флажок BIOCIMMEDIATE сообщает библиотеке libpcap о необходимости блокировки чтения и установке буфера минимально возможного размера. При этом гарантируется максимальное время обработки пакетов маршрутизатором. Это хорошая вещь.
Некоторые платформы могут жаловаться о посылке им опции IOCTL. Поэтому если читатель захочет узнать, присуща ли этой строчке кода ошибка или нет, то пусть он раскомментирует закомментированный раздел:/*
* Create the filter to catch ARP requests, ICMP’s, and
routable
* packets.
*/
snprintf(pfprogram, sizeof(pfprogram), “arp or icmp or ether dst
%hX:%hX:%hX:%hX:%hX:%hX”, user_mac[0], user_mac[1],
user_mac[2],
user_mac[3], user_mac[4], user_mac[5]);
/* Compile and set a kernel-based packet filter*/
if (pcap_compile(pcap, &fp, pfprogram, 1, 0x0) == -1) {
pcap_perror(pcap, “pcap_compile”);
exit(EXIT_FAILURE);
}
if (pcap_setfilter(pcap, &fp) == -1) {
pcap_perror(pcap, “pcap_setfilter”);
exit(EXIT_FAILURE);
}Наличие возможности откликнуться на все видимые пакеты еще не означает, что это действительно нужно сделать. Нет никакой нужды анализировать весь трафик, и так добросовестно обрабатываемый ядром операционной системы! Поэтому сначала настроим фильтр, используя функцию snprintf. Только теперь, после завершения функции getopt, можно фильтровать пакеты, предназначенные для заданного MAC-адреса. Поэтому перед тем как прослушать трафик, надо знать свой MAC-адрес. Простой способ компиляции и активизации правил фильтрации был показан в предшествующем коде.
Реализовать описанный способ непросто. Успех его реализации зависит от элегантности и доступности интерфейса программного кода ядра, написанного другими людьми с соблюдением требований переносимости с одной платформы на другую. Позднее будет осуществлен поиск пакетов специфического типа. Любая подсказка, которая сможет пролить свет на загрузку анализатора пакетов, будет полезной. Дареному коню в зубы не смотрят и все такое прочее.
С этого момента, наконец, появляется возможность приступить к перехвату пакетов.Noa.o Libnet.
/* Get Direct Connection To The Interface */
if ((l = libnet_open_link_interface(dev, errbuf)) == NULL) {
fprintf(stderr, “Libnet failure opening link
interface: %s”,
errbuf);
}Интерфейс связи предоставляет пользователю способ получения необработанных пакетов сразу же после прихода их по линии связи. Libpcap позволяет выбирать необработанные пакеты, а libnet – отправлять их. Подобная симметричность двух программных средств очень полезна. Чуть позже это станет видно лучше.
Но все упирается в цену успеха. Возможность определить адрес аппаратных средств, которым посылаются данные, означает отсутствие какой-либо помощи со
/* Lookup the router */
Помните, что ядро не предоставляет никакой подсказки относительно места нахождения маршрутизатора, и все, что фактически можно спросить у пользователя, – это его IP-адрес. В распоряжении разработчика предоставлен разумно гибкий интерфейс сетевого стека. Давайте воспользуемся им для посылки широковещательного запроса по протоколу разрешения адресов ARP с целью определения адреса аппаратных средств, соответствующих заданному IP-адресу, через который, как было сказано, следует направить пакет для маршрутизации. В нижеприведенном фрагменте кода видно, как на пустом месте следует создать пакет и отослать его:
libnet_init_packet(LIBNET_ETH_H + LIBNET_ARP_H, &newpacket);
Являясь простой оболочкой malloc, libnet_init_packet инициализирует заданное количество памяти (в этом случае необходимое количество памяти для заголовков Ethernet и ARP) и создает указатель newpacket на выделенную таким образом память:
libnet_build_ethernet(bcast_mac, /*eth->ether_dhost*/
user_mac, /*eth->ether_shost*/
ETHERTYPE_ARP, /*eth->ether_type*/NULL, /*extra crap to tack on*/
0, /*how much crap*/
newpacket);
Следует полностью определить базовую часть пакета: указать, куда пакет направляется, откуда поступил, тип пакета и т. д. В рассматриваемом случае пакет является широковещательным сообщением ARP из MAC-адреса пространства. Учитывая указатель newpacket правильным образом, указываем на заголовок Ethernet:
libnet_build_arp(ARPHRD_ETHER,
ETHERTYPE_IP,
ETHER_ADDR_LEN,
IPV4_ADDR_LEN,
ARPOP_REQUEST,
user_mac,
user_ip,
bcast_mac,
upstream_ip,
NULL,
0,
newpacket + LIBNET_ETH_H);Библиотека libnet предоставляет полезные функции и учитывает почти все обрабатываемые выпуски программ, достаточные для заполнения полей пакета. При заполнении ARP-пакета требуется заполнить поля MAC-адреса пользователя и его IP-адрес, причем IP-адрес перечислен в списке upstream_ip и должен быть принят во внимание любым, кто может прослушать этот адрес. Следует отметить, что эта груда байтов к указателю newpacket непосредственно не добавляется. По протоколу Ethernet она передается следующему заголовку фиксированного размера:
i = libnet_write_link_layer(l, dev, newpacket, LIBNET_ETH_H
+
LIBNET_ARP_H);
if (verbose){
fprintf(stdout, “ARP REQUEST: Wrote %i bytes looking
for ” , i);
print_ip(stdout, upstream_ip);
}Точно так же как машины отправляются в путь, пример отправляет Ethernet и ARP-заголовки, найденные им по указателю newpacket, а затем выполняет код, написанный для отладки. Функция Libnet_write_link_layer получает от библиотеки libnet номер соединения, адрес памяти отсылаемого пакета, как бы ни велик был пакет, а затем возвращает число успешно переданных байтов: