Podatność w implementacjach TCP – nowa technika ataków DoS

tcpprobetimerW październiku 2008 roku fiński zespół CERT (FICORA/CERT-FI) został poinformowany przez firmę Outpost24 zajmującą się wdrażaniem rozwiązań bezpieczeństwa sieciowego o obecności krytycznych luk w implementacjach protokołu TCP. Szczegóły odkrytych podatności nie zostały upublicznione – CERT-FI, we współpracy z firmą Outpost24 oraz kilkudziesięcioma producentami sprzętu i oprogramowania, pracują nad oszacowaniem skali problemu i opracowaniem stosownych poprawek. Dokładna charakterystyka odkrytych podatności ma zostać ujawniona, gdy producenci i deweloperzy wyeliminują je ze swoich produktów. Wiadomo jedynie, że problem dotyczy kolejkowania połączeń w protokole TCP i pozwala na przeprowadzenie ataku DoS (ang. Denial of Service). Atak wymaga ustanowienia pełnych połączeń TCP ze zdalnym hostem (ang. three-way handshake), jednak ilość ruchu konieczna do wygenerowania przez atakującego jest stosunkowo mała. Zgodnie z informacjami udostępnionymi przez fiński CERT, prace mające na celu wyeliminowanie tej podatności są na zaawansowanym etapie i najprawdopodobniej jeszcze w 2009 roku producenci wydadzą odpowiednie aktualizacje.

11 czerwca 2009 roku, w magazynie Phrack ukazał się artykuł opisujący nowy mechanizm ataku DoS . Artykuł „Exploiting TCP Persist Timer Infiniteness” autorstwa ithilgore poświęcony jest podatności związanej z mechanizmem czasu oczekiwania (ang. persist timer) wykorzystywanym w protokole TCP do kontroli przepływu (a dokładnie do eliminowania zakleszczeń przy wstrzymaniu transmisji za pomocą zerowej szerokości okna). Spekulowano, że opisany atak jest jednym z ataków zgłoszonych do Fińskiego CERT. Jednakże zespół CERT-FI stwierdził, że chociaż metoda opisana w Phrack’u dotyczy podobnych zagadnień, to nie wykorzystuje słabości protokołu TCP, których dotyczył ich komunikat, a jej upublicznienie w żaden sposób nie wpłynie na koordynowane przez ten zespół prace.

Na czym więc polega nowa metoda ataków DoS ?

Implementacja czasu oczekiwania wyspecyfikowana w dokumentach RFC powstała 20 lat temu i nie była opracowywana pod kątem ochrony przed wysublimowanymi atakami. W ciągu ostatnich lat systemy operacyjne ewoluowały stosując rozwiązania chroniące przez rozmaitymi formami złośliwej aktywności takimi jak ataki DoS, nawet kosztem częściowej niezgodności ze standardami RFC. Jednak implementacja mechanizmu persist timer w jądrach systemu Linux i *BSD (autor artykułu z Phrack’a przeprowadził testy na systemie z jądrem Linux 2.6.18, jak również na systemach *BSD) ściśle stosuje się do RFC i w rezultacie umożliwia przeprowadzenie ataku DoS poprzez wyczerpanie pamięci jądra lub limitów aplikacji sieciowej przy minimalnym wykorzystaniu łącza.


Szerokość okna to 16-bitowa wartość znajdująca się w nagłówku TCP, będąca jednym z mechanizmów kontroli przepływu. Z jej wykorzystaniem jedna ze stron połączenia może poinformować drugą stronę o ilości danych, którą jest w stanie przyjąć bez potwierdzenia. Gdy host nie jest w stanie przetwarzać napływających w dużym tempie danych, wysyła potwierdzenia z mniejszą szerokością okna, dostosowując w ten sposób prędkość transmisji do swojej wydajności. W skrajnym przypadku wysyłane jest powiedzenie z zerową szerokością okna, co stanowi informację dla drugiej strony o konieczności zaprzestania wysyłania danych.

W sytuacji, gdy jedna ze stron otrzymała potwierdzenie z zerową szerokością okna, będzie ona oczekiwała na kolejne potwierdzenie z niezerową szerokością okna informujące o możliwości wznowienia transmisji. Jeśli taki pakiet komunikujący gotowość hosta do odbierania danych ulegnie zagubieniu, nastąpi zakleszczenie (jedna ze stron nie będzie wysyłała danych, gdyż ostatni otrzymany przez nią pakiet miał zerową szerokość okna, druga strona będzie oczekiwała na dane, ponieważ wysłała pakiet z niezerową szerokością okna). Aby wyeliminować takie sytuacje, protokół TCP wykorzystuje mechanizm czasu oczekiwania (ang. persist timer). Odbiorca pakietu z zerową szerokością okna czeka określony czas (kilka do 60 sekund) i wysyła pakiet nazywany próbką szerokości okna (ang. window probe) do drugiej strony – jeśli odpowie ona potwierdzeniem z zerową szerokością okna, cykl oczekiwania jest powtarzany. W przypadku gdy druga strona może już przyjmować dane, odsyła potwierdzenie z niezerową szerokością okna i transmisja jest wznawiana.

Dopóki próbki i odpowiedzi na nie są wysyłane, połączenie będzie cały czas utrzymywane. Protokół TCP nie wymusza ponadto konieczności wysyłania aktualizacji z niezerową szerokością okna – można w nieskończoność jedynie odpowiadać na próbki potwierdzając zerową szerokość okna. Jeśli próbki szerokości okna nie będą potwierdzane, połączenie powinno zostać zamknięte przez drugą stronę (w przypadku systemów Linux maksymalna liczba niepotwierdzonych próbek wynosi 15). Powyższe cechy tego protokołu umożliwiają utrzymywanie połączenia TCP nieskończenie długo przy minimalnym wysiłku ze strony atakującego – w praktyce wystarczy co kilkadziesiąt sekund wysłać pakiet z odpowiedzią na próbkę o rozmiarze kilkudziesięciu bajtów. Zwielokrotnienie takich połączeń pozwala na przeprowadzenie skutecznego ataku DoS.

Atak DoS polega na wykonaniu następujących kroków:

  • ustanawiane jest połączenie TCP z ofiarą na jeden z otwartych portów z wykorzystaniem standardowego mechanizmu three-way handshake – jedyną zmianą jest wysłanie w trzecim pakiecie sekwencji nawiązania połączenia (ACK) payloadu z zapytaniem warstwy aplikacji (np. żądanie HTTP GET), co jest legalną funkcjonalnością protokołu TCP
  • ofiara, w zależności od implementacji stosu sieciowego, odpowie samym pakietem ACK potwierdzającym uprzednio wysłane dane na etapie ustanawiania połączenia (systemy Linux) albo pakietem ACK potwierdzającym uprzednio wysłane dane zawierającym również odpowiedź warstwy aplikacji (systemy *BSD i Windows); w pierwszym przypadku sam pakiet ACK bez payloadu jest ignorowany i wymagane jest odczekanie na dotarcie pakietów z właściwymi danymi (odpowiedzią)
  • podczas odbierania danych z odpowiedzią (w zależności od systemu: po dwóch segmentach w przypadku systemów Linux, po jednym w przypadku *BSD i Windows), atakujący wysyła potwierdzenie ACK z ustawioną zerową szerokością okna; od tej chwili ofiara wysyła co jakiś czas pakiet nazywany próbką szerokości okna – ang. window probe (początkowo po 5 sekundach, czas ten jest stopniowo zwiększany do 60 sekund, same wartości są kontrolowane przez licznik czasu oczekiwania – ang. persist timer)
  • co jakiś czas atakujący musi ponowić wysłanie aktualizacji okna z zerową szerokością, aby zagwarantować utrzymanie połączenia przez druga stronę (jeśli nie otrzyma ona odpowiedzi na określoną liczbę próbek szerokości okna, połączenie jest zamykane – w systemach Linux jest to 15 niepotwierdzonych pakietów window probe)

Pojedyncze połączenie według powyższego scenariusza wygląda następująco (w przypadku systemu Linux):

Atak ten posiada wyższą skuteczność niż ataki wykorzystujące półotwarte połączenia TCP (np. SYN flood), gdyż w powyższym scenariuszu dane przekazywane są aż do warstwy aplikacji. Wysyłanie samych pakietów SYN alokuje jedynie pamięć jądra, a aplikacja nasłuchująca na tym porcie „nie widzi” takiego ruchu. Prezentowana metoda jest także skuteczniejsza niż ataki polegające na ustanowieniu pełnego połączenia TCP, wysłaniu zapytania warstwy aplikacji (takie jak HTTP GET), po czym porzuceniu połączenia bez informowania o tym drugiej strony – oprócz alokacji zasobów ofiary (pamięć jądra oraz maksymalna liczba otwartych połączeń) dodatkowo powoduje to zapychanie łącza przez odpowiedź na zapytanie i jej retransmisje inicjowane przez protokół TCP. Nowoczesne systemy operacyjne posiadają jednak zabezpieczenia przed takimi sytuacjami – gdy brakuje pamięci z powodu ustanowienia zbyt dużej liczby połączeń, takie porzucone gniazda (ang. orphaned sockets) są sukcesywnie zamykane, zwalniając zasoby nowym połączeniom.

Za pomocą podatności związanej z mechanizmem persist timer można ominąć zaimplementowane w systemach operacyjnych zabezpieczenia przed atakami DoS i w rezultacie doprowadzić do wyczerpania zarówno pamięci jądra, jak również limitów aplikacji nasłuchujących na atakowanym porcie (takich jak maksymalna liczba otwartych jednocześnie połączeń). Podatne systemy mogą utrzymywać ustanowione tą techniką połączenia praktycznie przez nieskończony czas, o ile warstwa aplikacji nie posiada dodatkowych mechanizmów zamykających niewykorzystywane połączenia. Na przykład popularny serwer www Apache w domyślnej konfiguracji zamyka nieaktywne sesje po 5 minutach, niezależnie od działania protokołu TCP. W takich przypadkach atakujący musi ponownie przeprowadzić całą procedurę. Autor koncepcji sugeruje, że zaatakowanie pojedynczej usługi (jednego portu TCP) najprawdopodobniej wpłynie tylko na wyczerpanie limitów tej usługi i w efekcie jej niedostępność, natomiast nie zużyje całej pamięci jądra. Aby doprowadzić do niedostępności całego systemu w wyniku wyczerpania zasobów jądra, atak należałoby przeprowadzić na wiele otwartych portów TCP ofiary. Skuteczność ataku jest wtedy wprost proporcjonalna do liczby atakowanych portów i liczby połączeń ustanowionych z każdym z portów.

Do publikacji w Phrack’u został załączony program Nkiller2, który automatyzuje opisywaną procedurę ataku. Przeprowadzone przez nas testy (z których pochodzą przedstawione powyżej zrzuty ekranu) wskazują, że jest on w stanie przeprowadzić skuteczny atak DoS na serwer Apache z domyślną konfiguracją przy minimalnym wykorzystaniu łącza (domyślna liczba 256 jednoczesnych połączeń zostaje szybko osiągnięta i serwer nie jest w stanie obsługiwać nowych żądań). Ponieważ Apache zamyka (domyślnie) po 5 minutach nieaktywne połączenia, muszą być one ponownie otwierane po upływie tego czasu (co Nkiller2 także pozwala zautomatyzować).

Obecne implementacje systemów operacyjnych są kompromisem między zgodnością ze standardami a względami praktycznymi – najlepiej świadczą o tym komentarze we fragmencie kodu jądra Linuksa implementującego persist timer (plik net/ipv4/tcp_timer.c) zawierające polemikę programistów dotyczącą poprawnej implementacji tego licznika i zgodności z dokumentem RFC 1122 (Requirements for Internet Hosts – Communication Layers). Opisywana podatność jest więc wynikiem różnicy zdań deweloperów i ostatecznego zastosowania się do przestarzałych dokumentów RFC. Co ciekawe, w jądrze systemu Solaris opisywana właściwość licznika persist timer została uznana za błąd i skorygowana mimo niezgodności takiego rozwiązania ze standardami. Autor artykułu sugeruje, że nie istnieje prosty sposób obrony przed tak skonstruowanym atakiem bez modyfikacji jądra systemu operacyjnego. Doradza, że w pewnym stopniu ochronę może zapewnić stanowy firewall pozwalający na ograniczenie całkowitej liczby pakietów, które pochodzą od pojedynczego hosta. Biorąc jednak pod uwagę specyfikę i złożoność tworzonych obecnie serwisów WWW, trudno wyobrazić sobie zastosowanie tej metody w praktyce (przynajmniej w przypadku protokołu HTTP, który jest najczęstszym obiektem ataków DoS).

Linki:
Exploiting TCP and the Persist Timer Infiniteness (Phrack)
CERT-FI Statement on the Outpost24 TCP Issues
TCP DoS Vulnerabilities
Requirements for Internet Hosts – Communication Layers (RFC 1122)
Transmission Control Protocol (RFC 793)

Tags: , , , , , , ,

Comments are closed.