Implementacja systemu aktywnego przeciwdziałania intruzom (IPS) w Pythonie [cz. 1]
przez 04-04-2010 o 23:07 (4659 Odwiedzin)
Zapora ogniowa (ang. firewall) już od dawna przestała być jedynym środkiem zabezpieczającym sieci prywatne. Kolejnymi rozwiązaniami były pasywne systemy wykrywania włamań IDS (ang. Intrusion Detection System) oraz aktywne systemy zapobiegania włamaniom IPS (ang. Intrusion Prevention System)[1]. Systemy IPS dzielą się jeszcze na dwie grupy zależnie od przeznaczenia: sieciowy system NIPS (ang. Network Intrusion Detection System) oraz system przeznaczony do ochrony hosta HIPS (ang. host-based intrusion detection system)[2][3]
Skupmy się na systemach IPS (NIPS). Z względu na sposób, w jaki blokują niepożądane pakiety możemy je podzielić na dwie grupy:
- pracujące w trybie outline (aktywne przeciwdziałanie intruzom)
- pracujące w trybie inline (zapobieganie intruzom)
Oba te systemy nie wykluczają się, czyli używanie ich jednocześnie jest jak najbardziej pożądane. Czym one się od siebie różnią?
Pierwszy z nich outline - bardzo rzadko używany termin, działa poza linią przepływu pakietów. Ma to miejsce, gdy odpowiednie reguły zapory ogniowej lub usługi systemowe generują logi, które są podstawą działania takiego systemu. Czyli system IPS outline podejmuje przeciwdziałanie po co najmniej pierwszym wystąpieniu niepożądanego zdarzenia.
Systemy IPS w trybie inline są bardzo pożądane, pracują dosłownie na drodze pakietów i potrafią podejmować decyzje dotyczące zablokowania bądź modyfikacji konkretnego pakietu. Ich największą zaletą jest to, że powstrzymają niepożądane pakiety, zanim te dotrą do celu. Na przykład serwer BIND może być zaatakowany pojedynczym pakietem UDP - w takiej sytuacji system aktywnego przeciwdziałania nie miały by szans.
Jednak istnieją zadania, do których systemy outline są lepsze od systemów działających na linii. Jednym z takich przykładów są boty próbujące w brutalny sposób odgadnąć hasło na serwerze SMTP. Obecnie spam jest największym zagrożeniem internetu[4]. Problem z takimi incydentami polega na tym, że pierwsze połączenie z określonego adresu IP, które dokonało niepoprawnej autoryzacji do systemu SMTP wcale nie musi być powodem do zablokowania tego adresu. Może się zdarzyć, że użytkownik źle wpisał hasło. Poza tym blokowanie adresu IP zawsze jest ryzykowne - może to być adres routera sieci i wtedy zablokujemy nawet setki innych hostów.
W takich sytuacjach doskonale sprawdzają się systemy IPS typu outline. Czytają logi i interpretują je. Jak wspomniałem błędna autoryzacja nie oznacza ataku, ale wielokrotna błędna autoryzacja z tego samego adresu IP na dodatek występująca z bardzo dużą częstotliwością jest strzałem w dziesiątkę dla takiego systemu i powodem do działania.
Oto przykład autentycznego ataku z pliku /var/log/auth.log:
Logi dotyczą demona Dovecot[5] ponieważ Postfix[6] jest tak skonfigurowany aby używał jego mechanizmu autoryzacji. Jak widzimy z logów w ciągu 13 sekund miała miejsce nieprawidłowa autoryzacja z tego samego adresu IP - nie mógł być to przypadek (dla przykładu wkleiłem tylko 8 linii, w rzeczywistości było ich ponad 200 lub 300!).Kod:Mar 30 05:19:01 prv dovecot-auth: pam_unix(dovecot:auth): check pass; user unknown Mar 30 05:19:01 prv dovecot-auth: pam_unix(dovecot:auth): authentication failure; logname= uid=0 euid=0 tty=dovecot ruser=admin@ rhost=202.55.172.6 Mar 30 05:19:05 prv dovecot-auth: pam_unix(dovecot:auth): check pass; user unknown Mar 30 05:19:05 prv dovecot-auth: pam_unix(dovecot:auth): authentication failure; logname= uid=0 euid=0 tty=dovecot ruser=test@ rhost=202.55.172.6 Mar 30 05:19:09 prv dovecot-auth: pam_unix(dovecot:auth): check pass; user unknown Mar 30 05:19:09 prv dovecot-auth: pam_unix(dovecot:auth): authentication failure; logname= uid=0 euid=0 tty=dovecot ruser=danny@ rhost=202.55.172.6 Mar 30 05:19:13 prv dovecot-auth: pam_unix(dovecot:auth): check pass; user unknown Mar 30 05:19:13 prv dovecot-auth: pam_unix(dovecot:auth): authentication failure; logname= uid=0 euid=0 tty=dovecot ruser=sharon@ rhost=202.55.172.6
Teraz już mniej więcej wiemy z czym próbujemy walczyć. W tym celu wykorzystamy własny system IPS napisany w języku Python działających w roli aktywnego przeciwdziałania intruzom.
Jaka jest idea takiego systemu i zakres działania?
System sam generuje wiele logów, więc nasz skrypt będzie czytał i interpretował te logi, które nas interesują. Logi możemy tworzyć również sami przy użyciu zapory ogniowej iptables i jej celu zwanego LOG[7].
Teraz system IPS musi wiedzieć czego szukać i co zrobić jeżeli będzie miało miejsce takie zdarzenie. Zanim jednak przejdziemy do tego jak to zrealizować zastanówmy się nad ogólną logiką programu komputerowego.
Działanie każdego programu komputerowego można przedstawić w trzech fazach:
- pobieranie danych (input)
- przetwarzanie danych (prcessing)
- generowanie wyników (output)
Nasz skrypt pobiera dane z dwóch miejsc. Po pierwsze na samym początku czyta reguły z pliku rule.ips. Reguły te są pisane w jego własnym formacie - opiszę go później. Następnie skrypt przystępuje do głównej działalności, która polega na bieżącym czytaniu dostarczanych mu logów.
Jest to kwestia zasadnicza, od niej zależy czas reakcji działania systemu IPS na zaistniałe niepożądane zdarzenia. Przedstawiona implementacja jest drugą opracowaną przez mnie. Pierwsza pobierała logi czytając je okresowo bezpośrednio z plików źródłowych. Okres trwał 11 sekund, więc czas reakcji mógł wynosić "aż" 11 sekund od dopasowania reguły/zdarzenia. W bieżącej wersji czas ten został skrócony do minimum poprzez wykorzystanie systemowych potoków, a właściwie urządzenia tego typu[8].
Pokażę teraz jak przygotować dane pobierane przez program. Po pierwsze musimy utworzyć urządzenie potoku /dev/ips (jako root):
oraz na wszelki wypadek nadać mu prawa:Kod:mkfifo /dev/ips
Kolejną czynnością jest konfiguracja demona rsyslog[9] (bo taki jest obecnie w Debian Lenny) w taki sposób aby wysyłał również (nie tylko) wybrane logi do naszego potoku. W tym celu dodajemy do pliku /etc/rsyslog.conf linię:Kod:chmod 777 /dev/ips
i restartujemy demona:Kod:kern.*,auth,authpriv.* |/dev/ips
Jako ciekawostkę podam informację, iż ten demon logowania oprócz przekazywania danych do potoku obsługuje również gniazda TCP. W systemie lokalnym nie będzie to lepsze rozwiązania ale stwarza to możliwosci uruchomienia takiego skryptu również na maszynie zdalnej.Kod:/etc/init.d/rsyslog restart
Rsyslog będzie teraz wysyłał do naszego potoku /dev/ips to samo co do plików:
- /var/log/kern.log - logi generowane przez jądro, głównie z iptables
- /var/log/auth.log - logi generowane przez mechanizm PAM[10] oraz mechanizmy wewnętrznej autoryzacji demonów np. sshd[11]
Możemy, a nawet powinniśmy to sprawdzić generując jakiś logowany ruch lub logi autoryzacyjne systemu. Sprawdźmy to zatem.
Spróbujmy uchwycić logowanie ruchu sieciowego. Ja testuję to wszystko na systemach wirtualnych w tzw. środowisku laboratoryjnym (ang. Environment Lab) więc konfiguracja zapory ogniowej jest tu sprawą indywidualną - dlatego ją pominę. W moim testowym systemie Debian Lenny zasadniczy będzie łańcuch FORWARD tablicy filter, ponieważ pracuje on jako brama internetowa dla sieci wewnętrznej.
Dodam do zapory regułę, która będzie logować każdy ruch kierowany z sieci prywatnej do portu 80/TCP:
Czyli nowe połączenia TCP kierowane na port 80/TCP z sieci 1921.68.44.0/24 zostaną zalogowane z prefiksem "dport 80 ". Prefiks posłuży do późniejszej identyfikacji dla systemu IPS.Kod:iptables -A FORWARD -s 192.168.44.0/24 -p tcp --dport 80 --syn -m state --state NEW -j LOG --log-prefix "dport 80 " --log-tcp-options --log-ip-options --log-tcp-sequence
Pamiętaj, że reguła i łańcuch jest dowolny. Ja wstawiam taką przed regułą przepuszczającą ruch na port 80/TCP aby szybko otrzymać przykładowe wyniki. Natomiast system IPS może zareagować na dowolną regułę, bardziej użyteczną, ale to już inny temat.
Używając polecenia powłoki cat spróbujemy pobrać zawartość potoku (aby zakończyć wciśnij Ctrl+C):
Teraz z jednego z hostów z sieci 192.168.44.0/24 musimy uruchomić przeglądarkę internetową i załadować kilka storn WWW. W moim przypadku będzie to host o adresie 192.168.44.4.Kod:cat /dev/ips



![Submit "Implementacja systemu aktywnego przeciwdziałania intruzom (IPS) w Pythonie [cz. 1]" to Digg](images/misc/bookmarksite_digg.gif)
![Submit "Implementacja systemu aktywnego przeciwdziałania intruzom (IPS) w Pythonie [cz. 1]" to del.icio.us](images/misc/bookmarksite_delicious.gif)
![Submit "Implementacja systemu aktywnego przeciwdziałania intruzom (IPS) w Pythonie [cz. 1]" to Google](images/misc/bookmarksite_google.gif)
![Submit "Implementacja systemu aktywnego przeciwdziałania intruzom (IPS) w Pythonie [cz. 1]" to facebook](images/misc/bookmarksite_facebook.gif)
![Submit "Implementacja systemu aktywnego przeciwdziałania intruzom (IPS) w Pythonie [cz. 1]" to wykop](images/misc/wykop.gif)
Wyślij na e-mail wpis na blogu