| RSS



Меню

Bookmark and Share


Статистика
Ваш IP: 127.0.0.1
Вы используете: v





Сейчас на сайте:

Тех поддержка ->

Облако тэгов
ОС видио Tor Обратная сторона антенна 4.6 php libc rand() эксплоит Windows Server 2008 FreeBSD Jail Elastix QIP Virtual chroot Limit kernel proc sysctl Tune freeBSD bridge Boot LiveCD Disk Bluetooth GEO game DirectX emulator Python Shell червь Conficker вирус троян лаборатория касперского пиратство Apple iPhone Microsoft twitter социальная сеть анонимность лицензия Open Source уязвимость MySQL база данных Закон Франция Пират Skype мобильный Deutsche Telekom хакер trend micro кибератака Германия робот Персональные данные Ноутбук Интернет китай цензура windows vista acer Linux патент браузер Firefox Internet Explorer Opera Safari Intel Oracle патч Банкомат IBM США Dell Ford MAC контроль Internet кибербезопасность приговор Mozilla Chrome безопасность Госдума СМИ Windows 8 взлом Пентагон Украина Facebook Cisco Cloud Windows XP нетбук торрент музыка Биометрический Nokia Hardware Manager ФБР IP-адрес sms RSA java Google Captcha Symantec Спам Антивирус тест Anti-Malware Windows 7 операционная система windows провайдер авторское право rapidshare UNIX свиной грипп шантаж Дети ipod копирайт McAfee HTTPS icann студент Норвегия New York Times YouTube Warner Music КНДР Ubuntu AMD ATI касперский Россия РФ сервер хостинг Wi-Fi суд пароль блог фишинг одноклассники Медведев контрафакт мошенник sony Gps по JavaScript Хакеры Yahoo фас компьютер софт Минкомсвязи Сбой мошенничество Доктор ВЕб Вконтакте ie8 исходный код МВД фильтр порнография свобода слова казахстан Autodesk сисадмин Gmail кредитная карта LiveJournal шифрование Deep Purple банк HTML5 Нанотехнологии wikipedia выборы DNS bind KaZaA Android Basic атака Mac OS X домен ФСБ прокуратура уголовное дело ICQ Sophos Google Voice ошибка DARPA военные сайт турция конференция спамер Полиция Koobface Великобритания IRC белоруссия Грузия Bittorrent Европа Dr.WEB Linux Mint Билл Гейтс спецслужбы Royal Bank of Scotland смартфон Canonical F-Secure Symbian фильм Microsoft Office Новая Зеландия Adobe Австралия IDC Internet Explorer 9 iPad Ирландия поиск GOOGLE EARTH МТС Реклама слежка Mandriva BSD Zeus личные данные eset avast Avira G Data Software защита Defcon виртуализация dll LibreOffice Черный список BlackBerry индия Москва DVD социальные сети flash player paypal BitDefender email сертификат honda MasterCard Anonymous технологии IPv6 Ассанж Оптоволокно передача данных арест Fedora Samsung Иск Apache учетная запись iTunes исследование Cert Санкт-Петербург McDonald's SOPA PIPA Bioshock Infinite: Burial at Sea - ico Megaupload CES hotfile отчет приложение Инвестиции платформа DRM DDoS-атака роскомнадзор

Главная » Статьи » Общие Статьи

Пишем сниффер под Linux
PF_PACKET

Функция socket() открывает сокет (или, как сказано в 'man 2 socket' моего линукса, "оконечную точку коммуникации") и возвращает её дескриптор. Синтаксис функции таков:

int socket(int domain, int type, int protocol);

Первый параметр, int domain, задаёт семейство (или, более привычно, стек) протоколов, для которого создаётся сокет. Стеку IPv4 (Internet Protocol version 4), например, соответствует константа PF_INET или её эквивалент, AF_INET. Все доступные (но не обязательно поддерживаемые ядром) константы перечислены в <bits/socket.h>. Так вот, в Linux'е поддерживается особый стек протоколов (который на самом деле стеком не является), PF_PACKET. Апеллируя к нему, можно открывать сокеты с доступом к самому низкому, сетевому уровню (Local Networking Level по модели OSI), а это именно то, что нам с тобой нужно для создания сниффера.

Второй параметр, int type, определяет тип протокола, требуемый внутри выбранного семейства. Таких типов протоколов немного: SOCK_STREAM (двустороннее потоковое соединение), SOCK_DGRAM (односторонняя дейтаграммная передача без установления соединения), SOCK_RAW (доступ к получению/формированию заголовков протоколов выбранного семейства) и нужный нам SOCK_PACKET (доступ к получению/формированию кадров данных). Существуют и другие типы протоколов специального назначения, но они в настоящее время либо не используются, либо используются крайне редко.

Третий параметр либо содержит нуль, указывая на то, что необходимо использовать дефолтный протокол, подразумеваемый вторым параметром, либо явно уточняет конкретный протокол, который необходимо использовать для открываемого сокета. Например, вызов

sock = socket(PF_INET,SOCK_STREAM,0);

откроет нам IP/TCP'шный сокет, а вызов

sock = socket(PF_INET,SOCK_RAW,IPPROTO_ICMP);

откроет нам IP/ICMP'шный сокет.

В нашем же случае, третий параметр указывает на протокол (Internetworking Level по модели OSI) сетевого уровня, с которым необходимо проассоциировать сокет. Все доступные значения для сокета PF_PACKET/SOCK_PACKET перечислены в <linux/if_ether.h>. В своём примере я буду использовать параметр ETH_P_ALL, что означает приём всех доступных ядру системы сообщений. Необходимо кастовать эту двухбайтную константу к обратному порядку следования байт, макросом htons(). Итак,

sock = socket(PF_PACKET,SOCK_PACKET,htons(ETH_P_ALL));

откроет нужный нашему снифферу сокет.

Обрати внимание, дружище, ты не сможешь открыть такой сокет, не обладая привилегиями рута. Из соображений безопасности, ядро не позволит открывать сокеты с SOCK_PACKET (и даже с SOCK_RAW) юзеру с UID'ом, не равном нулю.

ПРИВЯЗКА СОКЕТА К УСТРОЙСТВУ

Необходимо привязать сокет к физическому устройству, которое мы будем прослушивать. Это можно (и нужно) делать для любого устройства, кроме псевдоустройств (типа loopback). Привязка осуществляется системным вызовом setsockopt():

int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);

int s -- сокетный дескриптор;
int level -- уровень, на котором необходимо произвести операцию;
int optname -- непосредственная операция, зависящая от второго параметра;
const void *optval -- указатель на начало аргумента к операции (либо NULL, если аргументов не требуется);
socklen_t optlen -- длина аргумента.

Вообще говоря, setsockopt() -- функция, весьма богатая своими возможностями, но сейчас нас интересует только возможность привязки сокета устройству, имя которого мы сообщим в четвёртом параметре, например:

rc = setsockopt(sock,SOL_SOCKET, SO_BINDTODEVICE,"eth0\x00",strlen("eth0\x00")+1);

привяжет сокет sock к устройству eth0. Обрати внимание, необходимо завершать имя устройство нулевым символом. Если setsockopt() совершит привязку успешно, она вернёт нуль. В противном случае необходимо проверять глобальную переменную errno для детальной диагностики ошибки.

PROMISCIOUS MODE

В нормальном режиме работы, устройство будет принимать (и, соответственно, доставлять ядру) лишь те кадры данных, которые содержат в поле Destination MAC Address проассоциированный с этим устройством MAC-адрес. Иными словами, при нормальном режиме работы устройства, ты сможешь ловить из сети только те сообщения, которые направлены к тебе.

Для того, чтобы получить возможность вылавливать из сети все кадры данных без исключения, необходимо перевести устройство в promiscious mode ("промискуитетный", т.е. неразборчивый режим). Это осуществляется с помощью вызова ioctl():

int ioctl(int d, int request, ...);

int d -- файловый (или, как частный случай файлового, сокетный) дескриптор;
int request -- системный вызов ядра Linux (перечислены в man 2 ioctl_list и разбросаны по хидерам в <linux/...>);
... -- переменное число аргументов ко второму параметру.

Для осуществления этой операции нам потребуется сгрузить текущие параметры и настройки устройства (интерфейса) в структуру struct ifreq (описан в <linux/if.h>) с помощью системного вызова SIOCGIFFLAGS:

struct ifreq interface;
...
ioctl(sock,SIOCGIFFLAGS,&interface);

И взвести в элементе ifr_flags структуры interface бит IFF_PROMISC:

interface.ifr_flags |= IFF_PROMISC;

А затем, с помощью системного вызова SIOCSIFFLAGS, загрузить изменённую структуру interface обратно:

ioctl(sock,SIOCSIFFLAGS,&interface);

попутно проверяя результаты ioctl на предмет наличия ошибок.

Обязательно учти тот момент, что при большой нагрузке на сеть (более нескольких тысяч кадров данных в секунду), сниффер, переведённый в promiscious mode, будет "задыхаться", не успевая обрабатывать поток сообщений. Это может привести к непредсказуемым последствиям. Начиная с того, что такой сниффер будет попросту пропускать некоторые сообщения (ядро не будет успевать "сгребать" эти сообщения с устройства), и заканчивая тем, что активность такого сниффера можно легко обнаружить различными анти-снифферскими методами. Эта опасность не преувеличена: даже пара десятков windows-машин в локальном сегменте создадут ощутимую нагрузку на сеть, обмениваясь пустопорожним NETBIOS-траффиком друг с другом.

ВЫХОД ИЗ PROMISCIOUS MODE

После завершения работы сниффера, НЕОБХОДИМО вернуть устройство в первоначальное (нормальное) состояние, сняв флаг IFF_PROMISC. Для этого, производим обратную описанной выше операцию:

interface.ifr_flags ~= IFF_PROMISC;

и

ioctl(sock,SIOCSIFFLAGS,&interface);

RECVFROM

Итак, после того, как мы создали сокет, привязали его к нужному интерфейсу и перевели устройство в promiscious mode, мы можем получать кадры данных (начиная с заголовка EtherNet, соответственно), следующим вызовом:

rc = recvfrom(sock,buf,sizeof(buf),0,0,0);

где buf -- достаточно крупный, чтобы вместить максимально возможный кадр данных, буфер. sizeof(buf) я рекомендую делать не менее 65536 байт (хотя, на самом деле, во многих локальных сетях MTU не превышает 1.5-4 тысячи байт). Последние три параметра, за ненадобностью, опускаются.

Обрати внимание: сокет остаётся в блокирующем режиме. Это не очень эффективно, но зато очень просто :)) В самый раз для демонстрационного примера :) Итак, recvfrom() будет отдавать управление всякий раз, как только в буфере сокета sock появится хоть что-нибудь для чтения и это "что-нибудь" будет прочитано.

LOOPBACK

Для желающих сниффить loopback device (а такая необходимость нередко возникает, особенно у разработчиков сетевого ПО, тестирующих свой софт на локалхосте), следует не привязывать сокет к устройству и, соответственно, не вводить его в promiscious mode, а просто отфильтровывать (на программном уровне) сообщения с нулевыми Source и Destination MAC-адресами. Этот подход проиллюстрирован в примере.

ПАРСИНГ

Я сделал небольшой примитивный парсинг вывода в демо-сниффере. Метод, конечно же, оставляет желать лучшего :))) Но, всё же, это эффективнее, чем вызывать по тысяче раз функцию printf() непосредственно на консоль при парсинге одного-единственного сообщения :) Вообще говоря, парсинг в сниффере -- это самая муторная и ресурсоёмкая задача. Но, уверен, тебе не составит особого труда её решить в том виде, в котором ты захочешь.

ЭФФЕКТИВНОСТЬ

Демо-сниффер адски неэффективен: он случает все без исключения сообщения, проходящие мимо устройства. Можно, конечно же, реализовать фильтр программного уровня, который будет отдавать на парсинг лишь те сообщения, которые интересны пользователю, но ядро всё равно будет испытывать всю тяжесть сетевого трафика.

Выход, тем не менее, есть. Он был предложен аж в начале 80-х годов и давно реализован в виде библиотеки libpcap для UNIX, используемой популярным сниффером tcpdump. Это решение, именуемое Berkeley Packet Filtering (bpf), заключается в установке фильтра на устройстве таким образом, что устройство генерирует прерывание и отдаёт ядру лишь те сообщения, которые этот фильтр пропускает. Фильтр можно настраивать на MAC-адреса, на IP-адреса, на протоколы транспортного уровня (ICMP, TCP, UDP, etc), на определённые порты, на количество байт, которое необходимо сгребать с каждого кадра данных и на многое другое.

BPF можно программировать с помощью команд SO_ATTACH_FILTER и SO_DETACH_FILTER уровня SOL_SOCKET вызова setsockopt():

rc = setsockopt(sock,SOL_SOCKET,SO_ATTACH_FILTER,&opcode,sizeof(int));

особым BPF-ным псевдокодом (а это весьма муторное занятие), либо с помощью вызова pcap_compile() библиотеки libpcap, компилируя псевдокод из текстовой строчки, как это делается в tcpdump'е (вроде "host 192.168.0.1 proto 6 port 23\x00").

Но обо всём этом я напишу в следующей статье...

P.S.

Мне очень хотелось бы услышать твоё мнение относительно того, хочешь ли ты увидеть продолжение этой статьи? Интересна ли эта тема? Жду откликов во "мнениях"...

С уважением, [Privacy]

Исходники

Категория: Общие Статьи | Добавил: aka_kludge (19.08.2008) | Автор: Privacy
Просмотров: 3116 | Рейтинг: 5.0/1
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
    Главная      
...
На службе : дней

11:58
Обновить


Пользователи
aka_kludge
qwerty
LeadyTOR
aka_Atlantis
AdHErENt
mAss
Sissutr
hiss
DrBio
tHick

Поиск


Copyright tHR - TeAM 2025 г. admin: aka_kludge (ICQ:334449009) Moderator's: LeadyTOR, ... Яндекс.Метрика