Коллектив авторов - Защита от хакеров корпоративных сетей
Все, что для этого нужно сделать, на самом деле не очень сложно. После чтения нескольких опций пользователя инициируется программа перехвата и генерации пакетов, которая сравнивает каждый поступивший пакет с коротким списком правил, определяющих возможную генерацию кода возврата в той или иной форме. Хотите более подробно? Вот схема алгоритма:
1. Установить конфигурацию.
1.1. Установить статические переменные.
1.2. Присвоить значения по умолчанию.
1.3. Выполнить анализ командной строки.
2. Начать анализ трафика.
2.1. Открыть устройство прослушивания с максимально возможной производительностью.
2.2. Применить фильтрацию ядра к потоку данных, который вскоре будет активизирован.
2.3. Активизировать поток.3. Начать спуфинг.
3.1.Открыть устройство отправки данных с максимально возможной производительностью.
3.2. Послать ARP-запрос на поиск MAC-адреса маршрутизатора.4. Разбор прослушиваемого пакета (бесконечный цикл, который срабатывает по приему пакета).
4.1. Применить правила анализа.
4.2. Потребовать пространство пользователя для IP-и MAC-адреса.
4.2.1. Поиск ARP-запросов для своего IP-адреса.
4.2.2. Деструктивное преобразование ARP-запроса в ARP-ответ с указанием IP-адреса и МАС-адреса в пространстве пользователя.
4.2.3. Отсылка преобразованного пакета.
4.3. Поиск ARP-ответов с MAC-адресами маршрутизатора.
4.3.1. Создание кэша для последующего решения задач маршрутизации.
4.4. Поиск запросов PING (ICMP ECHO) к своим IP-и MAC-адресам.
4.4.1. Деструктивное преобразование ICMP ECHO и ответ на него.
4.4.2. Уменьшение счетчика времени жизни пакета TTL.
4.4.3. Пересчет контрольной суммы пакета.
4.4.4. Отсылка преобразованного пакета.
4.5. Маршрутизация пакета на свой MAC-адрес.
4.5.1. При необходимости проверить, является ли полученный пакет IP-пакетом.
4.5.2. Деструктивное переназначение Ethernet-адресов получателя и отправителя на адреса отправителя пакета и получателя в локальной сети соответственно.
4.5.3. Если можно вычислить контрольную сумму, то уменьшить счетчик времени жизни пакета и повторно вычислить контрольную сумму пакета.
4.5.4. Отослать измененный пакет.
Начало: директивы препроцессора и объявления функций. Ниже приводится полный код для использования. Его трудно прокомментировать. В интересах обсуждения отступ в комментариях был удален. Давайте начнем!#define TITLE “DoxRoute: Userspace IP Router”
#define VERSION “0.1”
#define CODERS “Copyright (C) 2001 Dan Kaminsky
([email protected])”
#define CODENAME “Bender”
#define GIANT “Mark Grimes([email protected])”Конечно, следует доверять там, где это оправданно. Удивительно, но приведенных строк достаточно для построения кода с использованием блестящего пакета nemesis компании Grimes, хотя его использование практически не заметно.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libnet.h>
#include <pcap.h>
#ifndef IPV4_ADDR_LEN
#define IPV4_ADDR_LEN 4
#endifПрежде всего следует определить необходимые для работы приложения библиотеки. Для программы DoxRoute потребуются три вещи. Во-первых, стандартные библиотеки, необходимые почти каждому приложению на языке C. Они подключаются при помощи файлов stdio.h, stdlib.h и unistd. Во-вторых, система для отправки фальсифицированных пакетов. Она инкапсулирована внутри файла libnet.h, очевидно, связанного с библиотекой libnet. И наконец, в-третьих, система прослушивания любых пакетов, передаваемых по каналу связи. Подключение такой системы осуществляется при помощи файла pcap.h библиотеки libpcap.
Но более важным является не то, что реализовано, а то, что не реализовано. Обычно для любой предназначенной для работы в сети программы, особенно программы обработки пакетов на низком уровне, требуется огромное число зависимых от операционной системы библиотек и включаемых в программу файлов заголовков. Используемые файлы и заголовки сильно изменяются от платформы к платформе, что является головной болью не только при переходе от одной платформы к другой, но и от одной версии ядра к другой. Программа сталкивается с ордами директив препроцессора с большим числом макросов #ifdef, которые определяют последовательность действий на каждой системе. После этого кода программа приобретает вполне законченный вид.
Использование библиотек libpcap и libnet позволяет изменить это. В них содержатся описания входящих и выходящих пакетов, а также некоторые базовые структуры, которые необходимы для того, чтобы понять, что вообще происходит на самом деле. Появляется возможность отвлечься от рассмотрения пустой болтовни, зависимой от операционной системы:void usage();
void print_ip(FILE * stream, u_char * ip);
void print_mac(FILE * stream, u_char * mac);
int
main(int argc, char **argv)
{Объявления переменных. В основном все переменные предназначены для функции getopt – общего синтаксического анализатора опций командной строки:
int opt;
extern char *optarg;
extern int opterr;К настоящему моменту времени читатель уже, вероятно, заметил, что в операционной системе UNIX почти все приложения командной строки совместно используют одинаковый синтаксис: что-то вроде foo – X – y параметр. Этот формат входных параметров стандартизирован и обрабатывается библиотечной функцией getopt. Очень старые платформы для успешного анализа входных параметров потребуют от программиста добавить в начало его программного кода директиву # include <getopt.h>. Более современные стандарты предусматривают помещение функции getopt как части файла unistd.h:
pcap_t *pcap; /* PCAP file descriptor */
u_char *packet; /* Our newly captured packet */
struct pcap_pkthdr pkthdr; /* Packet metadata—time
received, size */
struct bpf_program fp; /* Structure to hold kernel packetfilter
*/
char pfprogram[255]; /* Buffer for uncompiled packet
filter */
char dev[255]; /* Name of device to use */
int immediate = 1; /* Flag to suck packets at
max speed */
int promisc = 1; /* Flag to grab all packets
visible */Особого пояснения требует буфер pfprogram. Аналогичное выражение можно использовать в программе tcpdump или tethereal точно так же, как и, например, порт 22 или хост 1.2.3.4 и udp. Фактически описание буфера является входной спецификацией конструирования фильтров внутри библиотеки libpcap. Библиотека libpcap сама транслирует фильтр в выполняемый код. Достаточно только передать осмысленную с точки зрения синтаксиса строку параметров, а все остальное библиотека доделает сама. Результат впечатляет:
struct libnet_ethernet_hdr *eth = NULL;
struct libnet_ip_hdr *ip = NULL;
struct libnet_tcp_hdr *tcp = NULL;
struct libnet_arp_hdr *arp = NULL;
struct libnet_icmp_hdr *icmp = NULL;
struct libnet_udp_hdr *udp = NULL;В библиотеке libnet определены базовые типы пакетов, которые описаны во включаемом файле include/libnet/libnet-headers.h. Подобное определение типов пакетов не только экономит время, но и позволяет стандартизировать структуры описания пакетов, по крайней мере при создании переносимых сетевых инструментальных средств:
struct libnet_link_int *l;
u_char *newpacket;
u_char user_ip[IPV4_ADDR_LEN+1];
u_char upstream_ip[IPV4_ADDR_LEN+1];
u_char test_ip[IPV4_ADDR_LEN+1];
struct in_addr test_ipa;
/* MAC addresses = Local Link-Level Hardware Addresses On
The Network */
u_char user_mac[ETHER_ADDR_LEN+1]; /* MAC to receive
packets on */
u_char upstream_mac[ETHER_ADDR_LEN+1]; /* MAC to forward
packets to */
u_char bcast_mac[ETHER_ADDR_LEN+1]; /* Forward addr for
all MACs */
u_char test_mac[ETHER_ADDR_LEN+1]; /* A buffer to test
against */В этих строчках кода присутствует стеснительный и, вероятно, ненужный хакинг. Важно, что создан статический массив для заполнения различных адресов: собственного IP-адреса, MAC-адреса маршрутизатора, которому будет передан пакет, и т. д. Но благодаря странностям функции sscanf и тому факту, что при быстрой работе утрачивается некоторая безопасность, буфера перезаписываются странными и не до конца выясненными способами. Буфера можно очистить, создавая буфер одного из устройств большего, чем это действительно нужно, размера. Этот способ не очень элегантен, он даже уродлив, но вполне работоспособен. Для правильного решения возникшей проблемы необходимо написать собственный вариант функции sscanf, выполняющий правильный разбор способов задания MAC– и IP-адресов, но автор попытался сохранить этот код разумно компактным и простым:
char errbuf[255];
int do_checksum = 0;
int verbose = 0;
int i = 0;Установка значений по умолчанию. Одна важная особенность, присущая всем программам, заключается в задании их поведения по умолчанию. Тем самым минимизируется объем знаний, необходимых программе во время ее первого запуска. Например, Web-серверам не обязательно указывать имя домашней страницы всякий раз, когда кто-либо подключается к http://www.host.com. По умолчанию если не указано ничего другого, то при подключении по этому адресу пользователю возвращается ответ, как если бы он запросил http://www.host.com/index.html. Точно так же следует установить значения по умолчанию для маршрутизации пакетов:
/* Set Broadcast MAC to FF:FF:FF:FF:FF:FF*/
bcast_mac[0] = 0xFF;
bcast_mac[1] = 0xFF;
bcast_mac[2] = 0xFF;
bcast_mac[3] = 0xFF;
bcast_mac[4] = 0xFF;
bcast_mac[5] = 0xFF;Иногда выбор установленных по умолчанию значений не представляет большого труда. Основные стандарты Ethernet определяют, что при задании в пакетах MAC-адреса FF: FF: FF: FF: FF: FF эти пакеты должны получить все хосты данной подсети. Локальная сеть на основе протокола Ethernet только недавно стала переключаемой средой, поэтому ранее использование адреса FF: FF: FF: FF: FF: FF больше носило характер «рекомендательного» сообщения для сетевых плат, которые должны были передать этот пакет операционной системе даже в том случае, если это сообщение не было адресовано определенному хосту. Ныне сетевые платы не видят сетевой трафик до тех пор, пока переключатель не посчитает, что он предназначен заданному хосту. В программе широковещательная рассылка MAC-адресов осуществляется следующим образом. Во многих протоколах предусмотрен запрос ко всем хостам локальной подсети. Для наших целей наиболее уместен протокол ARP: