Skanowanie portów, fingerprinting (nmap, nikto, p0f, httprint)

Bez rozpisywania się na temat teoretycznych aspektów bezpieczeństwa – chciałbym przedstawić kilka ciekawych moim zdaniem zagadnień, które powinny być bliskie każdemu potencjalnemu administratorowi sieci czy serwera. Bez względu na sprzęt i system operacyjny – zarówno admin szkolnej pracowni, jak i uczelnianego serwera SMTP – powinien zdawać sobie sprawę z zagrożeń, technik potencjalnych ataków (zarówno z wewnątrz jak i z zewnątrz sieci lokalnej) i podstawowych przynajmniej technik zabezpieczania się przed nimi.

Generalnie skanowanie i fingerprinting pozwalają na wykrycie jaka aplikacja obsługuje określoną usługę, działającą na zdalnej maszynie, w jakiej wersji, na jakim porcie, z uwzględnieniem często wielu drobiazgowych niuansów jej działania. Dzięki temu, że zarówno pojedyńcze usługi, jak i mechanizmy sieciowe całych systemów operacyjnych (np. generatory liczb losowych) charakteryzują się unikalnymi cechami, wręcz „odciskami palców” (fingerprint), można za pomocą różnorodnych technik i narzędzi wykryć potencjalnie stare, dziurawe, źle skonfigurowane aplikacje i systemy. Jednym z najpopularniejszych skanerów jest Nmap. Pozwala nie tylko na rozbudowane techniki skanowania (syn, fin, ack, null, xmas) ale również potrafi „zgadnąć” jaki system operacyjny jest uruchomiony na zdalnym hoście. Aplikacja dostępna jest w każdej wersji Linux-EduCD. W Debianie i pochodnych wystarczy standardowe:

# apt-get update
# apt-get install nmap

Samo działanie TCP/IP, flagi typu ACK, SYN, RST itp omówiłem pobieżnie w
artykule o snorcie: http://biuletyn.skos.org/0501/rajmund/

SKANOWANIE

Skanowanie typu „tcp connect” – to najbardziej podstawowa technika. Polega na przeprowadzeniu pełnego połączenia TCP z danym portem. Jako że podczas tzw. trójstronnego uzgadniania połączenia (SYN, SYN/ACK i ACK) żaden komputer pracujący w sieci nie może ignorować pakietów TCP/SYN – jest to również metoda całkiem skuteczna. Jeśli więc dany port jest otwarty i otrzyma od nmapa pakiet TCP z ustawioną flagą syn, odpowie pakietem SYN/ACK. Jeśli jest zamknięty odpowie RST/ACK.

Należy pamiętać, że metoda ta jest łatwa do wykrycia. Przecież nawiązywane są próby faktycznych połączeń z usługami. W logach zdalnego systemu będą więc po nich ślady. Żeby przeprowadzić skanowanie tcp connect za pomocą nmapa należy posłużyć się opcją -sT:

nmap -sT adres_ip

Skanowanie tcp syn polega na wysłaniu pakietu z ustawioną flagą SYN. Nie jest jednak nawiązywane pełne połączenie, ponieważ jeśli zdalny host odpowie SYN/ACK (czyli port jest otwarty), atakujący nigdy nie wyśle ACK. W logach typowych firewalli nie będzie więc nawet śladów połączenia. W przypadku tej techniki posłużymy się opcją -sS:

nmap -sS adres_ip

Dla odmiany tcp fin to metoda polegająca na przesłaniu do zdalnego portu pakietu z flagą FIN (czyli takiego który zazwyczaj, w przypadku „kulturalnego i podręcznikowego” działania kończy uzgadnianie połączenia). Host powinien odpowiedzieć pakietem RST jeśli port jest zamknięty. Jest to tzw skanowanie ukryte:

nmap -sF adres_ip

Skanowanie typu tcp ack to również stosunkowo bezpieczna, ukryta metoda. Polega na wysłaniu od razu pakietu z flagą ACK (z pominięciem SYN i SYN/ACK). W tym przypadku wartość ACK jest sfałszowana, bo dotyczy połączenia które nigdy nie zostało nawiązane. Port zamknięty odpowie RST, port otwarty …wcale nie odpowie 😉 Z pomocą nmapa robimy to następująco:

nmap -sA adres_ip

tcp null to technika, w której do hosta wysyłane są pakiety bez żadnej flagi (SYN, SYN/ACK czy FIN).
Na takie „zaczepki” port otwarty nie odpowie (czyli skaner wie że jest otwarty), port zamknięty natomiast odburknie zwykłym RST:

nmap -sN adres_ip

Przykładowa sesja nmapa:
# nmap -sF www.linux-educd.pl

Starting Nmap 4.11 ( http://www.insecure.org/nmap/ ) at 2007-01-22 09:30 CET
Interesting ports on an2.alpha.pl (85.255.1.130):
Not shown: 1664 closed ports
PORT STATE SERVICE
21/tcp open|filtered ftp
22/tcp open|filtered ssh
25/tcp open|filtered smtp
42/tcp open|filtered nameserver
80/tcp open|filtered http
110/tcp open|filtered pop3
3001/tcp open|filtered nessusd
3306/tcp open|filtered mysql
5432/tcp open|filtered postgres

Nmap finished: 1 IP address (1 host up) scanned in 18.103 seconds

Nmap pozwala również na zdalne wykrycie systemu operacyjnego. Służy do tego opcja „-O”. Przykładowy wynik działania takiego skanu:
nmap -O www.simp-st.pl



Device type: general purpose
Running: Linux 2.4.X|2.5.X
OS details: Linux 2.4.0 – 2.5.20
Uptime 4.836 days (since Thu Jan 18 21:02:37 2007)

Jak widać wiemy już że zdalny system to Linux, oraz że pracuje bez żadnej przerwy od ponad 4 dni.
Informacje na temat uptime’u nmap pobiera z pola „Timestamp” z nagłówka TCP/IP. Natomiast „Device type: general purpose” oznacza że w bazie sygnatur (odcisków) nmapa sprzęt na którym pracuje system należy do tzw. klasy uniwersalnej

WYKORZYSTANIE IPTABLES DO WYKRYWANIA PRÓB SKANOWANIA

Oczywista i kluczowa sprawa to nie uruchamiać żadnych zbędnych/nadmiarowych usług. W przypadku
systemów CMS często wystarczy że np. serwer baz danych nasłuchuje wyłącznie na localhoście i po lokalnym interfejsie łączy się z nią nasza aplikacja.

Ponadto za pomocą iptables możemy logować próby skanowania i w zależności od konkretnej sytuacji reagować na takie incydenty (oczywiście nie przesadzajmy z wpisywaniem każdego IP do /etc/hosts.deny 🙂 Adres z którego przeprowadzane są inwigilacje łatwo sfałszować. Wystarczy np:

nmap -S 83.238.100.0 -e eth0 -P0 -sF -v ip_atakowanego_hosta

.. i w logach skanowanej maszyny pojawi się informacja że z ktoś z adresu 83.238.100.0 biegał po jej portach.

Wracając do tematu – dodanie poniższych regułek do tablicy iptables spowoduje że system wykryje i odpisze w logach róby skanowania TCP SYN:
iptables -A INPUT -m conntrack –cstate NEW -p tcp -tcp-flags SYN,RST,ACK,FIN,URG,PSH SYN -j LOG
–log-level info -log-prefix „uwaga! ktoś skanuje tcp syn!”

Tajemnicze „conntrack” w naszej regułce oznacza, że śledzone są przychodzące połączenia. Dla odmiany logowanie skanów typu TCP FIN np. wymaga analogicznej regułki:
iptables -A INPUT -m conntrack –cstate NEW -p tcp -tcp-flags SYN,RST,ACK,FIN,URG,PSH FIN -j LOG
–log-level info -log-prefix „uwaga! ktoś skanuje tcp fin!”

Możemy również (pod warunkiem że nie udostępniamy żadnych usług) wycinać takie połączenia:
iptables -A INPUT -m conntrack –cstate NEW -p tcp -tcp-flags SYN,RST,ACK,FIN,URG,PSH SYN -j DROP

Trochę inaczej będzie wyglądało logowanie skanów typu TCP NULL. Tutaj nie jest ustawiana żadna flaga, więc za pomocą opcji INVALID poinformujemy iptables – że pakiet nie należy do żadnego prawidłowo nawiązanego połączenia:
ptables -A INPUT -m conntrack –cstate INVALID -p tcp -tcp-flags !
SYN,RST,ACK,FIN,URG,PSH SYN,RST,ACK,FIN,URG,PSH -j LOG
–log-level info -log-prefix „uwaga! skany tcp NULL!”

PASYWNY (i nie tylko) FINGERPRINTING

Nmap poza informacjami na temat uruchomionych usług, ich wersji oraz systemu operacyjnego nie pozwala na dokładniejsze zbadanie zdalnej aplikacji. Generalnie największy poziom szczegółowości można uzyskać za pomocą opcji „-sV”. Np.

nmap www.linux-educd.pl -P0 -sV -p 80

W odpowiedzi dostaniemy:

PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 1.3.33 ((Unix) PHP/4.3.10)

Oczywiście możemy zakazać naszemu apache’owi tak obszernego „przedstawiania się w sieci”. W tym celu wystarczy w głównym pliku konfiguracyjnym (httpd.conf) zmienić:

ServerSignature On

na:

ServerSignature Off

Oraz dodać poniżej w/w wpisu linię, która spowoduje, że serwer nie będzie podawał numeru wersji:

SeverTokens Prod

Następnie tylko „apachectl restart” i gotowe. W tej chwili po przeskanowaniu otrzymamy wyłącznie:

PORT STATE SERVICE VERSION
80/tcp open http Apache httpd

Poza nmapem są jednak bardziej wyspecjalizowane aplikacje, służące do skanowania serwerów WWW. Jedną z nich jest httprint (Można go pobrać z http://net-square.com/httprint . Nie jest dostępny w repozytoriach Debiana). Httprint ma własną bazę odcisków palców (sygnatur) za pomocą których potrafi bardzo dokładnie przeanalizować typ serwera WWW, weryfikując implementację protokołu HTTP. Nie da się go więc oszukać zwykłą podmianą czy wyłączeniem bannera 🙂
Httprint uruchamiamy w następujący sposób:

# ./httprint -h 127.0.0.1:80 -s sinatures.txt -P0

Opcja „-P0″ powoduje że serwer nie próbuje pingować docelowej maszyny (w tym wypadku localhosta).
Należy też pamiętać że htprint wymaga podania adresu IP – nie adresu DNS’owego! Opcja „-s signatures.txt” to wskazanie pliku, w którym znajduje się zbiór wspomnianych „odcisków” httprinta. Domyślnie jest on w tym samym katalogu co uruchamiany program.

Kolejną ciekawą aplikacją służącą do fingerprintingu serwera WWW (i aplikacji „server-side”) jest nikto. Program dostępny jest w repozytoriach Debiana. W Linux-EduCD 0.7/0.7.1 znajduje się gotowy do użycia na płycie DVD. Po uruchomieniu przeprowadza kilkanaście rodzajów testów oraz wyszukuje błędy w skryptach CGI, PHP itp. Dodatowe ciekawe możliwości jakie oferuje nikto – to „omijanie” systemów wykrywania intruzów, przez losowe kodowanie adresów URI, czy dzielenie sesji na fragmenty. W podstawowy sposób używamy go z opcją „-h”:

nikto -h localhost

Przykładowy fragment sesji nikto:
# nikto -h localhost
—————————————————————————
– Nikto 1.35/1.35 – www.cirt.net
+ Target IP: 127.0.0.1
+ Target Hostname: localhost
+ Target Port: 80
+ Start Time: Tue Jan 23 19:05:21 2007
—————————————————————————
– Scan is dependent on „Server” string which can be faked, use -g to override
+ Server: Apache/1.3.34 (Debian) PHP/5.2.0-7
– Retrieved X-Powered-By header: PHP/5.2.0-7
+ /robots.txt – contains 13 ‚disallow’ entries which should be manually viewed (added to mutation file lists) (GET).
+ Apache/1.3.34 appears to be outdated (current is at least Apache/2.0.54). Apache 1.3.33 is still maintained and considered secure.
+ /icons/ – Directory indexing is enabled, it should only be enabled for specific directories (if required). If indexing is not used all, the /icons directory should be removed. (GET)

Jeśli chcemy np. zakodować w sposób losowy URI dodajemy opcję „-e 1″. Jeśli nikto ma pofragmentować sesję i pozmieniać wielkości liter oraz separator (dla zmylenia IDS’a, takiego chociażby jak snort) dodajemy opcję „-e 789″:

nikto -e 789 -h localhost

Możliwe jest również jawne podawanie numeru portu (jeśli serwer WWW nasłuchuje na innym niż domyślny) za pomocą „-p” oraz podawanie ścieżki do interesujących nas katalogów (opcja „-r”).

Wszystkie powyższe aplikacje generują duży ruch sieciowy i działają dosyć inwazyjnie. Skanując nmapem np. własny serwer zauważymy w logach dużą liczbę dodatkowych połączeń na różnych portach. Istnieją jednak metody pasywnego fingerprintingu, kiedy to nie wysyłamy do zdalnego systemu żadnych pakietów a jedynie analizujemy to – co do nas przychodzi i co można „podsłuchać” bez wysyłania czegokolwiek poza ruter. Oczywiście można również „sprowokować” zdalną maszynę do tego, żeby nam podesłała kilka niewinnych pakietów TCP/IP 😉 Skaner analizując zawartość i strukturę tych pakietów może się sporo dowiedzieć o ich źrodle.

Jedną z najlepszych aplikacji służących do pasywnego fingeprintingu jest p0f autorstwa lcamtufa. Ma tak obszerną bazę sygnatur, że potrafi nawet rozpoznawać podłączone do sieci konsole gier. Oczywiście dostępny jest w repozytoriach Debiana. Póki co w sieci można go znaleźć pod adresem: http://lcamtuf.coredump.cx/p0f.shtml

Prosto po uruchomieniu p0f’a zobaczymy, że pozornie nic się nie dzieje:
# p0f
p0f – passive os fingerprinting utility, version 2.0.5
(C) M. Zalewski <lcamtuf@dione.cc>, W. Stearns <wstearns@pobox.com>
p0f: listening (SYN) on ‚eth0′, 231 sigs (13 generic), rule: ‚all’.

P0f czeka na pakiety.. spróbujmy więc wykonać jakąś próbę połączenia (np. z serwerem WWW), albo choćby spingować maszynę. Zauważymy od razu:

p0f – passive os fingerprinting utility, version 2.0.5
(C) M. Zalewski <lcamtuf@dione.cc>, W. Stearns <wstearns@pobox.com>
p0f: listening (SYN) on ‚eth0′, 231 sigs (13 generic), rule: ‚all’.
83.18.98.206:2847 – Linux 2.6.9 [S4:56:1:60:M1460,S,T,N,W3:.:?:?] (up: 235 hrs)
-> 86.100.68.125:22 (link: ethernet/modem)
83.18.98.206:4730 – Linux 2.6.9 [S4:56:1:60:M1460,S,T,N,W3:.:?:?] (up: 235 hrs)
-> 86.100.68.125:80 (link: ethernet/modem)
83.18.98.206:4730 – Linux 2.6.9 [S4:56:1:60:M1460,S,T,N,W3:.:?:?] (up: 235 hrs)
-> 86.100.68.125:80 (link: ethernet/modem)
+++ Exiting on signal 2 +++
[+] Average packet ratio: 1.86 per minute.

Jak na dłoni widać że ktoś o adresie IP 83.18.98.206 (Linux 2.6.9) (czyli ja) wykonywał na początku połączenie na porcie 22 (ssh) a następnie 80 (WWW) z maszyną 86.100.68.125. Gdybyśmy chcieli uruchomić p0f’a w trybie nasłuchiwania pakietów SYN-ACK (domyślnie wyłapuje tylko SYN), wystarczy dodać odpowiednią opcję:

p0f -A

Przykładowa sygnatura (p0f przechowuje je w plikach p0f.fp, p0fa.fp, p0fo.fp i p0fr.fp) systemu operacyjnego może wyglądać następująco:

65535:128:1:64:M*,N,W0,N,N,T0,N,N,S:A:Windows:2000 SP4

Wartość „65535″ to pole Window nagłówka TCP, „128″ – to TTL (time to live), czyli czas życia pakietu (wartości TTL są widoczne chociażby podczas pingowania maszyny. Każdy system operacyjny generuje unikalny TTL. Podczas ruchu sieciowego każdy kolejny router na trasie pakietu zmniejsza jego TTL o jeden. Jeśli router otrzyma pakiet TTL o wartości „1″, odrzuci go i usunie z sieci, a nadawca otrzyma komunikat ICMP o błędzie. Kolejne pole („1″) to bit „don’t fragment, który jak widać jest ustawiony.

Jak widać możliwości „rozpoznania” zdalnego systemu i aplikacji jest wiele (rzecz jasna dużo więcej niż zostało poruszone w tym artykule). Warto też pamiętać o tym, by na bieżąco aktualizować bazy sygnatur i same narzędzia do fingerprintingu.