четверг, 13 февраля 2014 г.

Сниффер своими руками за 5 минут


  Любой новичок, который начал изучать программирование на С в Linux, после написания «Hello, world!» мечтает написать что нибудь более серьезное и полезное. Я попробую показать, что в этом нет ничего сложного. Человек установивший на своем компьютере Linux или другую Unix подобную систему чувствует себя немного хакером, ну а какой хакер без сниффера, основного «инструмента» анализа системы. В данной статье приведен алгоритм работы сниффера, основанного на библиотеке libpcap. Библиотека присутствует во всех дистрибутивах Linux, поэтому не буду приводить здесь процесс установки этой библиотеки и не буду расписывать все ее возможности, так как это выходит за рамки данной статьи.

Ниже приведен примерный алгоритм работы сниффера:

1.Определяем все доступные интерфейсы, для чего используем функцию pcap_findalldevs(&a, errbuf), в качестве аргументов функции передается ссылка на специальную структуру pcap_if_t и указатель на буффер errbuf[PCAP_ERRBUF_SIZE] типа char. В первую переменную заносятся сведения о всех найденных интерфейсах, во второй параметр заноситься описание ошибки,
если по каким либо причинам нам не удалось получить сведения об интерфейсах.



. . .


pcap_if_t* alldevs;
char errbuf[PCAP_ERRBUF_SIZE];
printf("Start capturing packets ...\n");

if (pcap_findalldevs(&alldevs, errbuf)==-1) {
printf("Error in pcap_findalldevs:%s\n",errbuf);
}



2.Далее мы выбираем интерфейс с которым будем работать, следует отметить, что в списке доступных интерфейсов присутствует интерфейс с именем any, в том случае если мы будем использовать этот интерфейс, будут прослушиваться все
доступные интерфейсы.




. . .
d=alldevs;
if ((fp=pcap_open_live(d->name,65536,1,1000,errbuf))==NULL){
printf("\nUnable to open the adapter. \n");
return 2;
} else {
printf("Start sniffing on %s\n",d->name);



Выбор интерфейса для прослушивания аналогичен открытию файла, только для данной операции мы будем использовать
функцию pcap_open_live. Данная функция имеет четыре параметра



1. имя интерфейса, представляет собой
обыкновенную переменную типа char*, как правило имя интерфейса можно получить из структуры типа pcap_if_t,
что и было сделанно в нашем примере.



2. Второй параметр это размер пакета, который будет захвачен, в данном случае 64К



3. Третий параметр, установленный в 1 указывает на то, что интерфейс будет работать вpromisc режиме.



4.Четвертый параметр это тайм-аут по чтению



5. Ну и последний параметр уже знакомый нам errbuf, куда будет занесено сообщение об ошибке. 


Функция возвращает указатель на структуру типа pcap_t, которая в данном случае будет аналогично дескриптору открытого
файла, либо NULL, если, что то пошло не так при открытии интерфейса.



3. Далее мы открываем файл дампа, куда будем заносить все перехваченные нами пакеты. Формат записей, которые буду
заноситься в наш файл, совпадает с форматом данных утилиты tcpdump, таким образом можно в дальнейшем, полученный
нами файл использовать с этой утилитой для анализа перехваченных пакетов. Первое что мы сделаем, это опишем
переменную, которую будем использовать как дескриптор нашего файла дампа

pcap_dumper_t *dump;

затем откроем сам файл на запись данных:




dump=pcap_dump_open(fp,"dump.log");
if (dump==NULL) {
  printf("Error in open file dump.log\n") ;
  pcap_close(fp);
  return 3;
}
    


4. И теперь, после всех проведенных предварительных действий, мы можем приступить к захвату и обработке пакетов, проходящих
через прослушиваемый нами интерфейс.
В библиотеке libpcap, как и в ее аналоге для Windows систем winpcap, существует целый набор функций, который позволяет записывать и обрабатывать полученную при прослушивании
информацию. В качестве примера воспользуемся самым примитивным
случаем. С помощью функции pcap_next будем перехватывать пакеты и обрабатывать их в цикле. в качестве
параметров функции pcap_next передается дескриптор прослушиваемого интерфейса и ссылка на специальную структуру типа pcap_pkthdr. Функция возвращает значение типа
unsigned char*.




. . .
j=0;


while((pkt_data=pcap_next(fp,header))!=NULL){
  pcap_dump((unsigned char*)dump, header, pkt_data);
  ethh=(struct ether_header*) pkt_data;
  if (ntohs(ethh->ether_type)==ETHERTYPE_IP){
    ip = (struct ip*)(pkt_data+ETH_H);
    if (ip->ip_p==0x06){
      tcp = (struct tcphdr*)(pkt_data+ETH_H+IP_H) ;
      printf("TCP packet %s:%d ->
",inet_ntoa(ip->ip_src),ntohs(tcp->source));
      printf("%s:%d\n\n",inet_ntoa(ip->ip_dst),ntohs(tcp->dest));
      printf("%d -> Get tcp
packet\n",j);
    }
  }

  if (j++>100) break ;
}
pcap_close(fp);
pcap_dump_close(dump); 



Поскольку программа разрабатывалась в качестве примера, поэтому никаких особых действий она не делает. Просто в цикле
перехватывается 100 пакетов, затем они заносятся в файл. Одновременно происходит анализ заголовков нескольких уровней сетевой модели, сначала  ethernet пакета, затем ip пакета и наконец tcp пакета. После чего определяется тип ip пакета и если это tcp пакет, выводиться адрес и порт источника и назначения.

В процессе написания примера были использованы:
SDK winpcap и пример из статьи в журнале "Хакер" #56 за 2003 год.

Комментариев нет:

Отправить комментарий