Dziurawimy NATy jak szmaty za pomocą UDP Hole Punching
Napisał: Patryk Krawaczyński
Wczoraj w Bezpieczeństwo Brak komentarzy. (artykuł nr 943, ilość słów: 1342)
Z
e względu na ograniczoną liczbę publicznych adresów IPv4, a także aby chronić systemy przez zagrożeniami z internetu wiele komputerów umieszczanych jest za zaporami sieciowymi. W wielu przypadkach funkcję zapory sieciowej pełni domowy / firmowy router, który również tłumaczy lokalny adres sieciowy komputera np. 192.168.0.10 na publiczny adres IP od ISP za pomocą mechanizmu translacji adresów sieciowych, czyli NAT (ang. Network Address Translation). W połączeniu ze stanowymi regułami zapory sieciowej teoretycznie oznacza to, że atakujący nie może bezpośrednio z internetu połączyć się z komputerem wewnątrz takiej sieci – pierwsze / inicjujące połączenie musi być nawiązane z wewnątrz chronionej sieci. W takiej konfiguracji, gdy dwa komputery są za różnymi zaporami stanowymi (ang. stateful firewall) z mechanizmem NAT i będą chciały skomunikować się ze sobą bezpośrednio – niezależnie od tego, który z nich rozpocznie połączenie, zapora sieciowa tego drugiego może odrzucić przychodzące pakiety danych.
Aby rozwiązać ten problem, stworzono UDP Hole Punching. Dlaczego wykorzystano akurat protokół UDP (ang. User Datagram Protocol)? Możliwość dostania się do sieci za mechanizmem NAT przy użyciu protokołu UDP wynika ze specyficznej charakterystyki tego protokołu oraz sposobu, w jaki NAT zarządza jego sesjami komunikacyjnymi. W przeciwieństwie do TCP, który wymaga trójstopniowego uzgadniania połączenia (ang. handshake) i ścisłego śledzenia sekwencji bajtów, UDP jest protokołem bezpołączeniowym. Urządzenia NAT traktują pakiety UDP jako „strumienie”, które wymagają jedynie utworzenia tymczasowego mapowania w tablicy translacji. Gdy host wewnątrz sieci LAN wyśle pakiet UDP na „zewnątrz” (np. do internetu / innej sieci), mechanizm NAT otwiera „port wyjściowy” i przez pewien czas pozwala na powrót pakietów z tego samego adresu zewnętrznego na ten port. RFC 3489 definiuje cztery główne typy NAT, które różnią się restrykcyjnością:
- Full Cone – każdy host zewnętrzny może wysłać pakiet na otwarty port.
- Restricted Cone – tylko host, do którego wcześniej został wysłany pakiet, może odpowiedzieć.
- Port Restricted Cone – tylko host z portu, do którego wcześniej został wysłany pakiet, może odpowiedzieć.
- Symmetric NAT – każde nowe połączenie do innego celu dostaje inny port publiczny.
UDP pozwala na przejście przez pierwsze trzy typy stosunkowo łatwo, ponieważ raz otwarte „mapowanie” portu (de facto „dziura sieciowa”) może być wykorzystane do odebrania ruchu ze świata. Wspomniane implementacje NAT „ufają”, iż pakiety przychodzące na port, z którego niedawno wysłano dane, są odpowiedzią. W protokole TCP system operacyjny odrzuciłby pakiety przychodzące bez odpowiednich numerów sekwencyjnych i flag (np. SYN/ACK). W UDP to aplikacja dziurawiąca NAT / zaporę sieciową ma pełną kontrolę nad pakietem i może samodzielnie zinterpretować dane, które „przecisnęły” się przez mechanizm ochrony. Sytuacja staje się nieco bardziej skomplikowana dla czwartego typu, gdy zapora sieciowa przypisuje za każdym razem inne porty – pierwszemu port 31337, kolejnemu 31338 itd. Wówczas wymagane jest sekwencyjne testowanie portów powyżej pierwotnego połączenia, mając nadzieję, że w pewnym momencie trafimy na właściwy.
No dobrze, ale jak dwie różne osoby mają się ze sobą komunikować za mechanizmem NAT skoro żadna z nich nie wie jakie są ich adresy publiczne i porty? Lub w przypadku czwartego typu mechanizmu NAT – sieć jest bardzo aktywna i nie można znaleźć prawidłowego, otwartego portu albo porty są przypisywane losowo, a nie sekwencyjnie? Tutaj wkracza serwer STUN (ang. Session Traversal Utilities for NAT) stosowany w komunikatorach do rozmów głosowych (VoIP – ang. Voice over IP), serwerach gier, czy aplikacjach P2P (ang. Peer-to-Peer). Jest to publicznie dostępny „rozgłośnik” (ang. broadcaster), którego jedynym celem jest pomoc urządzeniu za NAT-em w odnalezieniu portów, które NAT przypisuje połączeniom wychodzącym. Możemy uznać, że jest to przyjazna usługa echa w internecie, która mówi nam: „tak jesteś widziany z internetu”. W ten sposób dwie osoby za mechanizmem NAT mogą połączyć się ze sobą. Serwer STUN przekazuje użytkownikom niezbędne informacje, aby mogli między sobą nawiązać komunikację. W przypadkach, gdy trudne jest odkrycie „powrotnych” portów do komunikacji wykorzystywany jest serwer TURN (ang. Traversal Using Relays around NAT). Działa on jak „pośrednik” (ang. relay) przez którego urządzenia nie mogące się połączyć bezpośrednio przesyłają całą komunikację. Oba urządzenia wysyłają dane do serwera TURN, a ten przekazuje je dalej do odpowiedniego uczestnika. Zaletą tego rozwiązania jest jego bardzo duża skuteczność w wielu rodzajach NAT oraz zapór sieciowych. W nowoczesnych aplikacjach wszystkie te „sztuczki” połączono pod szyldem ICE (ang. Interactive Connectivity Establishment). Technika ta najpierw próbuje połączyć się lokalnie (w ramach tej samej sieci). Jeśli to zawiedzie, używa STUN, by spróbować połączenia bezpośredniego przez internet. Jeśli zapora sieciowa jest zbyt restrykcyjna, w ostateczności przełącza się na TURN.
Demo UDP Hole Punching:
Za pomocą kilku prostych narzędzi możemy samemu przeprowadzić technikę dziurawienia NAT za pomocą UDP. Wystarczą takie narzędzia jak netcat i hping3. Nasza architektura sieciowa będzie wyglądać następująco: komputer lokalny (Raspberry PI – Linux) jest umieszczony za zaporą stanową / NAT (Mikrotik – RouterOS), która zezwala (ACCEPT) tylko na połączenia do niego w stanie ESTABLISHED oraz RELATED. Wykona on dziurę w routerze dla zdalnego serwera (Darkstar-C2), który nawiąże z nim komunikację zwrotną.
[ Raspberry PI ]---[ Mikrotik (NAT, Firewall) ]---[ISP Modem (NAT) ]---[ Darkstar-C2 ]
Na Raspberry PI poznajemy nasz adres publiczny IP oraz ustanawiamy nasłuch na porcie 31337 protokołu UDP:
agresor@wingzero:~ $ curl ifconfig.me; echo -e '\n' 89.230.160.158 agresor@wingzero:~ $ nc -v -u -l -p 31337 Bound on 0.0.0.0 31337
Z poziomu Darkstar-C2 próbujemy nawiązać połączenie na adres: 89.230.160.158:31337:
root@darkstar:~# echo "Hello Moto!" | nc -v -w1 -p 31338 -u 89.230.160.158 31337
Jednak zgodnie z oczekiwaniami, nic nie zostało odebrane na komputerze o nazwie wingzero i dzięki zaporze sieciowej, nic nie jest zwracane do darkstar. Teraz na drugiej konsoli wingzero za pomocą narzędzia hping3 wygenerujemy pakiet UDP, który przebiję dziurę w routerze i jego zaporze sieciowej:
root@wingzero:~# hping3 -c 1 -2 -s 31337 -p 31338 darkstar.nfsec.pl HPING darkstar.nfsec.pl (eth0 147.135.209.161): udp mode set, 28 headers + 0 data bytes ICMP Port Unreachable from ip=147.135.209.161 name=nfsec.pl status=0 port=31337 seq=0 --- darkstar.nfsec.pl hping statistic --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max = 29.7/29.7/29.7 ms
Odpowiedź protokołem ICMP z komunikatem: Port Unreachable jest prawidłową reakcją systemu operacyjnego darkstar na próbę komunikacji z zamkniętym portem i nie ma dla nas żadnego znaczenia. Dla nas ważne jest, że na routerze Mikrotik w tablicy połączeń powinniśmy zobaczyć wpis:
protocol=udp src-address=10.0.0.5:31337 dst-address=147.135.209.161:31338
reply-src-address=147.135.209.161:31338 reply-dst-address=192.168.1.10:31337
timeout=5s orig-packets=1 orig-bytes=28 orig-fasttrack-packets=0
orig-fasttrack-bytes=0 repl-packets=0 repl-bytes=0 repl-fasttrack-packets=0
repl-fasttrack-bytes=0 orig-rate=0bps repl-rate=0bps
Gdy pakiet UDP przeszedł przez router (łańcuch FORWARD) mechanizm śledzenia połączeń (conntrack) utworzył rozbudowany wpis, który śledzi połączenie dla obu kierunków: 1) kierunek oryginalny – źródłowy IP i port (klient w sieci LAN – 10.0.0.5:31337) oraz docelowy IP i port (serwer w internecie – 147.135.209.161:31338); 2) kierunek odpowiedzi – źródłowe IP i port (serwer w internecie – 147.135.209.161:31338) oraz docelowe IP i port (zewnętrzny adres IP routera – 192.168.1.10:31337 – tutaj inny adres wewnętrzny LAN bo router stoi jeszcze za modemem ISP). Daje nam to 5’cio sekundowe okno (timeout=5s), aby odpowiedzieć z serwera 147.135.209.161 (darkstar) i portu 31338, aby dostać się do komputera o nazwie wingzero w sieci lokalnej, który nasłuchuje na adresie 10.0.0.5 i porcie 31337. Dlatego druga próba komunikacji z darkstar:
root@darkstar:~# echo "Hello Moto!" | nc -v -w1 -p 31338 -u 89.230.160.158 31337 agresor@wingzero:~ $ nc -v -u -l -p 31337 Bound on 0.0.0.0 31337 Connection received on darkstar.nfsec.pl 31338 Hello Moto!
Kończy się powodzeniem i na konsoli wyskakuje komunikat „Hello Moto!”. Stało się tak, ponieważ gdy zewnętrzny host (darkstar) odpowiedział w zadanym czasie, router sprawdził tabelę śledzenia połączeń i znalazł pasujący wpis (zgodność adresów IP i portów). Pakiet otrzymał stan ESTABLISHED, który jest dozwolony (ACCEPT) dla ruchu przechodzącego przez router do i z sieci lokalnej (FORWARD). W ten prosty sposób pakiet „prześlizguje się” przez zaporę i trafia do komputera w sieci lokalnej.
Więcej informacji: Peer-to-Peer Communication Across Network Address Translators, Linux: The hole trick to bypass firewall restriction, STUN, TURN
Poprzedni wpis Brak nowszych postów

