Paweł Pokrywka
Testowanie zabezpieczeń sieci lokalnych pod względem nieupoważnionego dostępu na poziomie warstw 2-3 OSI.

Spis treści

1
 1.1Obszar zainteresowania
 1.2Uwierzytelnianie użytkowników
 1.3Metody nadużyć w sieci LAN
 1.3.1Podszywanie się
 1.3.2Bierne podsłuchiwanie
 1.3.3ARP Spoofing
 1.3.4MAC Flooding
 1.3.5Fałszywy serwer DHCP
 1.3.6Przekierowania ICMP
 1.3.7Resetowanie połączeń
2
 2.1Podsłuchiwanie sieci
 2.2Wstrzykiwanie danych do sieci
 2.3Koncepcja wirtualnych interfejsów tun/tap
 2.4Translacja adresów NAT
3
 3.1Interfejsy i protokoły
 3.2netdb
 3.3Zmiana adresów MAC
 3.3.1rx i tx
 3.3.2tapio
 3.3.3cmac
 3.4Monitorowanie sieci
 3.4.1scanarp
 3.4.2deta
 3.5Testowanie i równoważenie obciążenia
 3.5.1conncheck
 3.5.2natman
 3.6Skrypt multispoof
4
 4.1Pomiar maksymalnej przepustowości
 4.2Pomiar wydajności w warunkach typowych
5
 5.1Metody reaktywne
 5.1.1Wykrywanie skanowania ARP
 5.1.2Wykrywanie testowania łączności
 5.1.3Standardowe transmisje
 5.1.4Skanowanie i monitorowanie hostów
 5.1.5Hosty pułapki
 5.1.6Korelacja transmisji sieciowych
 5.1.7Moment pojawienia się hosta w sieci
 5.1.8Analiza wykorzystania portów przełączników
 5.2Środki prewencyjne
 5.2.1Zagłuszanie
 5.2.2Model dostępu do usługi w sesjach
 5.2.3Autoryzujące serwery proxy
 5.2.4Portale i Authpf
 5.2.5VPN
 5.2.6Metody pomocnicze
 5.2.7Inteligentne przełączniki sieciowe
6
 6.1Utrudnianie wykrywania
 6.1.1Randomizacja
 6.1.2Symulacja normalnej aktywności
 6.1.3Kontrola wykorzystania adresów
 6.1.4Antyradar
 6.2Przełamywanie innych metod uwierzytelniania
 6.2.1Metody warstwy trzeciej
 6.2.2Wykorzystywanie danych uwierzytelniających
 6.2.3Metody dodatkowo zabezpieczone
 6.3Wydajność, wygoda, kontrola
 6.3.1Tryby pracy
 6.3.2Statystyki
 6.3.3Inne poprawki
 6.4Detekcja przełamywania innych metod uwierzytelniania
 6.4.1Wykorzystywanie usługi wspólnie z użytkownikiem
 6.4.2Przechwytywanie danych umożliwiających dostęp
A
 A.1Skrypt multispoof
 A.2Skrypt generujący ruch sieciowy
B
 B.1Wymagania
 B.2Kompilacja i instalacja
 B.3Obsługa

Wstęp

Podstawę funkcjonowania każdego społeczeństwa stanowi komunikacja we wszelkich odmianach. Najważniejszą i najpopularniejszą jej formą jest mowa i związany z nią język ludzki, będący jedną z pierwszych umiejętności, które zdobywa jednostka.

Wraz z rozwojem cywilizacyjnym komunikacja ewoluowała, co objawiało się w szczególności rozwojem metod przekazywania informacji na odległość. Plemiona afrykańskie używały w tym celu sygnałów dźwiękowych wydawanych przez potężne bębny, Indianie korzystali z systemu znaków dymnych, zaś Rzymianie za pomocą umieszczonych na wzgórzach luster przesyłali impulsy świetlne. W 1838 roku został zbudowany telegraf elektryczny wykorzystujący alfabet Morse'a1), co stało się podwaliną współczesnej telekomunikacji.

Obecnie informacje przesyłane są przez nowoczesne trakty cyfrowe, które pozwalają na szybką transmisję danych na duże odległości. Systemy komputerowe, które jeszcze kilkadziesiąt lat temu z reguły pracowały w izolacji, dziś łączone są w sieci umożliwiające współdzielenie zasobów. Telekomunikacja i informatyka stały się wzajemnie zależne, co zaowocowało powstaniem teleinformatyki, czyli nauki łączącej te dziedziny wiedzy.

Tematem niniejszej pracy są lokalne sieci komputerowe oraz ich bezpieczeństwo, ze szczególnym naciskiem na problem uwierzytelniania. Program komputerowy, który powstał w jej ramach, pozwala na demonstrację słabości najpopularniejszej metody zabezpieczania tego typu sieci przed nieupoważnionym dostępem.

Praca została podzielona na rozdziały. Podział ten przedstawia się następująco:
Rozdział 1
ma za zadanie wprowadzić czytelnika w tematykę tzw. sieci osiedlowych oraz problemy bezpieczeństwa w nich występujące.
Rozdział 2
zawiera przegląd technologii sieciowych wykorzystywanych w aplikacji multispoof, która powstała w ramach pracy.
Rozdział 3
przedstawia koncepcję aplikacji multispoof, a następnie koncentruje się na architekturze programu oraz problemach implementacyjnych.
Rozdział 4
zawiera analizę zachowania aplikacji podczas działania, wraz z wynikami przeprowadzonych testów.
Rozdział 5
stanowi opis metod wykrywania nieupoważnionego dostępu do sieci oraz środków, które pozwalają ją przed tym zabezpieczyć.
Rozdział 6
przedstawia kierunki dalszego rozwoju aplikacji, które dotyczą utrudniania detekcji, przełamywania innych typów zabezpieczeń oraz zwiększania wydajności i wygody użytkowania.
Dodatek A
zawiera dwa listingi: skryptu multispoof oraz skryptu używanego w testach.
Dodatek B
stanowi zbiór informacji niezbędnych w procesie kompilacji oraz instalacji programu multispoof. W dodatku zawarta jest także instrukcja obsługi, oraz analiza przykładowej sesji aplikacji.

Konwencje i oznaczenia

W celu ułatwienia czytania zostały wprowadzone konwencje typograficzne. Narzędzia, biblioteki i pakiety oprogramowania pisane są czcionką o stałej szerokości, zaś komponenty aplikacji multispoof są dodatkowo pogrubione. Czcionka o stałej szerokości jest używana także w listingach oraz sesjach powłoki systemowej. Te fragmenty, na które należy zwrócić szczególną uwagę lub stanowią komendy wpisywane przez użytkownika, są pogrubione. Zbiór oznaczeń graficznych, używany jest konsekwentnie na większości rysunków. Adresy URL, z których można pobrać wykorzystywane narzędzia podawane są w przypisach, najczęściej z krótką informacją o funkcjonalności danego programu.

Podziękowania

Praca niniejsza powstała w dużej mierze dzięki pomocy wielu życzliwych osób, którym należą się słowa podziękowania.

W pierwszej kolejności chcę wyrazić wdzięczność dr Tomaszowi Surmaczowi za owocną współpracę.

Pragnę serdecznie podziękować moim rodzicom, Krystynie i Janowi Pokrywkom za wszelką pomoc, której nie jestem w stanie opisać, ani wyliczyć.

Za pomoc przy rozwiązywaniu problemów podczas pisania aplikacji, dziękuję Michałowi Pokrywce. Za cierpliwość, cenne dyskusje, wskazówki i pożyteczne uwagi chcę podziękować Krzysztofowi Noskowi, Przemysławowi Plata oraz moim braciom Piotrowi i Przemysławowi Pokrywkom. Chcę także wyrazić wdzięczność wszystkim osobom, tworzącym oprogramowanie, które wykorzystywałem podczas pisania niniejszej pracy oraz aplikacji multispoof.

I would like to thank especially Guy Harris from tcpdump project for help with libpcap patch inclusion, and John Bothe for initial patch code.

Rozdział 1: Problem uwierzytelniania w sieciach LAN

“The enemy knows the system being used.”
–  Claude Shannon

W tym rozdziale zostanie przedstawiona koncepcja sieci LAN, zagrożenia jakie w nich występują oraz praktyczne problemy, związane z ich wykorzystaniem przez intruzów. Główny nacisk zostanie położony na omówienie popularnego sposobu uwierzytelniania użytkowników sieci, którego słabości będą zademonstrowane praktycznie w następnych rozdziałach.

1.1 Obszar zainteresowania

Ze względu na fakt, że tematyka sieci lokalnych to szeroki zakres dziedziny IT, jaką są sieci komputerowe, należy uściślić obszar zainteresowania tej pracy. Są nim lokalne sieci komputerowe, zbudowane z wykorzystaniem technologii Ethernet [Net99 ] lub pochodnych i wykorzystywane do płatnego świadczenia usługi dostępu do Internetu. Dotyczy to tzw. sieci osiedlowych, zarówno amatorskich (non-profit) jak i profesjonalnych. Te pierwsze są zarządzane przez osoby, które nie są zainteresowane zyskiem, zaś opłaty pobierane od korzystających z sieci są w całości przeznaczane na zwrot kosztów jej utrzymania. W przeciwieństwie do nich, sieci profesjonalne są własnością firm (nazywanych operatorami lub dostawcami usługi dostępu do Internetu), które opierają swoją działalność na przychodach uzyskiwanych z abonamentu.

Głównym powodem tego, że sieci osiedlowe istnieją i rozwijają się, jest niska cena infrastruktury ethernetowej w zakresie instalacji i utrzymania. Urządzenia wchodzące w skład takiej sieci są łatwo dostępne i tanie, w przeciwieństwie do sprzętu niezbędnego w innych rozwiązaniach szerokopasmowych, jak technologia DSL2) czy telewizja kablowa3). Na infrastrukturę osiedlowego Ethernetu składają się najczęściej tylko trzy rodzaje elementów: przełączniki sieciowe, kable miedziane lub światłowody oraz karty sieciowe w komputerach. Dostęp do Internetu zapewnia router, który w mniejszych sieciach bywa implementowany na zwykłym, niedrogim komputerze klasy PC.

1.2 Uwierzytelnianie użytkowników

Dostęp do Internetu jest udzielany użytkownikom, którzy uregulowali należności finansowe. Natomiast klienci, którzy zalegają z opłatami powinni tracić dostęp do usługi, najlepiej w dniu przekroczenia terminu płatności. Najpewniejszą metodą odcięcia użytkownika od sieci jest wyłączenie z najbliższego przełącznika kabla, który do niego prowadzi. Jest to jednak kłopotliwe, ponieważ wymaga wykonania pracy fizycznej, zaś przełączniki sieciowe często instalowane są w miejscach trudno dostępnych, jak piwnice, strychy, słupy lub mieszkania osób prywatnych. Dodatkowo, niektórzy dostawcy sieci osiedlowych zezwalają także na bezpłatny lub obciążony mniejszą opłatą dostęp do zasobów sieci lokalnej, pod warunkiem niekorzystania z Internetu.

Dlatego najczęstszą praktyką jest blokowanie komputera klienta na poziomie logicznym w tej sposób, że nie traci on dostępu do sieci LAN, natomiast łączność z Internetem jest zawieszana. W praktyce polega to na odfiltrowywaniu danych, płynących z komputera użytkownika w kierunku globalnej sieci i vice versa. Wymaga to jednak odpowiedzi na pytanie:
Jak powiązać transmisje przepływające przez router operatora z człowiekiem, którego komputer je wygenerował4)?
Odpowiedzią jest proces uwierzytelniania. Aby uzyskać dostęp do usługi, komputer użytkownika musi przedstawić się, wykorzystując do tego informacje uzgodnione wcześniej między jego właścicielem i operatorem sieci.

Jeśli hosty w sieci są uwierzytelnione, oznacza to, że jest możliwe ich rozróżnienie, co w efekcie pozwala na oferowanie spersonalizowanych usług przez dostawcę. Takimi usługami są na przykład możliwość wyboru przepustowości dostępu do Internetu przez klienta, blokowanie niepożądanych treści, dostęp do informacji billingowych, ogłoszenia i reklamy.

Najpopularniejsza metoda uwierzytelniania w sieciach osiedlowych wykorzystuje to, że każdy komputer posiada kartę sieciową, zaś każda karta ma przypisany przez producenta unikalny adres sprzętowy MAC (ang. Medium Access Control). Na jego podstawie serwer DHCP5), stanowiący część infrastruktury sieciowej, przydziela mu adres IP, który jest wymagany do komunikacji. Ponieważ serwery DHCP najczęściej konfigurowane są w ten sposób, że dla danego adresu MAC przydzielają zawsze ten sam adres IP, zaś użytkownicy rzadko wymieniają karty sieciowe, adres ten może być wykorzystywany do uwierzytelniania.

Najczęściej router, który zapewnia dostęp do Internetu, jest konfigurowany tak, aby w procesie uwierzytelniania brały udział oba adresy: sprzętowy oraz IP. Dzieje się tak, ponieważ ten drugi adres użytkownik może w trywialny sposób zmienić, zaś weryfikacja zgodności obu adresów pozwala na wykrycie tego typu oszustwa. Mimo tego, autorowi znane są sieci osiedlowe, które nie stosują nawet tego, podstawowego zabezpieczenia.

1.3 Metody nadużyć w sieci LAN

Niski koszt sieci Ethernet, prostota jej instalacji oraz wysoka elastyczność użytkowania są niestety okupione podatnością na wiele ataków, obniżających jej bezpieczeństwo zarówno w sensie poufności i integralności transmisji, jak i dostępności. Wydaje się, że głównymi źródłami tych problemów są protokół ARP oraz technika dynamicznego przełączania ramek.

1.3.1 Podszywanie się

W sieciach Ethernet opartych na popularnych, tanich przełącznikach lub koncentratorach istnieje niebezpieczeństwo podszycia się poprzez zmianę adresu. Możliwe jest to zarówno w warstwie trzeciej modelu OSI, poprzez zmianę numeru IP6), jak i w warstwie drugiej poprzez zmianę adresu MAC. W popularnych systemach operacyjnych modyfikacja tego drugiego jest równie prosta jak pierwszego. Jednak zmiana adresu MAC stanowi z pewnych względów wiedzę tajemną, dostępną tylko wybranym7). Rozpowszechniony jest natomiast pogląd, że adres MAC, tzw. adres sprzętowy jest zapisany na stałe w urządzeniu i nie ma możliwości wpływu na jego wartość poza wymianą karty sieciowej.

Adres MAC jest faktycznie zapisany w pamięci karty, ale zazwyczaj ta pamięć pozwala na zmianę jej zawartości. Prostszą metodą jest jednak programowa zmiana adresu na poziomie sterownika karty sieciowej w systemie operacyjnym. Wreszcie wysyłanie ramek ethernetowych ze sfałszowanym adresem źródłowym jest możliwe także w przestrzeni użytkownika za pomocą odpowiednich bibliotek i interfejsów udostępnianych przez jądro. Więcej informacji na temat generowania ramek z poziomu aplikacji zostało zamieszczonych w podrozdziale 2.2.

Zmiana adresu MAC na adres komputera innego użytkownika, który jest w danej chwili nieaktywny powoduje, że serwer DHCP przydziela jego adres IP i dostęp do Internetu odbywa się w cudzym imieniu. Jest to kradzież usługi, przed którą operator sieci osiedlowej powinien się zabezpieczyć.

1.3.2 Bierne podsłuchiwanie

Sieci oparte na koncentratorach są podatne na podsłuchiwanie, ponieważ urządzenia te przesyłają otrzymane ramki na wszystkie porty (rysunek 1.1). Pozwala to atakującemu na dostęp do informacji przesyłanych w obrębie segmentu sieci, do którego on należy. Narzędzia do podsłuchiwania popularnie nazywane są snifferami. Najbardziej znanym programem tego typu jest tcpdump8). Podsłuchiwanie jest techniką, która obecnie ma coraz mniejsze znaczenie, ze względu na wypieranie koncentratorów przez przełączniki. W sieciach przełączanych efekty biernego podsłuchiwania są znikome. Jednak podsłuchiwanie nadal jest wykorzystywane przez intruzów w połączeniu z innymi metodami. Więcej o tym można przeczytać w podrozdziale 2.1.


          Przepływ ramek przez koncentrator sieciowy.
Rysunek 1.1: Przepływ ramek przez koncentrator sieciowy.

1.3.3 ARP Spoofing

Jest to najbardziej znany typ ataku na sieci lokalne, wykorzystujący słabości protokołu ARP [Gusta i Szmit 2003]. Protokół ten jest używany do mapowania numerów IP na adresy MAC, czyli łączy warstwę trzecią z warstwą drugą, umożliwiając tym samym komunikację w sieci fizycznej. Każdy host w sieci posiada lokalną tablicę ARP. Jeśli wystąpi potrzeba wysłania danych do innego hosta o znanym adresie IP w tym samym segmencie sieci lokalnej, tablica ta jest przeglądana w celu odnalezienia odpowiadającego mu adresu MAC. W przypadku, gdy tablica nie zawiera wpisu dla poszukiwanego adresu IP, system operacyjny wysyła do wszystkich komputerów w sieci lokalnej komunikat ARP Request, z zapytaniem o adres MAC tego hosta. Jeśli w danej chwili komputer o poszukiwanym adresie IP jest obecny w sieci, to wysyła komunikat ARP Reply do hosta, który wysłał zapytanie. Odpowiedź zawiera jego adres MAC, co pozwala na uaktualnienie tablicy ARP i dalszą transmisję.

Atak ARP Spoofing9) polega na wprowadzaniu modyfikacji do tablic zdalnych hostów, wykorzystując do tego sfałszowane komunikaty ARP10). Na przykład atakujący wprowadza swój adres MAC w miejsce adresu hosta B w tablicy komputera A, oraz w miejsce adresu hosta A w tablicy komputera B. Dodatkowo komputer oszusta zmienia adres źródłowy ramek pochodzących od A na swój i przesyła je do B. Tak samo postępuje w przypadku ramek otrzymywanych od B. Komputery A i B mają wrażenie, że komunikują się bezpośrednio, ale w rzeczywistości cały ruch przechodzi przez komputer atakującego (rysunek 1.2). Daje to intruzowi następujące możliwości:
Podsłuchiwanie aktywne.
Atak ARP Spoofing pozwala na przeprowadzanie podsłuchiwania w sieciach przełączanych.
Ingerencja w transmisje.
Atakujący może modyfikować wybrane elementy ruchu, co nazywane jest atakiem z wnętrza systemu (ang. Man in the Middle).
Uniemożliwianie transmisji.
Efekt ten wystąpi, jeśli atakujący zaprzestanie przesyłania ramek pomiędzy obydwoma hostami. Jeśli atak ten będzie dotyczył routera, to spowoduje on odmowę usługi dostępu do Internetu (ang. Denial of Service).

          Koncepcja ataku ARP Spoofing.
Rysunek 1.2: Koncepcja ataku ARP Spoofing.

1.3.4 MAC Flooding

Sieć ethernetowa może zostać zalana (ang. flooding) ramkami generowanymi przez komputer atakującego11). W zależności od metody nadawania adresów źródłowych ramkom, można uzyskać dwa poniższe efekty:
  • Jeśli ramki mają losowe adresy źródłowe, to tablice MAC przełączników po krótkim czasie ulegają przepełnieniu, co prowadzi do tego, że przechodzą one w tryb koncentratora. Efektem jest zdegradowanie sieci przełączanej do poziomu współdzielonego medium, co pozwala np. na bierne podsłuchiwanie.
  • Jeżeli ramki generowane przez atakującego mają adres źródłowy równy adresowi hosta ofiary, to pamięć przełączników ulegnie przeprogramowaniu. Ruch, który płynął do tego hosta, zmieni kierunek, i popłynie do komputera intruza. Spowoduje to, że ofiara nie otrzyma danych, na które oczekiwała, natomiast otrzyma je atakujący.
Takie zachowanie sieci wynika ze sposobu działania składających się na nią przełączników. Zapisują one w swojej pamięci numer portu fizycznego i adres źródłowy ramek, które na nim się pojawiają. Te asocjacje są następnie używane w celu wyboru portu, przez jaki mają być wysyłane dalsze ramki.

1.3.5 Fałszywy serwer DHCP

Jeśli hosty w sieci są skonfigurowane w ten sposób, że pobierają ustawienia sieciowe z serwera DHCP, to atakujący może uruchomić drugi, konkurencyjny serwer, który będzie przydzielał komputerom użytkowników inne ustawienia. Atakujący może w ten sposób wymusić na komputerach, aby przesyłały ruch internetowy do jego maszyny, zamiast do routera. Manipulując wartością maski sieciowej, może także spowodować, że nawet transmisje lokalne będą kierowane do niego. Atakujący uzyskuje wtedy pełną kontrolę nad ruchem, tak jak w przypadku ataku ARP Spoofing.

Inną możliwością jest zmiana adresu serwera DNS na adres maszyny kontrolowanej przez atakującego. Fałszywy serwer DNS natomiast będzie przekierowywał wybrany ruch na host oszusta, który znów przejmuje nad nim pełną kontrolę.

Atakujący może też selektywnie blokować hosty w sieci przez przydzielanie nieprawidłowych adresów, co skutkuje efektem odmowy usługi.

1.3.6 Przekierowania ICMP

Jeśli host próbuje wysyłać pakiety IP przez router, zaś ten posiada informacje o lepszej trasie, prowadzącej przez bramę znajdującą się w tej samej sieci, to router wysyła do hosta komunikat ICMP Redirect. W komunikacie zawarta jest informacja o adresie routera, którego host powinien użyć aby wysyłane przez niego pakiety trafiły do miejsca przeznaczenia.

Komunikaty te mogą być wysyłane także przez atakującego w celu przekierowania ruchu hosta do kontrolowanej przez niego maszyny12). Maszyna ta uzyskuje pełną kontrolę nad ruchem hosta, zaś efekty są podobne jak w przypadku ataku ARP Spoofing.

1.3.7 Resetowanie połączeń

Jeśli ataki zapewniające kontrolę nad transmisją nie są wykonalne, zaś celem atakującego jest uniemożliwienie komunikacji w sieci to może posunąć się do prób resetowania połączeń. Polega to na wstrzykiwaniu do sieci pakietów, które służą do awaryjnego zawieszania połączeń TCP i transmisji UDP13). W przypadku protokołu TCP są to segmenty z ustawioną flagą RST, zaś przerywanie połączeń UDP odbywa się z wykorzystaniem komunikatów ICMP Unreachable. Pakiety resetujące wymagają podstawowych informacji o połączeniu jak adresy i porty źródłowe oraz przeznaczenia, a także numery sekwencyjne dla połączeń TCP. Dlatego ten atak jest najbardziej efektywny w połączeniu z podsłuchiwaniem ruchu sieciowego. Z przechwyconego ruchu atakujący wybiera te połączenia, które chce zakończyć.

Inną metodą jest zgadywanie części danych opisujących połączenie, o którym pozostałe informacje są znane. Na przykład jeśli atakujący wie, że dany host ustanowił długotrwałą sesję z innym hostem wykorzystując protokół FTP, to generuje pakiety resetujące z wszystkimi możliwymi kombinacjami portów źródłowych i numerów sekwencyjnych14). Pozostałe dane jak adresy IP i numer portu docelowego, są znane.

Rozdział 2: Wykorzystywane technologie

“There are only 10 types of people in this world. Those who know binary, and those who don't.”
–  autor nieznany

Aby czytelnik mógł świadomie korzystać z programu multispoof, a także aby zrozumieć jego budowę, musi znać podstawowe technologie, wykorzystywane przez tę aplikację. W tym rozdziale zostaną przybliżone cztery najważniejsze. Zakłada się, że czytelnik posiada ogólną wiedzę na temat systemu GNU/Linux, jego administracji oraz zasad funkcjonowania lokalnych sieci komputerowych wykorzystujących protokół IP [Hunt 1997] [Bautts et al. 2005] [Russell 2001].

2.1 Podsłuchiwanie sieci

Podsłuchiwanie sieci LAN to proces polegający na odbieraniu wszystkich danych, które pojawiają się na interfejsie sieciowym, w formie ramek ethernetowych. Ramki odebrane przez sterownik karty sieciowej są przesyłane równolegle do programu lub programów nasłuchujących oraz do stosu sieciowego w systemie operacyjnym, dlatego proces nie zaburza normalnego funkcjonowania aplikacji korzystających z sieci. Dodatkowo, jeśli karta sieciowa znajduje się w trybie promiscuous odbierane ramki nie podlegają filtrowaniu, które standardowo odbywa się w karcie. Domyślnie bowiem, karta sieciowa pozwala tylko na odbiór ramek o adresie docelowym zgodnym z adresem MAC karty oraz ramek rozgłoszeniowych i multicastowych15). Aplikacja nasłuchująca ma dostęp do warstwy drugiej i wyższych modelu OSI, co pozwala na odbiór informacji przenoszonych nawet przez protokoły, które nie są obsługiwane przez system operacyjny.

Podsłuchiwanie sieci wykorzystywane jest głównie w analizatorach pakietów, nazywanych snifferami. Znajdują one zastosowanie przy diagnozowaniu problemów oraz pomagają poznawać protokoły sieciowe. Funkcje przechwytywania informacji wysyłanych przez inne hosty są także wykorzystywane przez komputerowych włamywaczy np. w celu poznawania haseł.

Podsłuchiwanie w trybie promiscuous umożliwia analizę ruchu całej sieci, pod warunkiem, że jest ona oparta na koncentratorach. Sieci budowane z wykorzystaniem przełączników są bardziej odporne na bierne podsłuchiwanie16), jednak zastosowanie metod aktywnych w dalszym ciągu pozwala na przechwytywanie transmisji (zostało to wyjaśnione w podrozdziale 1.3.3). Niemniej aplikacja, która powstała w ramach pracy dyplomowej, nie wymaga przechwytywania transmisji innych hostów.

Programy, które wykorzystują podsłuchiwanie sieci, często nie potrzebują wszystkich ramek, które odbiera karta. Zazwyczaj wybierają z nich tylko te, które spełniają określone kryteria. W tym celu został opracowany filtr BPF (ang. Berkeley Packet Filter). Pozwala on na wstępną selekcję danych z wykorzystaniem prostego języka17). Program w tym języku jest optymalizowany, kompilowany i ładowany do jądra18). Droga ramki sieciowej od momentu nadania, do otrzymania przez aplikację podsłuchującą jest zobrazowana na rysunku 2.1. Zanim ramka dotrze do programu, może zostać odfiltrowana na przełączniku sieciowym (1), ze względu na to, że jej adres docelowy znajduje się już w pamięci przełącznika i jest skojarzony z portem innego hosta. Jeśli ramka dotrze do karty sieciowej hosta (2), karta nie znajduje się w trybie promiscuous, zaś adres docelowy MAC ramki nie pokrywa się z adresem karty ani nie jest adresem rozgłoszeniowym, wtedy karta odrzuci ramkę. W przeciwnym razie ramka jest analizowana przez program filtra BPF (3) i tylko jeśli spełni jego warunki zostanie dopuszczona do aplikacji.


        Droga ramki od momentu nadania do otrzymania
        przez ap...
Rysunek 2.1: Droga ramki od momentu nadania do otrzymania przez aplikację podsłuchującą ruch sieciowy.

2.2 Wstrzykiwanie danych do sieci

Wstrzykiwaniem określa się wysyłanie ramek ethernetowych bezpośrednio do sterownika karty sieciowej w systemie operacyjnym, czyli z pominięciem większości stosu sieciowego. Aplikacja w całości decyduje o zawartości ramki i może dowolnie określać wszystkie jej pola i dane protokołów wyższych warstw. Tak więc operacje, które nie są udostępniane przez system operacyjny, jak zmiana adresu źródłowego, wybranie docelowego adresu MAC i inne – są możliwe w trybie wstrzykiwania.

Podobną funkcjonalność oferują tzw. surowe gniazda sieciowe (ang. RAW sockets). Pozwalają one na generowanie z poziomu aplikacji dowolnych pakietów IP, które następnie są opakowywane przez jądro systemu w ramki protokołu warstwy drugiej modelu OSI [Al-Herbish 1999]. Zaletą surowych gniazd jest niezależność od medium transmisyjnego, natomiast wadą brak kontroli nad ramką.

Obie metody wysyłania danych są wykorzystywane głównie w aplikacjach do diagnozowania sieci oraz testowania i przełamywania zabezpieczeń.

2.3 Koncepcja wirtualnych interfejsów tun/tap

Interfejs tun jest zapewnianym przez jądro wirtualnym urządzeniem sieciowym typu punkt-punkt. Podobnie interfejs tap z tą różnicą, że oferuje on wirtualną kartę ethernetową. Oba typy interfejsów są dynamiczne, tzn. mogą być tworzone w dowolnej ilości i usuwane [Krasnyansky i Thiel 2002]. Utworzenie i komunikacja z interfejsem odbywa się odpowiednio przez otworzenie pliku urządzenia19) oraz odczyt i zapis do deskryptora z poziomu aplikacji. Dane które zostaną zapisane pojawią się na interfejsie tun jako pakiet IP, zaś na interfejsie tap jako ramka ethernetowa. Pakiet bądź ramka, która zostanie wysłana przez interfejs może być odczytana z deskryptora jako ciąg bajtów.

Interfejsy tun/tap są wykorzystywane zazwyczaj w tunelowaniu. Tunelowanie polega na przesyłaniu pakietów lub ramek, po wcześniejszej enkapsulacji w pakiety specjalnych protokołów komunikacyjnych. Po obu stronach tunelu znajdują się interfejsy tun/tap, dzięki czemu użytkownik odnosi wrażenie, że komunikuje się z drugą stroną przez dedykowane połączenie fizyczne. Tunelowanie jest z reguły używane w wirtualnych sieciach prywatnych (VPN) oraz zastosowaniach eksperymentalnych20).

Rysunek 2.2 przedstawia porównanie interfejsów wirtualnych tun/tap oraz interfejsów fizycznych. Interfejsy fizyczne nadają i odbierają dane do/z odpowiedniego medium transmisyjnego za pośrednictwem właściwego sprzętu sieciowego. Natomiast interfejsy wirtualne komunikują się z aplikacjami, znajdującymi się w przestrzeni użytkownika.


        Porównanie interfejsów wirtualnych i fizycznych.
Rysunek 2.2: Porównanie interfejsów wirtualnych i fizycznych.

2.4 Translacja adresów NAT

NAT (ang. Network Address Translation) to proces, który odbywa się zwykle na routerze sieciowym. Polega on na dynamicznym tłumaczeniu adresów pakietów IP. Najczęściej używany jest w celu zapewnienia dostępu do Internetu sieci, która używa prywatnego zakresu adresów IP21). W tym przypadku router natujący zmienia źródłowy adres IP każdego pakietu wychodzącego do Internetu na adres publiczny routera. Każdy pakiet powracający do sieci otrzymuje adres odpowiadający komputerowi, który zainicjował transmisję. Dzięki temu cała sieć może wykorzystywać jeden publiczny adres IP22).

NAT jest wykorzystywany także podczas równoważenia obciążenia pomiędzy kilka serwerów dysponujących pojedynczym adresem IP. Router równoważący obciążenie korzystając z translacji adresów może przypisywać kolejne połączenia do różnych serwerów, np. w zależności od ich obciążenia, podmieniając docelowy adres IP połączeń na adres konkretnego serwera, który znajduje się w sieci wewnętrznej. Dzięki temu użytkownicy korzystający z usług serwerów odnoszą wrażenie, że komunikują się z jednym hostem, zaś w rzeczywistości jest ich kilka.

Zasada działania NAT została zobrazowana na rysunku 2.3. Zaawansowane implementacje NAT23) umożliwiają tworzenie bardziej złożonych translacji niż wymienionego powyżej schematu jeden do wielu. Mogą to być wiele do wielu (adresy są odwzorowywane w liczniejszą lub mniej liczną pulę), jeden do jednego (pule adresów zewnętrznych i wewnętrznych są jednakowo liczne, odwzorowania są stałe). Możliwe jest także wykonywanie translacji warunkowej w połączeniu z listą filtrów systemu firewall [Strebe i Perkins 2000] [Russell 2002b].


        Sieć w której dostęp do Internetu jest zapewniany przez
     ...
Rysunek 2.3: Sieć w której dostęp do Internetu jest zapewniany przez router z translacją adresów.

Rozdział 3: Aplikacja multispoof

Master Foo once said to a visiting programmer: “There is more Unix-nature in one line of shell script than there is in ten thousand lines of C.”
–  Eric S. Raymond, Rootless Root [Raymond 2003]

Aplikacja multispoof która powstała w ramach pracy dyplomowej, ma na celu praktyczną demonstrację słabości najpopularniejszej metody uwierzytelniania w sieciach osiedlowych. Program pozwala na przełamywanie zabezpieczenia usługi dostępu do Internetu, które bazuje na sprawdzaniu zgodności adresów IP i MAC komputera użytkownika z danymi przechowywanymi w bazie operatora.

Aplikacja wykorzystuje podszywanie się pod nieaktywne hosty. W tym procesie fałszowane są adresy IP i MAC wysyłanych pakietów. Cechą odróżniającą działanie aplikacji od zwykłej zmiany adresu w systemie operacyjnym jest możliwość podszywania się pod wszystkie nieaktywne komputery jednocześnie. Wykorzystanie programu pozwala osiągnąć szybkość transmisji, mogącą równać się sumie przepustowości poszczególnych hostów, których adresy są wykorzystywane przez aplikację. Koncepcję działania programu przedstawia rysunek 3.1.


      Idea działania aplikacji multispoof w sieci lokalnej.
Rysunek 3.1: Idea działania aplikacji multispoof w sieci lokalnej.

Dodatkową funkcją programu jest samodzielne rozpoznawanie sieci i tworzenie listy komputerów, które będą mogły być później wykorzystane w procesie podszywania się. Aplikacja nieustannie monitoruje sieć i jeśli zauważy, że wykorzystywany w procesie podszywania się host staje się aktywny, to natychmiast przestaje używać jego adresu, aby nie powodować konfliktów.

Należy podkreślić, że aplikacja multispoof powstała w celach demonstracyjnych, zaś używanie jej bez zgody właściciela sieci jest równoznaczne z kradzieżą usługi, co jest niezgodne z prawem.

Wewnętrzna architektura aplikacji multispoof ewoluowała w trakcie jej implementacji. Początkowo aplikacja miała mieć postać jednego programu. Szybko jednak okazało się, że pojedynczy program byłby zbyt skomplikowany, dlatego część funkcji została umieszczona w osobnym programie. Liczba programów zwiększała się wraz z identyfikacją kolejnych zadań, które aplikacja miała wykonywać. Doprowadziło to do niemal całkowitej separacji do osobnych procesów zadań, które nie były ze sobą ściśle powiązane. Jednocześnie były opracowywane interfejsy, za pomocą których procesy komunikowały się ze sobą. Mają one prosty, tekstowy charakter, który jest czytelny dla człowieka. Separacja zadań i proste interfejsy to metody modularyzacji aplikacji, które wydatnie przyśpieszyły proces pisania kodu, testowania oraz znajdowania i usuwania błędów [Raymond 2003].

Na działanie aplikacji multispoof składają się trzy zasadnicze zadania:
  • Zmiana adresów MAC
  • Monitorowanie sieci
  • Testowanie i równoważenie obciążenia

Każde z zadań jest realizowane przez zbiór procesów, nazwanych komponentami. Komponenty wykonują proste, jednowątkowe operacje z wykorzystaniem dwóch typów interfejsów, które zostaną omówione w podrozdziale 3.1. W podrozdziale 3.2 przybliżony zostanie komponent netdb, który uczestniczy we wszystkich trzech zadaniach. Następne podrozdziały będą dotyczyć kolejnych zadań, oraz wykonujących je komponentów. Rozdział zakończy opis skryptu multispoof, odpowiedzialnego za przygotowanie środowiska, utworzenie zadań z poszczególnych komponentów po uruchomieniu, oraz zatrzymanie ich przed zakończeniem.

3.1 Interfejsy i protokoły

Interfejsy służą do jedno- lub dwustronnej komunikacji pomiędzy komponentami aplikacji multispoof z wykorzystaniem odpowiednich protokołów. Intencją przyświecającą ich budowie była prostota, dlatego dane wymieniane z ich wykorzystaniem mają postać tekstową. Decyzja ta wpłynęła na dużą elastyczność protokołów, co znacznie ułatwiało bieżącą ich rozbudowę podczas powstawania aplikacji. Oprócz tego forma tekstowa jest czytelna dla człowieka i daje się przetwarzać przy użyciu narzędzi uniksowych (np. grep, sed, awk). Są to pożądane cechy ułatwiające proces testowania oprogramowania.

Pierwszy typ interfejsu, nazwany tekstowym protokołem ramek, jest używany w potokach między komponentami przetwarzającymi ramki sieciowe. Interfejs jest jednokierunkowy. Pozwala na wysyłanie odpowiednio zakodowanych ramek, lub ich odbieranie za pośrednictwem standardowego wejścia i wyjścia. Protokół ten ma format liniowy, każda linia zawiera jedną ramkę. Bajty ramki kodowane są heksadecymalnie, najstarszy bajt pierwszy (Big Endian). Przykładową ramkę obrazuje rysunek 3.2.


        Przykładowy pakiet ICMP Echo Request zakodowany zgodnie
     ...
Rysunek 3.2: Przykładowy pakiet ICMP Echo Request zakodowany zgodnie z tekstowym protokołem ramki (dla czytelności złamany do kilku linii).

Drugi typ interfejsu, nazywany interfejsem lub protokołem netdb, służy do wykonywania zapytań do bazy adresów netdb (baza ta będzie opisana w następnym podrozdziale). Interfejs wykorzystuje lokalne gniazdo uniksowe24) i jest dwukierunkowy. Komponenty mogą wysyłać zapytania, zaś baza odsyła odpowiedzi.

Zapytania mają postać komend z parametrami rozdzielonymi białymi znakami. Odpowiedzi składają się z jednej lub więcej linii, z których ostatnia ma ustandaryzowany format, przedstawiony na rysunku 3.3. Jeśli odpowiedź składa się z więcej niż jednej linii, wszystkie oprócz ostatniej mają format specyficzny dla wydanej komendy.


        Schemat komunikacji pomiędzy komponentem klienckim i netdb.
 ...
Rysunek 3.3: Schemat komunikacji pomiędzy komponentem klienckim i netdb.

3.2 netdb

Zadaniem komponentu netdb jest umożliwienie dostępu do bazy adresów oraz zmiennych innym komponentom. Baza netdb jest używana niemal przez wszystkie inne procesy, działające w ramach aplikacji multispoof, z wyjątkiem tx, rxtapio. Z tego względu komponent netdb zostanie omówiony na początku.

Komunikacja z innymi komponentami aplikacji jest realizowana z wykorzystaniem lokalnego gniazda uniksowego, które jest tworzone po uruchomieniu programu. Korzystając z tego gniazda inne komponenty mogą wydawać komendy i odczytywać wyniki zgodnie z tekstowym protokołem netdb. Tabela 3.1 zawiera listę dostępnych komend wraz z krótkimi opisami. Wybrane komendy będą omówione szerzej w następnych podrozdziałach.

Tabela 3.1: Lista komend komponentu netdb.
Komenda Parametry Opis
gethostAdres IPWyświetla dane hosta: adres MAC, wartości czasowe oraz znaczniki.
hostAdres IP, MACDodaje lub modyfikuje dane hosta. Uaktualnia czas ostatniej aktywności.
removeAdres IPUsuwa dane hosta.
doAkcja, Adres IPUstawia flagi dla hosta. Możliwe akcje: enable, disable, start-test, stop-test.
dumpWyświetla listę adresów IP.
getvarNazwa zmiennejWyświetla zawartość zmiennej.
setvarNazwa zmiennej, wartośćUstawia wartość zmiennej.
quitKończy połączenie z netdb.

Program netdb jest jednowątkowym serwerem opartym na funkcji select. Architektura ta charakteryzuje się wysoką wydajnością oraz prostotą implementacji [Brecht i Ostrowski 2001]. Podczas ewaluacji różnych rozwiązań, została ona wybrana głównie ze względu na tę drugą cechę, w szczególności brak sekcji krytycznej25). Proces obsługi połączeń jest przedstawiony na rysunku 3.4.


        Uproszczony algorytm obsługi połączeń
        w komponencie n...
Rysunek 3.4: Uproszczony algorytm obsługi połączeń w komponencie netdb.

Rozpatrywane były również inne sposoby realizacji dostępu do bazy hostów przez wiele procesów, lecz zostały odrzucone. Tablica hostów mogłaby być przechowywana w segmencie pamięci, dzielonym między komponentami, zaś synchronizacja odbywałaby się z wykorzystaniem semaforów. Zaletą tego rozwiązania jest wysoka wydajność, ponieważ operacje na pamięci są zdecydowanie szybsze niż komunikacja za pomocą gniazd lokalnych. Wadami są zwiększenie skomplikowania komponentów (potrzeba zaimplementowania synchronizacji, która sprzyja powstawaniu błędów, komplikacje związane z umieszczeniem dynamicznych struktur danych w pamięci dzielonej26)) oraz trudność testowania (konieczne byłoby napisanie osobnego programu testującego, brak możliwości monitorowania odczytów/zapisów do/z pamięci). Podobnym pomysłem jest użycie pamięci prywatnej specjalnej biblioteki. Biblioteka udostępniałaby dostęp do bazy hostów, znajdującej się w pamięci prywatnej za pomocą zestawu funkcji. Synchronizacja odbywałaby się tylko wewnątrz biblioteki, jednak pozostałe problemy są takie same jak w poprzednim rozwiązaniu.

Główne zadanie programu, czyli operacje na bazie hostów jest realizowane z wykorzystaniem tablicy haszującej, dostępnej w bibliotece glib27). Obsługa zmiennych (komendy getvarsetvar) wykorzystuje prostą tablicę struktur. Tablica ta jest statyczna, ponieważ zbiór zmiennych jest stały i zdefiniowany w kodzie.

Po uruchomieniu program rejestruje gniazdo lokalne oraz wczytuje bazę hostów z pliku cache, który mógł zostać stworzony w wyniku poprzednich uruchomień. Jest to plik tekstowy, który zawiera sekwencje komend host. Ścieżka do pliku jest podawana jako parametr. Następnie przechwytywane są funkcje obsługi sygnałów, aby program przed zakończeniem mógł zapisać bazę hostów do pliku cache. Ostatnim krokiem jest wywołanie funkcji odpowiedzialnej za nasłuchiwanie na gnieździe i obsługę połączeń.

3.3 Zmiana adresów MAC

Proces zmiany adresów to podstawowe zadanie, które pochłania najwięcej zasobów w porównaniu z innymi zadaniami aplikacji multispoof. Dzieje się tak dlatego, że każda przychodząca lub wychodząca ramka ethernetowa musi zostać przetworzona przez szereg komponentów. Przetwarzanie obejmuje zmianę źródłowego adresu MAC w przypadku ramek wysyłanych, oraz przywracanie docelowego adresu MAC dla ramek przychodzących. Zmiana adresów następuje pomiędzy interfejsem wirtualnym a fizycznym. Interfejs wirtualny oddany jest do dyspozycji użytkownika, natomiast interfejs fizyczny jest pod pełną kontrolą aplikacji multispoof. Cały proces odbywa się z wykorzystaniem wspólnej dla wszystkich komponentów bazy adresów i jest przedstawiony na rysunku 3.5 (oznaczenia używane w diagramach są wyjaśnione na rysunku 3.6). Jeśli pominąć komponent netdb, jest to zwyczajny potok (dla czytelności parametry przekazywane komponentom zostały pominięte):
  # rx | cmac unspoof | tapio | cmac spoof | tx
			
Pomiędzy elementami potoku dane przekazywane są w sposób zakodowany zgodnie z omówionym wcześniej protokołem ramek. Komunikaty diagnostyczne są wysyłane na standardowe wyjście błędów, dzięki czemu nie zaburzają potoku. Każdy komunikat jest poprzedzany nazwą komponentu, który go wygenerował. Dzięki temu użytkownik jest na bieżąco informowany o istotnych wydarzeniach i jest w stanie przypisać je do konkretnego źródła. Role poszczególnych komponentów zostaną omówione w podrozdziałach.

        Proces zmiany adresów MAC w ramkach ethernetowych.
Rysunek 3.5: Proces zmiany adresów MAC w ramkach ethernetowych.

        Wyjaśnienie oznaczeń stosowanych na rysunkach.
Rysunek 3.6: Wyjaśnienie oznaczeń stosowanych na rysunkach.

3.3.1 rx i tx

Para programów rxtx zajmuje się odpowiednio podsłuchiwaniem (odbieraniem ramek) oraz ich wstrzykiwaniem do sieci.

Komponent rx odbiera ramki z wykorzystaniem biblioteki libpcap [Carstens 2002]. Jako parametry z linii komend podaje się interfejs, na którym program ma nasłuchiwać, oraz filtr BPF, określający które ramki będą odbierane. Podsłuchiwanie musi odbywać się w trybie promiscuous, ze względu na to, że aplikacja multispoof wykorzystuje wiele adresów MAC. Jeśli tryb ten byłby wyłączony, aplikacja otrzymywałaby tylko ramki, których docelowy adres MAC jest równy adresowi interfejsu sieciowego, oraz ramki rozgłoszeniowe. Oprócz trybu promiscuous, komponent rx przed rozpoczęciem podsłuchiwania aktywuje filtr kierunku transmisji, tak aby odbierane były tylko ramki, które płyną z sieci, nie zaś te, które są wysyłane przez hosta. Domyślnie bowiem, biblioteka libpcap przechwytuje ramki płynące w obydwu kierunkach28).

Podsłuchane ramki, które spełniają warunki narzucone przez filtr BPF oraz filtr kierunku, zostają wysłane przez komponent rx na standardowe wyjście, zakodowane zgodnie z tekstowym protokołem ramek.

Komponent tx zajmuje się wstrzykiwaniem ramek do sieci przez określony interfejs sieciowy. Ramki są wczytywane ze standardowego wejścia w formacie zgodnym z protokołem ramek. Wstrzykiwanie odbywa się z wykorzystaniem biblioteki libnet [Schiffman 2004]. Jeśli ramka do wstrzyknięcia jest zbyt mała (standard Ethernet wymaga, aby minimalna wielkość wynosiła 60 bajtów), komponent tx powiększa ją, dopełniając zerowymi bajtami (ang. padding). Gdyby czynność ta nie była wykonywana i tak ostatecznie zrobiłby to sterownik karty sieciowej. Jednak wtedy analiza danych płynących przez interfejs z wykorzystaniem narzędzi typu sniffer nie ujawniłaby dopełnienia, co nie zgadzałoby się ze stanem faktycznym i mogłoby wzbudzać wątpliwości u osoby, która nie jest zaznajomiona z tym faktem.

Komponenty rxtx wspólnie pozwalają na kompletną, niskopoziomową kontrolę ruchu przychodzącego i wychodzącego przez dany interfejs. Stanowią interfejs do sieci dla innych części aplikacji multispoof.

Rozbicie funkcji podsłuchiwania sieci oraz wstrzykiwania ramek na dwa oddzielne programy, oprócz korzyści związanych z modularyzacją aplikacji, może przydać się także w przyszłości. W kolejnej wersji można stosunkowo łatwo wprowadzić obsługę pracy w sieci bezprzewodowej. Radiowe interfejsy sieciowe charakteryzują się tym, że nie jest możliwe jednoczesne odbieranie i nadawanie. Wiąże się to z tzw. efektem oślepienia, który występuje w momencie zbyt szybkiego przełączenia interfejsu z trybu nadajnika w tryb odbiornika. Konieczne jest zastosowanie dwóch oddzielnych interfejsów sieciowych29): jednego tylko do wysyłania, zaś drugiego tylko do odbierania ramek. Obecna architektura aplikacji poradzi sobie z tym wymogiem, ponieważ każdy interfejs będzie obsługiwany przez osobny komponent30).

3.3.2 tapio

Komponent tapio jest odpowiedzialny za utworzenie wirtualnego interfejsu tap oraz komunikację z nim. Program łączy z interfejsem standardowe wejście i wyjście, w ten sposób, że ramki wczytywane z wejścia są na niego wysyłane, zaś ramki z niego odbierane są wypisywane na standardowe wyjście. Proces ten jest zobrazowany na rysunku 3.7. Obsługa wejścia/wyjścia jest realizowana z zachowaniem tekstowego protokołu ramek. Nazwę interfejsu tap, który program ma utworzyć, podaje się jako parametr.


          Schemat działania programu tapio.
Rysunek 3.7: Schemat działania programu tapio.

3.3.3 cmac

Komponent cmac jest programem typu filtr. Wczytuje on ramki ze standardowego wejścia, następnie jeśli spełnione zostaną kryteria akceptacji, modyfikuje je i wysyła na standardowe wyjście. Modyfikacja dotyczy zmiany adresu MAC ramki. W zależności od trybu podawanego jako parametr przy uruchomieniu, komponent podmienia adres źródłowy lub docelowy. Algorytm działania programu został przedstawiony na rysunku 3.8.


          Algorytm programu cmac w trybie spoof.
Rysunek 3.8: Algorytm programu cmac w trybie spoof.

Po uruchomieniu cmac łączy się z komponentem netdb. Z każdej wejściowej ramki program wyodrębnia jej adres IP. Następnie wysyła do netdb zapytanie o ten adres (wykorzystując komendę gethost). Jeśli wpis zostanie znaleziony, to odpowiedź będzie zawierać adres MAC hosta, czas nieaktywności, czas który upłynął od ostatniego testu oraz informacje czy dany adres jest w tej chwili testowany i czy jest w stanie enabled. Komponent cmac testuje, czy uzyskane informacje spełniają opisane w tabeli 3.2 warunki zmiany adresu MAC. Jeśli test wypadnie pomyślnie adres MAC ramki zostaje zmieniony i ramka jest wypisywana na standardowe wyjście.

Tabela 3.2: Zestawienie warunków, które musi spełnić wpis dla hosta aby dany komponent brał go pod uwagę podczas wykonywania określonej czynności.
Warunki Komponent Czynność
age > min_agetest_age > min_test_ageenabledcur_test
PrawdaPrawdacmacZmień MAC i wypisz ramkę
PrawdaPrawda
PrawdaPrawdadetaWypisz odpowiedź na ARP
PrawdaPrawda
PrawdaPrawdaconncheckWykonaj test połączenia
PrawdaPrawdanatmanUwzględnij wpis w LB
Program cmac musi pracować w jednym z dwóch trybów. Tryb działania ustalany jest na etapie uruchamiania. Poniżej opisane zostały oba tryby:
Spoof.
Modyfikacji podlega źródłowy adres MAC, który na podstawie źródłowego adresu IP pakietu zawartego w ramce, jest zastępowany adresem uzyskanym z bazy netdb,
Unspoof.
Z ramki wyodrębniany jest docelowy adres IP pakietu. Następnie sprawdzane jest, czy w bazie netdb istnieje wpis dla tego adresu. Jeśli wpis istnieje, to docelowy adres MAC ramki jest zastępowany przez adres MAC interfejsu tap. Adres ten jest odczytywany z bazy netdb na etapie inicjalizacji. Należy podkreślić, że w tym trybie odczytany z bazy netdb dla każdej ramki adres MAC hosta jest ignorowany, wykorzystywane są tylko pozostałe informacje związane z hostem.

3.4 Monitorowanie sieci

Drugim zadaniem aplikacji multispoof jest monitorowanie sieci. Polega ono na biernym podsłuchiwaniu ruchu i aktywnym skanowaniu. W proces ten zaangażowane jest pięć komponentów, z których trzy: netdb, txrx, zostały omówione w poprzednich podrozdziałach. Rysunek 3.9 przedstawia schemat procesu, z uwzględnieniem połączeń między komponentami. Alternatywnie można zobrazować go za pomocą dwóch, wykonywanych równolegle potoków (parametry komponentów zostały pominięte dla czytelności):
  # rx | deta | tx
  # scanarp | tx
      

        Proces monitorowania sieci.
Rysunek 3.9: Proces monitorowania sieci.

3.4.1 scanarp

Komponent scanarp ma za zadanie periodyczne wysyłanie zapytań ARP Request do wszystkich hostów, których adresy są zarejestrowane w bazie netdb. Zapytania tego rodzaju są wysyłane, aby stwierdzić które z zarejestrowanych hostów są w danej chwili aktywne, bowiem działające komputery odpowiadają komunikatem ARP Reply31). Algorytm działania programu został przedstawiony na rysunku 3.10. Wysyłanie ramek w sieć jest realizowane za pośrednictwem komponentu tx, z wykorzystaniem protokołu ramek. Komponent pobiera listę hostów z bazy za pomocą komendy dump. Należy podkreślić, że aktywność sieciowa komponentu scanarp ogranicza się wyłącznie do wysyłania pakietów ARP Request. Odbieraniem odpowiedzi ARP Reply zajmuje się opisany dalej komponent deta.


          Algorytm komponentu scanarp.
Rysunek 3.10: Algorytm komponentu scanarp.

3.4.2 deta

Komponent deta wykonuje dwa zadania, które ze względu na to, że muszą być wykonywane sekwencyjnie zostały zaimplementowane w jednym programie. Są to: wykrywanie aktywności hostów w sieci oraz odpowiadanie na zapytania ARP. Komponent nasłuchuje na fizycznym interfejsie sieciowym (za pośrednictwem programu rx), wyodrębnia adresy IP z przychodzących ramek, a następnie uaktualnia wpisy w bazie netdb. Jeśli z sieci przyjdzie zapytanie ARP Request, wtedy w zależności od zawartości bazy netdb może być udzielona odpowiedź i wysłana w sieć za pośrednictwem tx. Algorytm komponentu deta został przedstawiony na rysunku 3.11.


        Algorytm komponentu deta.
Rysunek 3.11: Algorytm komponentu deta.

Komponent ma architekturę typu filtr. Na wejściu pojawiają się ramki, które program przetwarza, uaktualniając bazę netdb. Na wyjście komponent wypisuje ramki ARP Reply. Po odebraniu ramki, deta sprawdza jaki protokół ona niesie. Jeśli jest to protokół IP, to wyodrębniany jest źródłowy adres IP. Jeśli natomiast jest to pakiet ARP, to wyodrębniany jest adres IP komputera, który nadał ten pakiet (może to być zapytanie z sieci, bądź odpowiedź na zapytanie wysłane przez komponent scanarp). W obu przypadkach sprowadza się to do ustalenia adresu IP nadawcy, jednak dla każdego protokołu dana ta zapisana jest w nieco innym miejscu nagłówka (rysunek 3.12).


        Umiejscowienie źródłowego adresu IP w pakietach
        IP i ...
Rysunek 3.12: Umiejscowienie źródłowego adresu IP w pakietach IP i ARP.

Gdy źródłowy adres IP jest już znany, komponent sprawdza, czy host ten znajduje się na czarnej liście. Lista ta jest pobierana przy starcie programu ze zmiennej banned komponentu netdb. Składa się ona z adresów, które są bezużyteczne w procesie podszywania się, natomiast pojawiają się w sieci. Zmienna jest definiowana w skrypcie multispoof (który będzie omówiony w podrozdziale 3.6) i zawiera takie adresy, jak 0.0.0.032), 255.255.255.255 oraz adres domyślnej bramy33). Jeśli adres nie należy do czarnej listy komponent wykonuje komendę host na bazie netdb (patrz podrozdział 3.2, w szczególności tabela 3.1). Jako parametry do komendy zostają podane adres IP oraz źródłowy adres MAC ramki. Jeśli w bazie nie ma jeszcze wpisu dla tego hosta, jest on tworzony. Jeśli już jest, to czas, który upłynął od ostatniej aktywności, jest zerowany. Dzięki temu inne komponenty nie zaczną lub zaprzestaną wykorzystywać adres tego hosta, ponieważ stał się on aktywny. Jeśli ramki z tego hosta przestaną przychodzić, to po pewnym czasie inne komponenty z powrotem rozpoczną korzystanie z jego adresu.

Jeżeli przychodząca ramka niesie w sobie pakiet ARP Request, to następnym krokiem jest ustalenie, czy należy wysłać odpowiedź ARP. Odpowiedź ARP powinna być wysłana tylko wtedy jeśli adres, którego dotyczy zapytanie ARP, jest aktualnie w użyciu przez inne komponenty. W przeciwnym wypadku, tzn. jeśli fizyczny host o takim adresie jest aktywny, odpowiedź ARP mogłaby spowodować problemy w sieci34). Dlatego przed wysłaniem odpowiedzi program deta wykonuje zapytanie do bazy netdb, tym razem korzystając z komendy gethost. Jeśli host wystarczająco długo nie był aktywny oraz jeśli ma flagę enabled (patrz zestawienie warunków w tabeli 3.2 oraz opis komponentu conncheckpodrozdziale 3.5.1) to ramka z odpowiedzią ARP jest tworzona i wypisywana na standardowe wyjście.

3.5 Testowanie i równoważenie obciążenia

Ostatnie zadanie aplikacji to typowanie nieaktywnych hostów które będą wykorzystywane w procesie zmiany adresów. Polega to na testowaniu łączności oraz przeładowywaniu reguł NAT odpowiedzialnych za równoważenie obciążenia. W procesach tych uczestniczą trzy komponenty, spośród których dwa nie zostały jeszcze omówione: connchecknatman. Na rysunku 3.13 przedstawiono schemat tej części aplikacji, z uwzględnieniem połączeń między komponentami.


        Procesy testowania i równoważenia obciążenia.
Rysunek 3.13: Procesy testowania i równoważenia obciążenia.

3.5.1 conncheck

Komponent conncheck decyduje które adresy z bazy netdb mogą być wykorzystywane w procesie podszywania się. Może się bowiem zdarzyć, że host znajdujący się w bazie netdb nie ma połączenia z Internetem (np. jego adres został zablokowany na routerze). Podszywanie się pod host, który nie ma łączności z siecią globalną mija się z celem aplikacji multispoof. Aby temu zapobiec program wybiera nieaktywne hosty i co pewien czas wykonuje dla każdego z nich test połączenia korzystając ze skryptu access-test. Adres hosta, który podlega testowaniu, jak i inne informacje są przekazywane do skryptu przez zmienne środowiskowe (tabela 3.3). Skrypt zwraca kod zakończenia równy 0, jeśli połączenie z Internetem zostało poprawnie zweryfikowane. Jeśli skrypt nie zdołał pozytywnie przetestować połączenia, to zwraca 1. Wersja aplikacji multispoof, która jest dołączona do tego opracowania, zawiera skrypt wykorzystujący program nmap35). Kod skryptu przedstawiony jest na listingu poniżej.

  #!/bin/sh
  HOST="www.mbank.com.pl"
  PORT="443"

  echo "access-test: (debug) checking $_IP started"
  RESULT=1
  nmap -sT -P0 -n -p $PORT $HOST 2> /dev/null | \
  egrep "^$PORT" | grep -q "open" && RESULT=0
  echo "access-test: (debug) checking $_IP finished (result: $RESULT)"

  exit $RESULT
      

Po wywołaniu skryptu, program nmap wysyła segment TCP SYN na port 443 hosta o adresie www.mbank.com.pl. Jeśli otrzyma w odpowiedzi segment SYN ACK, wypisuje na standardowe wyjście stosowny komunikat. Komunikat jest przetwarzany przez narzędzie grep, które zwraca odpowiednią wartość logiczną, wykorzystywaną dalej przez skrypt do ustawienia zmiennej RESULT. Ostatnim krokiem jest zwrócenie wartości tej zmiennej. Metoda oparta na programie nmap została wybrana ze względu na to, że program ten generuje ruch sieciowy o stosunkowo niskim natężeniu. Cała transmisja składa się z jednego lub kilku zapytań DNS oraz rozpoczęcia połączenia TCP. Pakiety są małe i jest ich niewiele36).

Tabela 3.3: Zmienne środowiskowe przekazywane przez komponent conncheck do skryptu access-test.
Zmienna Przykładowa zawartość (czasy w sekundach) Opis
_IP156.17.40.16Adres IP hosta.
_MAC00:e0:7d:dc:62:8cAdres MAC hosta.
_AGE1337Czas nieaktywności hosta.
_TEST_AGE6858Czas, który upłynął od ostatniego testu.
_ENABLED1Stan flagi enabled w chwili testu.
_MIN_AGE300Minimalny czas nieaktywności hosta.
_MIN_TEST_AGE3600Minimalny czas między testami.
_NF_CHAINmultispoof-testŁańcuch dla tymczasowych reguł iptables.

Testowanie połączenia z Internetem zostało zorganizowane w powyższy sposób, aby użytkownik miał możliwość łatwego modyfikowania tego elementu i dostrajania go do sieci w której jest uruchamiana aplikacja multispoof. Także w tym celu do skryptu są przekazywane zmienne środowiskowe. W tej wersji skryptu bowiem nie są one wykorzystywane.

Aby przetestować połączenie z Internetem konkretnego hosta, komponent conncheck przed uruchomieniem skryptu access-test musi załadować do jądra regułę NAT37), która spowoduje, że dane wysyłane i odbierane przez skrypt będą wykorzystywały adres IP testowanego hosta. Odbywające się aktualnie transmisje użytkownika aplikacji multispoof nie powinny zostać zakłócone, dlatego reguła musi dotyczyć tylko transmisji wykonywanych przez skrypt i programy przez niego uruchamiane. Aby spełnić ten warunek wykorzystywany jest moduł owner. Moduł ten pozwala na wyodrębnienie transmisji konkretnego procesu (wykorzystując jego PID) lub ich zbioru (za pomocą numeru SID - session ID38)). Ponieważ wszystkie komponenty aplikacji multispoof są wywoływane przez jeden skrypt (opisany w podrozdziale 3.6), numer SID każdego procesu jest taki sam. Skrypt access-test jest jedyną częścią aplikacji, która wykonuje transmisje sieciowe, dlatego wykorzystanie w regule tego numeru nie zakłóci pracy programu. Jeśli numerem SID będzie 42, transmisje mają wykorzystywać interfejs tap0, zaś adres źródłowy ma być podmieniany na 156.17.40.16, to wywołanie programu iptables będzie miało poniższą formę:

  # iptables -t nat -A POSTROUTING -o tap0 \
             -m owner --sid-owner 42 -j SNAT --to-source 156.17.40.16
      

W rzeczywistości, aplikacja multispoof wykorzystuje dodatkowe łańcuchy iptables. Jest to opisane dokładniej w podrozdziale 3.6.

Przed uruchomieniem skryptu access-test, oprócz załadowania reguły NAT, conncheck wywołuje na bazie adresów netdb komendę do start-test (zobacz tabela 3.1). Komenda ta ustawia flagę, która informuje inne komponenty, że dany host jest aktualnie testowany. Dzięki temu np. komponent cmac zmienia i przesyła ramki nawet dla hostów, które nie są w stanie enabled (zachowanie poszczególnych komponentów w zależności od stanu flag jest przedstawione w tabeli 3.2). Dopiero po tym wywoływany jest skrypt testujący. Następnie w zależności od wyniku testu, stan hosta jest za pomocą komendy do zmieniany na enabled lub disabled. Zostaje jeszcze usunięcie znacznika testowania oraz reguły NAT, po czym komponent przechodzi do testowania następnego adresu. Algorytm działania programu jest przedstawiony na rysunku 3.14.


          Algorytm działania komponentu conncheck.
Rysunek 3.14: Algorytm działania komponentu conncheck.

3.5.2 natman

Komponent natman jest odpowiedzialny za utrzymywanie aktualności reguł NAT wykorzystywanych do równoważenia obciążenia. Program periodycznie pobiera listę hostów z bazy netdb i na jej podstawie buduje listę hostów, które są w stanie enabled i były nieaktywne przez wystarczającą długi czas. Tak przygotowana lista jest porównywana z listą z poprzedniej iteracji. Jeśli listy różnią się, to znaczy, że w bazie pojawiły się nowe hosty, które można wykorzystać, lub dotychczas nieaktywne komputery stały się aktywne. W obu przypadkach komponent przeładowuje listę reguł NAT, aby uwzględnić zmiany. Rysunek 3.15 przedstawia algorytm działania programu natman.


          Algorytm działania komponentu natman.
Rysunek 3.15: Algorytm działania komponentu natman.

Równoważenie obciążenia to proces realizowany przez podsystem Netfilter jądra Linuksa, rozdzielający połączenia sieciowe i przypisujący je do poszczególnych adresów, które w danej chwili są wykorzystywane. Dzięki temu użytkownik może wygenerować ruch, którego natężenie wielokrotnie przekracza limit dla pojedynczego hosta.

Aby lepiej zrozumieć, na czym polega równoważenie obciążenia, należy prześledzić drogę pojedynczego pakietu. Pakiet, który przychodzi na interfejs wirtualny tap, jest porównywany z tablicą nawiązanych połączeń conntrack. Z każdym połączeniem związany jest adres IP. Jeśli pakiet należy do nawiązanego połączenia, to jego adres źródłowy zostanie zmieniony na ten, który jest zapisany w tablicy conntrack. Jeśli zaś pakiet nie należy do żadnego z istniejących połączeń, tzn. jest pierwszym pakietem połączenia (np. jest to pakiet TCP z ustawioną opcją SYN39)), to adres, jaki zostanie mu przypisany, jest wybierany z puli dostępnych odpowiednim algorytmem rozkładania obciążenia. W obecnej wersji wykorzystywany jest algorytm round robin40). Polega on na tym, że każde nowe połączenie dostaje kolejny adres IP modulo liczba dostępnych adresów. Tzn. jeśli dostępnych jest 10 adresów, to pierwsze połączenie dostanie pierwszy adres, drugie drugi itd., zaś połączenie jedenaste otrzyma adres pierwszy. Jest to najprostsza metoda równoważenia obciążenia, nie uwzględniająca stopnia wykorzystania poszczególnych adresów. W kolejnych wersjach aplikacji multispoof mogą pojawić się inne metody.

Rozkładanie nowych połączeń metodą round robin na poszczególne dostępne adresy IP odbywa się z wykorzystaniem modułu iptables o nazwie nth41). Moduł ten zawiera liczniki trafień, które mogą być wykorzystywane do wybierania co n-tego42) pakietu lub połączenia. Odpowiednio wykorzystany w regułach NAT moduł nth pozwala na uzyskanie efektu równoważenia obciążenia. Poniżej przedstawiono przykładowy zestaw reguł dla czterech adresów IP:
  # iptables -t nat -A POSTROUTING -o tap0 \
             -m nth --every 4 --packet 0 \
             -j SNAT --to-source 156.17.40.16
  # iptables -t nat -A POSTROUTING -o tap0 \
             -m nth --every 4 --packet 1 \
             -j SNAT --to-source 156.17.40.17
  # iptables -t nat -A POSTROUTING -o tap0 \
             -m nth --every 4 --packet 2 \
             -j SNAT --to-source 156.17.40.18
  # iptables -t nat -A POSTROUTING -o tap0 \
             -m nth --every 4 --packet 3 \
             -j SNAT --to-source 156.17.40.19
        
Dla czytelności w powyższym przykładzie reguły umieszczane są bezpośrednio we wbudowanym łańcuchu POSTROUTING. Aplikacja multispoof wykorzystuje dedykowany łańcuch, w celu bardziej elastycznego zarządzania regułami. Tabela nat na której operują reguły posiada cechę, która nie jest spotykana w innych tabelach – mianowicie trafiają do niej tylko te pakiety, które inicjują połączenia43). Pozostałe pakiety ulegają translacji automatycznie, w zależności od tego do jakiego połączenia należą. Funkcja ta jest zapewniana przez moduł śledzenia połączeń conntrack podsystemu Netfilter i może być wymuszona także dla innych tabel z wykorzystaniem filtra state.

Śledzenie połączeń ulegających translacji jest fundamentalnych mechanizmem, dzięki któremu transmisja może odbywać się prawidłowo. W przeciwnym wypadku, tzn. gdyby mechanizm ten został zdezaktywowany, translacja dotyczyłaby pojedynczych pakietów a nie połączeń. Doprowadziłoby to do sytuacji, w której poszczególne pakiety jednego połączenia miałyby różne źródłowe adresy IP, co uniemożliwia właściwą identyfikację połączenia przez host, znajdujący się po jego drugiej stronie. Adres IP bowiem jest jedną z danych, które identyfikują połączenie44) i przez czas jego trwania muszą pozostać niezmienne.

Ideę procesu rozkładania obciążenia została przedstawiona na rysunku 3.16. Pakiety zobrazowane są na nim jako różnokolorowe kółka. Kolor ich wypełnienia określa połączenie do którego przynależy dany pakiet. Środkowy okrąg określa miejsce, w którym przeprowadzany jest NAT według tabeli conntrack, która łączy połączenia z adresami IP. Na rysunku prawie wszystkie połączenia są już nawiązane i mają przypisane adresy IP. Pakiety oznaczone czerwonymi kółkami rozpoczynają połączenie, któremu adres IP zostanie przypisany zgodnie z algorytmem round robin.


          Proces równoważenia obciążenia ruchu wychodzącego
         ...
Rysunek 3.16: Proces równoważenia obciążenia ruchu wychodzącego z wykorzystaniem śledzenia połączeń i NAT.

3.6 Skrypt multispoof

Skrypt multispoof stanowi tę część aplikacji, która jest odpowiedzialna za uruchamianie jej poszczególnych zadań. Chociaż zarówno skrypt, jak i pozostałe komponenty, są plikami wykonywalnymi, po instalacji całej aplikacji tylko skrypt staje się dostępny dla użytkownika w standardowej ścieżce dostępu PATH. Pozostałe komponenty są umieszczane w osobnym katalogu, nie uwzględnionym w ścieżce. Dzieje się tak, ponieważ działając samodzielnie, komponenty nie spełniają użytecznych zadań, zaś udostępnianie nieprzydatnych programów w systemie jest pozbawione sensu.

Skrypt został zaprogramowany w języku Bourne shell. Język ten został wybrany ze względu na to, że uruchamianie podprocesów jest w nim maksymalnie uproszczone. To samo dotyczy komunikacji międzyprocesowej z wykorzystaniem potoków. Oba te mechanizmy są intensywnie wykorzystywane w aplikacji multispoof. Język shell stanowi framework, czyli niejako środowisko, w którym wykonują się poszczególne komponenty aplikacji [Raymond 2003].

Skrypt wykonuje sekwencję kroków, które przygotowują środowisko oraz w odpowiedniej kolejności uruchamiają poszczególne komponenty, uwzględniając zależności między nimi. Po uruchomieniu wszystkich komponentów, aplikacja jest gotowa do pracy. Jej działanie zostało zobrazowane na rysunku 3.17, który przedstawia wszystkie zadania omówione w tym rozdziale. Poniższa lista przedstawia sekwencję kroków skryptu.
  1. Odczytywanie parametrów, które użytkownik podał przy uruchomieniu45). Spośród wszystkich parametrów jedynym wymaganym jest nazwa interfejsu sieciowego, który ma być wykorzystywany przez aplikację.
  2. Rozpoznawanie konfiguracji sieciowej: adresów IP i MAC interfejsu sieciowego, maski oraz adresów IP i MAC domyślnej bramy.
  3. Weryfikacja uprawnień – jeśli użytkownik nie jest administratorem, to korzystanie z programu jest niemożliwe.
  4. Utworzenie katalogu tymczasowego, w którym umieszczone zostanie gniazdo lokalne komponentu netdb.
  5. Przechwycenie sygnałów, które przerywają działanie aplikacji, aby po otrzymaniu sygnału, aplikacja mogła przywrócić środowisko do pierwotnego stanu. Obejmuje to cofnięcie kroków 416.
  6. Uruchomienie w tle komponentu netdb (opisanego w podrozdziale 3.2).
  7. Oczekiwanie na utworzenie przez netdb gniazda lokalnego.
  8. Zdefiniowanie czarnej listy adresów IP i wpisanie jej do zmiennej banned w bazie netdb.
  9. Uruchomienie komponentów rx, tx (podrozdział 3.3.1), cmac (podrozdział 3.3.3) i tapio (podrozdział 3.3.2) w potoku odpowiedzialnym za zmianę adresów MAC.
  10. Utworzenie potoku, realizującego zadanie skanowania sieci za pośrednictwem komponentów scanarp (podrozdział 3.4.1) i tx.
  11. Uruchomienie komponentów rx, deta (podrozdział 3.4.2) i tx w potoku służącym do monitorowania sieci i odpowiadania na zapytania ARP.
  12. Utworzenie łańcuchów podsystemu Netfilter. Tworzony jest jeden główny łańcuch multispoof-main oraz łańcuchy multispoof-test (wykorzystywany przez komponent conncheck) i multispoof-sub (do którego reguły ładowane są przez program natman). We wbudowanym łańcuchu POSTROUTING umieszczana jest reguła, która powoduje, że połączenia wychodzące przez interfejs wirtualny tap są kierowane do łańcucha multispoof-main. W łańcuchu tym jest definiowana reguła, która przekierowuje do łańcucha multispoof-test połączenia generowane przez komponent conncheck46), zaś pozostałe połączenia są kierowane do łańcucha multispoof-sub. Łańcuchy oraz połączenia między nimi zostały przedstawione na rysunku 3.18.
  13. Uruchomienie komponentu natman (rozdział 3.5.2).
  14. Oczekiwanie na utworzenie interfejsu tap przez komponent tapio.
  15. Rejestracja adresu MAC interfejsu tap w bazie netdb w zmiennej defmac.
  16. Usunięcie adresów IP z interfejsu fizycznego. Pociąga to za sobą automatyczne usunięcie informacji o wszelkich trasach, które były związane z tym interfejsem, w tym o trasie domyślnej. Następnie skonfigurowanie interfejsu tap, tj. nadanie adresu IP, podniesienie interfejsu oraz dodanie trasy domyślnej. To ostatnie wymaga wprowadzenia statycznego wpisu ARP dla adresu IP bramy, ponieważ w obecnej wersji aplikacja multispoof nie pozwala na wysyłanie zapytań ARP.
  17. Uruchomienie komponentu conncheck (rozdział 3.5.1).
  18. Oczekiwanie na zakończenie procesów za pomocą funkcji wait.