[ Pomyślałem, że umieszcze to tu, może komuś się przyda, chociaż niektórzy to już widzieli, jest to już stare ]
Sniffer w cpp z wykorzystaniem libpcap
Biblioteka libpcap pozwala na przechwytywanie pakietów, pracę w trybie PROMISC, ogólnie będzie odpowiedzialna za całą brudną robotę związaną z naszym snifferem.
Instalacja.
No więc musimy zainstalować potrzebne pakiety:
Kod:
aptitude install libpcap0.8 libpcap-dev
Każdy instaluje sposobem według uznania, można skompilować ze żródeł.
A więc nasz sniffer podzielimy na dwa moduły, części. Pierwszy będzie odpowiedzialny za przygotowanie karty sieciowej do nasłuchu, zainstalowaniu filtrów, oraz uruchomi funkcję przechwytującą pakiety. Moduł drugi będzie to funkcja obsługująca każdy złapany pakiet z osobna. Funkcja prowadząca nasłuch (ta z modułu pierwszego) będzie uruchamiała funkcję z modułu drugiego dla każdego odebranego pakietu. Tak więc eksperymentować najlepiej jest na funkcji obsługującje pakiety.
A więc kod modułu pierwszego wraz z komentarzami.(tą część lepiej zostawić w spokoju).
Kod:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <pcap.h> //tutaj mamy plik nagłówkowy biblioteki
void packet_handler(u_char* param,const struct pcap_pkthdr* header,const u_char* pkt_data);
//deklaracja procedury odpowiedzialnej za obsługę pakietu
//jej implementacja będzie później
//przyjmujemy założenie, że pierwszym argumentem będzie nazwa urządzenia (eth0, ath0), a drugim filtr
// oczywiście jeżeli filtr będzie wielowyrazowy ujmujemy go w apostrofy, np. 'ip and tcp', 'tcp and port 80'
int main(int argc,char* argv[])
{
if(argc<3)
{
printf(" Uzycie: %s <urzadzenie> <filtr>.\n",argv[0]);
exit(1);
}
char* dev=argv[1]; nazwa urzadzenia
pcap_t* fp;
char errbuf[PCAP_ERRBUF_SIZE]; //jeżeli będziemy chcieli obsługiwać błędy
int res;
u_int netmask,ip_addr;
struct bpf_program fcode;
char* packet_filter=argv[2];
if(pcap_lookupnet(dev,&ip_addr,&netmask,errbuf)==-1)
{
printf("Nie można uzyskać maski: %s\n",errbuf);
ip_addr=0;
netmask=0;
}
//otwieramy urządenie
if((fp=pcap_open_live(dev,65536,1,1000,errbuf))==NULL)
{
printf("Nie można otworzyć urządzenia: %s\n",errbuf);
exit(1);
}
//kompilacja filtra
if(pcap_compile(fp,&fcode,packet_filter,0,netmask)<0)
{
printf("Składnia filtru jest niepoprawna.\n");
pcap_close(fp);
exit(1);
}
//ustawienie filtra
if(pcap_setfilter(fp,&fcode)<0)
{
printf("Blad podczas ustawiania filtru.\n");
pcap_close(fp);
exit(1);
}
printf("\n\nNasłuchiwanie na %s.\n\n"dev);
pcap_loop(fp,0,packet_handler,NULL); //i to jest funkcja przechwytująca pakiety
// i wysyłająca je do procedury packet_handler
//zakończy się gdy wciśniemy Ctrl+C
pcap_close(fp);
return 0;
}
Ok, główna część programu jest utworzona, teraz przejdziemy do części trudniejsze i ciekawszej, czyli do implementacji funkcji packet_handler.
Właśnie w tej procedurze będziemy rozpoznawali protokół odczytywali adres ip, numer portu itp
Jak pokażę tylko jak rozpoznać adres ip źródłowy i docelowy, myślę, że wstawienie dodatkowych opcji będzie łatwe. sam zrobiłem rozpoznawanie wiadomości ICMP
No to lecimy dalej z kodem
Kod:
// nagłówek IP
// jakby ktoś chciał to może poszukać sobie gotowca w źródłach systemu
struct ipheader
{
unsigned char ip_hl:4,ip_v:4;
unsigned char ip_tos;
unsigned short int ip_len;
unsigned short int ip_id;
insigned short int ip_off;
unsigned char ip_ttl;
unsigned char ip_p;
unsigned short int ip_sum;
unsigned int ip_src;
unsigned int ip_dst;
};
//chyba nie muszę tłumaczyć budowy nagłówka IP?
//jakby ktoś nie wiedział to jest wikipedia
void packet_handler(u_char* param,const struct pcap_pkthdr* header,const u_char* pkt_data)
//jako trzeci parametr otrzymujemy cały pakiet, pozostałe dwa - nie wiem co oznaczają
{
ipheader* ih;
char sourceIP[16],destIP[16];
sockaddr_in source_addr,dest_addr;
ih=(struct ipheader*)(pkt_data+14); //pomijamy 14 bajtów zarezerwowane dla nagłówka ethernet
//z góry zakładan, że to ethernet, chyba mało z was ma token ring czy FDDI
source_addr.sin_addr.s_addr=ih->ip_src;
dest_addr.sin_addr.s_addr=ih->ip_dst;
strncpy(sourceIP,inet_ntoa(source_addr.sin_addr),16);
strncpy(destIP,inet_ntoa(dest_addr.sin_addr),16);
//właśnie uzyskaliśmy adresy IP, teraz można je wyświetlić
printf("%-16s >> %-16s\n",sourceIP,destIP);
}
No i teraz najważniejsza rzecz - kompilacja
Kod:
g++ sniffer.cpp -o sniffer -lpcap
uruchamiać na konce root!!! Przykład
Kod:
./sniffer ath0 'tcp and port 8074'
Dalsze eksperymenty
No więc najlepiej jest dodawać nowe rzeczy do procedury packet_handler. Tam możemy odczytać z pakietu interesujące dane. Przyda się wiedza o budowie protokołów sieciowych.
No i teraz możecie napisać sniffer gg, łapacz haseł, nawet aplikację do pasywnego rozpoznawania systemu.
Uwaga: kod całkowicie został napisany własnoręcznie więc mogą występować błędy. Jakby ktoś miał jakiś problem - pisać.