TCP/IP Timestamps – odczytywanie uptime hosta w sieci i nie tylko
Napisał: Patryk Krawaczyński
12/12/2010 w Bezpieczeństwo Brak komentarzy. (artykuł nr 297, ilość słów: 1761)
Z
naczniki czasu określone przez RFC1323 służą między innymi do ochrony przed “owijaniem” się numerów sekwencyjnych (PAWS – ang. Protection Against Wrapped Sequence Numbers), czy obliczaniem opóźnienia pomiędzy wysłaniem segmentu (PDU – ang. Protocol Data Unit dla warstwy transportu), a otrzymaniem potwierdzenia jego otrzymania (RTTM – ang. Round-Trip-Time Measurement).
Niestety – dzięki opcji timestamp jesteśmy też w stanie bardzo prosto obliczyć uptime, czyli jak długo maszyna pracuje w sieci bez restartowania, a tym samym dowiedzieć się np. czy zostały na nią nałożone aktualizacje bezpieczeństwa wymagające restartu całego systemu. Wynika to z faktu, że wszystkie systemy operacyjne fabrycznie podnoszą wartość timestamp w przesyłanych pakietach o wartość X, co X milisekund (np. Linux podnosi wartość o 1, co 1 ms, IOS Cisco, co .1 ms, a podstawa dzisiejszych systemów BSD – 4.4BSD – co 500 ms). Jeśli więc posiadamy informację o rodzaju używanego systemu operacyjnego i informację o ile podnosi wartość timestamp – możemy podzielić ją przez liczbę inkrementacji na sekundę, aby otrzymać uptime wyrażony w sekundach. Jednak to nie wszystko. Jak wykazał Elie aka Lupin w swojej pracy pt. “TCP Timestamp to count hosts behind NAT” na łamach magazynu Phrack #63 nie koniecznie musimy znać rodzaj systemu operacyjnego oraz wartość o jaką podnosi znaczniki czasu. Wystarczy pobrać dwa razy wartość timestamp nazwać ją np. ts1 i ts2 oraz oznaczyć czas – s1 i s2 (wyrażony w sekundach), w którym zebraliśmy próbki. Z tymi informacjami do obliczenia wzrostu wystarczy użyć równania:
X = (ts1 - ts2) / (s1 - s2)
Idąc krok dalej – dzięki znacznikom czasu, które używane są w TCP i poniższemu algorytmowi – możemy policzyć liczbę komputerów znajdujących się za mechanizmem NAT (mechanizm NAT nie przepisuje wartości timestamp):
- Każdemu odkrytemu już hostowi będzie przypisywany pakiet na podstawie równania. Każdy host posiada unikalny wynik równania chyba, że dwa hosty zostały uruchomione w tej samej sekundzie.
- Jeśli pakiet nie zostanie dopasowany do już zebranych wzorców – oznacza to, że został wykryty nowy host za mechanizmem NAT.
- Możemy też potwierdzić skuteczność ataku DoS poprzez porównanie wartości uptime przed i po ataku.
- A także określić, czy host został zaktualizowany na ostatnio wykrytą podatność wymagającą restartu serwera.
Patrząc na tą sytuację od strony komputera klienckiego – dzięki znacznikom czasu różne programy i urządzenia w Internecie mogą odczytywać, obliczać i tworzyć indywidualne profile (służące do śledzenia aktywności) tzw. przesunięć czasowych impulsów zegarowych (ang. clock skew) naszego komputera – w ten sposób nasza maszyna jest oznaczona “sprzętowo – programowym” ciasteczkiem już na poziomie warstwy transportowej (a nie aplikacji). Przykładem odczytania wartości uptime jest użycie popularnego skanera nmap z opcją OS detection. Na hoście agresora wywołujemy skanowanie:
nmap -PN -O -v nfsec.pl
Zwraca ono nam informację:
(...) No exact OS matches for host (test conditions non-ideal). Uptime: 11.853 days (since Mon Nov 29 23:29:30 2010) TCP Sequence Prediction: Difficulty=205 (Good luck!) IP ID Sequence Generation: All zeros (...)
Potwierdzamy ją na skanowanym hoście:
root@nfsec:~# uname -a Linux nfsec 2.6.33-4-smp #2 SMP Wed May 12 22:47:36 CDT 2010 (...) root@nfsec:~# uptime 20:01:07 up 11 days, 20:33, 1 user, load average: 0.11, 0.04, 0.01
Do sprawdzania serwerów znajdujących się za load balancerem możemy użyć polecenia hping3:
root@darkstar:~# hping3 -c 4 -S -p 443 --tcp-timestamp firma.corp HPING firma.corp (eth0 1.2.3.4): S set, 40 headers + 0 data bytes len=56 ip=1.2.3.4 ttl=53 DF id=0 sport=443 flags=SA seq=0 win=28480 rtt=35.7 ms TCP timestamp: tcpts=184791668 len=56 ip=1.2.3.4 ttl=53 DF id=0 sport=443 flags=SA seq=1 win=28480 rtt=39.4 ms TCP timestamp: tcpts=184791918 HZ seems hz=100 System uptime seems: 21 days, 9 hours, 18 minutes, 39 seconds len=56 ip=1.2.3.4 ttl=53 DF id=0 sport=443 flags=SA seq=2 win=28480 rtt=39.1 ms TCP timestamp: tcpts=184792168 HZ seems hz=100 System uptime seems: 21 days, 9 hours, 18 minutes, 41 seconds len=56 ip=1.2.3.4 ttl=53 DF id=0 sport=443 flags=SA seq=3 win=28480 rtt=38.9 ms TCP timestamp: tcpts=184792418 HZ seems hz=100 System uptime seems: 21 days, 9 hours, 18 minutes, 44 seconds --- firma.corp hping statistic --- 4 packets transmitted, 4 packets received, 0% packet loss round-trip min/avg/max = 35.7/38.3/39.4 ms root@darkstar:~# hping3 -c 4 -S -p 443 --tcp-timestamp firma.corp HPING firma.corp (eth0 1.2.3.4): S set, 40 headers + 0 data bytes len=56 ip=1.2.3.4 ttl=54 DF id=0 sport=443 flags=SA seq=0 win=28480 rtt=39.2 ms TCP timestamp: tcpts=144218929 len=56 ip=1.2.3.4 ttl=54 DF id=0 sport=443 flags=SA seq=1 win=28480 rtt=39.0 ms TCP timestamp: tcpts=144219179 HZ seems hz=100 System uptime seems: 16 days, 16 hours, 36 minutes, 31 seconds len=56 ip=1.2.3.4 ttl=54 DF id=0 sport=443 flags=SA seq=2 win=28480 rtt=38.9 ms TCP timestamp: tcpts=144219429 HZ seems hz=100 System uptime seems: 16 days, 16 hours, 36 minutes, 34 seconds len=56 ip=1.2.3.4 ttl=54 DF id=0 sport=443 flags=SA seq=3 win=28480 rtt=38.9 ms TCP timestamp: tcpts=144219679 HZ seems hz=100 System uptime seems: 16 days, 16 hours, 36 minutes, 36 seconds --- firma.corp hping statistic --- 4 packets transmitted, 4 packets received, 0% packet loss round-trip min/avg/max = 38.9/39.0/39.2 ms root@darkstar:~# hping3 -c 4 -S -p 443 --tcp-timestamp firma.corp HPING firma.corp (eth0 1.2.3.4): S set, 40 headers + 0 data bytes len=56 ip=1.2.3.4 ttl=54 DF id=0 sport=443 flags=SA seq=0 win=28480 rtt=35.7 ms TCP timestamp: tcpts=1766083410 len=56 ip=1.2.3.4 ttl=54 DF id=0 sport=443 flags=SA seq=1 win=28480 rtt=35.5 ms TCP timestamp: tcpts=1766083660 HZ seems hz=100 System uptime seems: 204 days, 9 hours, 47 minutes, 16 seconds len=56 ip=1.2.3.4 ttl=54 DF id=0 sport=443 flags=SA seq=2 win=28480 rtt=35.2 ms TCP timestamp: tcpts=1766083910 HZ seems hz=100 System uptime seems: 204 days, 9 hours, 47 minutes, 19 seconds len=56 ip=1.2.3.4 ttl=54 DF id=0 sport=443 flags=SA seq=3 win=28480 rtt=38.9 ms TCP timestamp: tcpts=1766084160 HZ seems hz=100 System uptime seems: 204 days, 9 hours, 47 minutes, 21 seconds --- firma.corp hping statistic --- 4 packets transmitted, 4 packets received, 0% packet loss round-trip min/avg/max = 35.2/36.3/38.9 ms
Jak widzimy, udało nam się zidentyfikować trzy różne serwery za tym samym adresem IP i portem. Jednym z możliwych rozwiązań wycieku tego typu danych przez protokół TCP jest po prostu wyłączenie opcji znaczników czasu. Dla systemu Linux możemy wykonać to za pomocą polecenia:
echo 0 >/proc/sys/net/ipv4/tcp_timestamps
Lub umieszczeniu poniższej wartości w pliku /etc/sysctl.conf
:
net.ipv4.tcp_timestamps = 0
Niestety jest to bezpieczne rozwiązanie tylko dla sieci o małych prędkościach przesyłu danych. Pole numerów sekwencyjnych w protokole TCP ma tylko 32 bity, co ogranicza liczbę dostępnych numerów sekwencyjnych. W sieciach o dużej wydajności i transferze danych możliwe jest wyczerpanie się numerów sekwencyjnych przed przemierzeniem pakietu przez sieć. Jeśli dane przesyłane są w sieci z prędkością 1 Gbps, numery sekwencyjne mogą wyczerpać się np. od 17 do 34 sekund (w zależności od uzyskanej szybkości transferu). Jeśli z jakiegoś powodu jeden z pakietów został opóźniony potencjalnie możliwe jest, że inny pakiet będzie istniał z takim samym numerem sekwencyjnym i zostanie zaakceptowany jako bieżący. Wówczas może dojść do cichego zniszczenia danych (ang. silent data corruption). Dlatego w celu uniknięcia nieporozumień podczas transmisji w przypadku powtarzających się numerów sekwencyjnych używa się znaczników czasu jako rozszerzenia tych numerów. W ten sposób pakiety posiadają postępujące (wzrastające) znaczniki czasu. Jeśli host wykryje, że timestamp segmentu jest mniejszy niż wartość ostatniego dobrego znacznika lub numer sekwencyjny jest większy niż ostatnie wysłane potwierdzenie – zostaje on odrzucony w transmisji.
Opisany powyżej mechanizm nazywa się PAWS i jest on w dodatku podatny na atak Denial of Service. W przypadku, gdy atakujący naszą sieć ma możliwość ustalenia (podsłuchania) źródłowych i docelowych portów oraz adresów IP obu hostów, które są zaangażowane w aktywne połączenie – może on spróbować wstrzykiwać specjalnie spreparowane segmenty (zawierające sfałszowane wartości timestamp) w aktywne połączenie (atak Man-in-the-middle). Jeśli jeden z hostów odbierze tak podrobiony segment może ustawić swój wewnętrzny timer by dopasować się do przesłanej i sfałszowanej wartości timestamp. Jeśli sfałszowana wartość znacznika czasu jest większa od kolejnych wartości pochodzących od prawdziwych segmentów – host odbierający kolejne dane uzna, że przychodzące segmenty są zbyt stare i odrzuci je. W rezultacie przepływ danych między hostami zostanie przerwany.
Podobny wyciek danych występuje w protokole ICMP. Zapytanie ICMP Timestamp (typ 13) pozwala hostowi na poznanie czasu jaki jest aktualny w strefie, w której jest umieszczony zdalny host. Odległy host używa odpowiedzi ICMP Timestamp Replay (typ 14), aby przekazać tę informację hostowi, który o nią poprosił. Odpowiedź od odległego hosta zawiera czas jaki był aktualny, w chwili otrzymania zapytania o ten czas. Czas jest podawany w ilości milisekund jakie upłynęły od czasu północy w Czasie Uniwersalnym (ang. Universal Time (UT)):
nfsec:~# hping3 -V -C 13 -c 3 darkstar.nfsec.pl using eth0, addr: 1.1.1.1, MTU: 1500 HPING darkstar.nfsec.pl (eth0 2.2.2.2): icmp mode set, 28 headers + 0 data bytes len=46 ip=2.2.2.2 ttl=56 id=59885 tos=0 iplen=40 icmp_seq=0 rtt=28.7 ms ICMP timestamp: Originate=57026070 Receive=50367488 Transmit=50367488 ICMP timestamp RTT tsrtt=29 len=46 ip=2.2.2.2 ttl=56 id=59886 tos=0 iplen=40 icmp_seq=1 rtt=21.1 ms ICMP timestamp: Originate=57027070 Receive=50368481 Transmit=50368481 ICMP timestamp RTT tsrtt=22 len=46 ip=2.2.2.2 ttl=56 id=59887 tos=0 iplen=40 icmp_seq=2 rtt=19.3 ms ICMP timestamp: Originate=57028071 Receive=50369479 Transmit=50369479 ICMP timestamp RTT tsrtt=19 --- darkstar.nfsec.pl hping statistic --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 19.3/23.0/28.7 ms
Blokadę tego typu komunikatów ICMP możemy skonfigurować na zaporze systemowej:
iptables -A INPUT -p icmp --icmp-type 13 -j DROP iptables -A OUTPUT -p icmp --icmp-type 14 -j DROP
Warto wspomnieć, że w systemie OpenBSD wartość pierwszego znacznika czasu podczas nawiązywania nowej sesji TCP/IP jest wybierana losowo. W ten sposób wyeliminowany został wyciek informacji dotyczący uptime’mu badanej maszyny. Jeśli chodzi o system Linux to wyłączenie opcji timestamp w protokole TCP powinno być rozważane dla każdej infrastruktury sieciowej z osobna. Szczególnie należy wziąć pod uwagę rodzaj usług jakie świadczy się na poszczególnej maszynie np. mogą wystąpić problemy w przypadku serwerów FTP udostępniających większe objętościowo pliki z prędkością 100 Mbps. Lecz jeśli mimo np. gigabitowej szybkości łącza pojedyncza sesja TCP/IP nie przekracza 10 sekund dla przesyłanych informacji z szybkością 125 MBps – istnieje małe ryzyko wyczerpania się numerów sekwencyjnych i zniekształcenia danych (przykładowa tabela czasów i prędkości oraz wzory znajdują się na 5 i 6 stronie RFC 1323). Nie musimy również się martwić o samą wydajność transferu, która w algorytmie zapobiegania zatorów (ang. congestion avoidance algorithm) TCP Tahoe and Reno ustawiała wielkość okna na podstawie wartości RTT dostarczanej przez znaczniki czasu. Od wersji 2.6.19 i wyższych jądro Linuksa używa standardowo algorytmu CUBIC TCP, który jest niezależny od wartości RTT.
Więcej informacji: Protokół TCP, ISS 52126, ISS 20635, KB 224829, Obtaining System Uptime Remotely, Target-Based TCP Timestamp Stream Reassembly, Misusing TCP Timestamps