Dostajesz maila z pogróżkami: Wykryliśmy problem w Twojej sieci. Jeśli zapłacisz xxxx zł w bonach z Żabki, dodamy Twoją sieć do natychmiastowej obrony anty-DDoS. Tak zaczyna się historia problemów wielu ISP. Niby niewielkie wymuszenie, ale coraz więcej operatorów boryka się z tego typu sytuacjami. Tego typu atak ma już swoją nazwę Atak dywanowy i jest kierowany w kolejnych polskich ISP.
EPIX jako węzeł wymiany ruchu w swoich założeniach powinien skupiać się na pewnej i szybkiej wymianie ruchu w warstwie L2 – zapewnić przesyłanie pakietów pomiędzy uczestnikami i dostarczyć informacje o routingu w OpenPeering. Nie możemy jednak pozostać bierni wobec tego, co się dzieje, dlatego systemowo podchodzimy do rozwiązywania problemów naszych uczestników. Poza budową scrubbing center staramy się edukować społeczność – i ten artykuł jest właśnie tego częścią: to kompilacja wiedzy o tym, na czym polega atak, zachęta do podjęcia działania oraz przykładowe propozycje rozwiązań. A właściwie: propozycje działań, które utrudnią życie atakującym.
Opis ataku
Mamy do czynienia z atakiem z rodziny reflection/amplification, opartym w całości na samym zachowaniu protokołu TCP – bez wykorzystania jakiejkolwiek luki czy błędu w oprogramowaniu. Atakujący nie kieruje ruchu wprost na ofiarę; zamiast tego posługuje się setkami czy tysiącami legalnie działających serwerów WWW jako nieświadomymi odbijaczami (reflektorami), które przy okazji pełnią rolę multiplikatorów natężenia ruchu.
Punktem wyjścia jest spoofing adresu źródłowego. Atakujący wysyła pakiety TCP/SYN, w których jako adres nadawcy podstawia adres IP ofiary, a jako adres docelowy – adresy serwerów obsługujących HTTP i HTTPS (porty 80 i 443). Z punktu widzenia takiego serwera wygląda to jak najzwyklejsza próba nawiązania połączenia: zgodnie ze specyfikacją odsyła pakiet SYN/ACK, rozpoczynając trójstronne uzgadnianie (handshake), tyle że odpowiedź trafia nie do atakującego, lecz do ofiary, której adres widnieje w nagłówku.
I tu pojawia się sedno problemu. Ofiara nigdy nie inicjowała tego połączenia, więc nawet jeśli SYN/ACK dotrze do działającego hosta, jego stos TCP nie znajdzie w tablicy pasującego wpisu. Warto jednak zaznaczyć, że goły stos TCP (Linux, Windows) w takiej sytuacji domyślnie odpowiada pakietem RST i to właśnie ten RST przerwałby cały mechanizm. Dlaczego więc atak działa?
Odpowiedź tkwi w realiach sieci operatorskich, do których ten atak jest skrojony. Po pierwsze, ofiarą rzadko bywa pojedynczy host; celem są zwykle całe, duże klasy adresowe, w tym zakresy nieużywane lub przydzielone, ale nieobsadzone żadnym aktywnym urządzeniem. Pakiety SYN/ACK trafiają wtedy w czarne dziury: nie ma komu ich odrzucić, nie ma kto odpowiedzieć RST-em. Z perspektywy serwera-reflektora wygląda to identycznie jak pakiet zagubiony w sieci, więc, dokładnie tak jak każe protokół, ponawia transmisję. I jeszcze raz. I jeszcze raz.
Po drugie, nawet tam gdzie pod adresem ofiary kryją się realne hosty, w sieciach operatorskich powszechny jest NAT oraz urządzenia brzegowe, które nieoczekiwany, niepasujący do żadnej sesji ruch po prostu po cichu dropują, zamiast odsyłać RST. Efekt jest ten sam co przy czarnej dziurze: brak jakiejkolwiek odpowiedzi, którą reflektor mógłby zinterpretować jako koniec połączenia, a zatem retransmisja za retransmisją.
Każda taka retransmisja to kolejny pakiet lądujący w sieci ofiary. W zależności od konfiguracji stosu TCP po stronie serwerów-multiplikatorów cykl powtarza się zwykle od 6 do 12 razy, zanim połączenie zostanie ostatecznie porzucone. Pojedynczy spreparowany pakiet wysłany przez atakującego zamienia się więc w kilkanaście pakietów uderzających w ofiarę i to wysłanych nie przez samego atakującego, lecz przez wiarygodne serwisy WWW rozsiane po całej Polsce. Efektem są miliony pakietów zalewających łącze ofiary, pochodzących z adresów, które same w sobie są całkowicie legalne.
Na tym właśnie polega perfidia tego ataku: nie istnieje przed nim prosta metoda obrony. Ruchu nie da się ot tak odfiltrować po adresie źródłowym, bo płynie on z prawdziwych serwerów HTTP(S) – blokując go, ofiara odcięłaby przy okazji własny, legalny ruch webowy. Nie pomoże też blokada po porcie, bo to ten sam port, na którym odbywa się normalna komunikacja ze stronami.
Realnym rozwiązaniem pozostaje stanowy firewall (stateful firewall) ustawiony na brzegu sieci ofiary. Śledzi on stan połączeń i wie, które z nich faktycznie zostały zainicjowane od wewnątrz. Gdy dociera do niego SYN/ACK niepasujący do żadnego wpisu w tablicy połączeń, zamiast po cichu go odrzucić, odsyła pakiet TCP/RST. Ten RST jest dla serwera-reflektora jednoznacznym sygnałem, że połączenia nie ma i nie będzie – co natychmiast przerywa łańcuch retransmisji i likwiduje efekt multiplikacji u samego źródła.
Jak się możemy bronić?
Tak naprawdę jedyną prawdziwą obroną jest higiena własnej sieci. I tak, to, że Twoja sieć nie jest w tej chwili atakowana, wcale nie znaczy, że komputery-zombie z Twojego zakresu, będące częścią botnetu, nie atakują właśnie teraz innych operatorów. Ten typ ataku da się wyciąć wyłącznie u źródła: blokując wysyłanie spoofowanych pakietów. A to Wy, operatorzy, macie zarówno narzędzia, jak i wiedzę o tym, co powinno wychodzić z Waszych sieci, a co nie.
Fakt, że nie jesteś w tej chwili atakowany – a atakowanie innych Ci nie przeszkadza – nie oznacza wcale, że jutro to Twoja sieć nie stanie się celem i to Ty będziesz miał problem. Najsmutniejsze jest to, że odpowiedni dokument istnieje od ćwierćwiecza. W maju 2000 roku – 26 lat temu – powstał RFC 2827 (znany też jako BCP 38), który wprost opisuje, jak konfigurować sieci operatorskie, by zapobiegać podszywaniu się pod cudze adresy źródłowe. W praktyce sprowadza się to do filtrowania ruchu wychodzącego (ingress filtering na brzegu klienta) – często realizowanego mechanizmem uRPF – tak by z danego zakresu mogły wychodzić wyłącznie pakiety o adresach źródłowych faktycznie do niego należących. To trochę analogia do szczepień, implementując rozwiązania z BCP 38 u siebie wzmacniamy odporność całej polskiej cyberprzestrzeni.
Przy niewielkich sieciach, mających po kilkanaście czy kilkadziesiąt prefiksów, cała operacja zajmuje kilkanaście minut i nie wpływa zauważalnie na obciążenie współczesnych routerów. I to jest nasza wspólna, społecznościowa metoda obrony – działająca jeszcze zanim ktokolwiek zostanie zaatakowany. Im więcej sieci ją wdraża, tym mniej miejsc, z których spoofing w ogóle może wyjść.
Trwa atak?
Tu już nie jest tak różowo. Jak wspomniałem wcześniej, prawidłowo skonfigurowany firewall czy stos TCP – taki, który na out-of-state SYN/ACK odsyła RST zamiast go po cichu dropować – powinien sobie z atakiem poradzić. Z doświadczenia wiem jednak, że teoria rozjeżdża się z praktyką. Większość konsumenckich ONT-ów i routerów robi NAT do sieci użytkownika i zazwyczaj jest na ten atak podatna: po cichu dropuje pakiety niezwiązane z żadną znaną im sesją, zamiast odpowiedzieć resetem. To realny problem, na który operator ma ograniczony wpływ.
Co więc zostaje w trakcie ataku? Po pierwsze – jeśli masz sporo nieużywanych prefiksów, po prostu ich nie rozgłaszaj; to, czego nie ma w tablicach routingu, nie ściągnie na siebie odbitego ruchu. Po drugie – zakresy adresacji, których nie używasz, skieruj do reguł firewalla odsyłających TCP/RST, dokładnie tak, jak opisano w sekcjach poniżej. Tu jednak ostrożnie: urządzenie masowo generujące RST samo może stać się reflektorem dla innego ataku, więc taką regułę trzeba ograniczyć do własnych, nieobsadzonych zakresów i nie odpowiadać na ruch spoza nich.
No i wreszcie NAT na Twoich urządzeniach – tu również nie jesteś do końca bezbronny.
Ochrona nieaktywnych zakresów w sieci BNG (BRAS) /PPPoE
Skoro atak żywi się ciszą – brakiem RST-a tam, gdzie pakiet trafia w nieobsadzony adres – to najskuteczniejszą obroną jest zamienić każdą taką czarną dziurę w urządzenie, które na nieoczekiwany SYN/ACK świadomie odpowiada resetem. W sieci operatorskiej z terminacją PPPoE na BNG/BRAS daje się to zrobić wyjątkowo elegancko, bo sama infrastruktura dostarcza gotowy sygnał ten adres jest aktywny: obecność trasy hostowej /32.
Mechanizm opiera się na regule longest-prefix match. Gdy sesja PPPoE klienta wstaje, BNG instaluje dla jego adresu trasę /32 wskazującą na interfejs subskrybenta (framed route). Gdy sesja pada – ta trasa /32 znika. Dla całej puli adresowej subskrybentów (np. /20) utrzymujemy natomiast trasę pokrywającą – mniej szczegółową – kierującą ruch na firewall lub dedykowany serwer odsyłający RST. Rozdział ruchu dzieje się wtedy automatycznie, bez żadnej dodatkowej logiki:
- adres aktywny – wygrywa bardziej szczegółowa trasa /32 z BNG, ruch trafia do klienta;
- adres nieaktywny – brak /32, więc wygrywa trasa pokrywająca, a ruch ląduje na urządzeniu odsyłającym reset.
Zamiast więc kierować nieużywaną przestrzeń adresową w null-route (klasyczna czarna dziura, która milczy i tym samym napędza retransmisje reflektora), kierujemy ją tam, gdzie każdy out-of-state SYN/ACK spotka się z RST-em. A ponieważ ataki tego typu celują właśnie w duże, rzadko obsadzone zakresy, trafiamy dokładnie w sam środek wektora.
Dedykowany serwer-responder
Rolę RST-respondera może pełnić sam firewall brzegowy, ale równie dobrze można obok niego postawić maszynę dedykowaną do tego zadania – rodzaj kontrolowanej ofiary do atakowania, która przejmuje na siebie cały ruch do martwych adresów. W obu wariantach kluczowa jest maska, a nie metryka: to mniej szczegółowy prefiks (np. /20 wobec /32 aktywnego klienta) sprawia, że responder z definicji dostaje wyłącznie ruch do adresów nieobsadzonych. Metryka rozstrzyga co innego – rywalizację między trasami tej samej długości – więc przydaje się dopiero do redundancji (firewall jako trasa podstawowa, serwer jako zapasowa ogłaszająca ten sam prefiks z gorszą metryką), a nie do samej selekcji aktywny kontra nieaktywny.
Tu jednak czai się pułapka, która potrafi zniweczyć cały pomysł. Goły stos systemowy odpowiada RST-em na nieoczekiwany SYN/ACK tylko wtedy, gdy pakiet jest zaadresowany na jego własny, lokalny adres IP. W tym scenariuszu SYN/ACK leci na adres klienta z puli /20 – adres, którego serwer nie posiada. Jeśli trasa po prostu wskazuje serwer jako next-hop, maszyna zobaczy obcy adres docelowy i albo spróbuje pakiet forwardować dalej, albo odrzuci go jako martian – w żadnym wypadku nie wygeneruje resetu. Innymi słowy: postawiony na goło serwer będzie po prostu kolejną czarną dziurą.
Żeby responder faktycznie resetował, musi przygarnąć całą pulę jako swoją. W praktyce oznacza to skonfigurowanie całego zakresu jako lokalnego na tej maszynie i politykę default-deny z jawnym resetem – na Linuksie REJECT –reject-with tcp-reset (iptables/nftables) – albo użycie dedykowanego respondera czy tarpita nasłuchującego na całym prefiksie i generującego RST. To świadoma konfiguracja, a nie efekt uboczny gołego stosu, i właśnie to rozróżnienie decyduje o tym, czy rozwiązanie działa, czy tylko sprawia takie wrażenie.
Wymiarowanie i zakres ochrony
Dwie rzeczy warto mieć z tyłu głowy, zanim taka konstrukcja trafi do produkcji. Po pierwsze, responder staje się ujściem ataku: cały odbity ruch do nieaktywnych adresów koncentruje się na jednym węźle. Same RST-y są malutkie i bezstanowe, więc ich generowanie jest tanie – ale odbiór milionów pakietów na sekundę to już kwestia wydajności PPS, obsługi przerwań i karty sieciowej, a nie pasma. Zwykły serwer ma tu swój sufit; przy poważnym ataku trzeba albo sięgnąć po generowanie RST w jądrze (XDP/eBPF, przed całym stosem sieciowym), albo liczyć się z tym, że pod obciążeniem responder również padnie – i wtedy znów zapadnie cisza zamiast resetu. Tę ofiarę do atakowania trzeba więc wymiarować pod realny wolumen, a nie stawiać na zapas.
Po drugie, technika ta domyka konkretnie lukę blackhole na nieobsadzonych zakresach, a nie cały problem. Subskrybent z aktywną sesją ma swoją trasę /32, więc odbity SYN/ACK zostanie mu normalnie dostarczony przez BNG – a z multiplikacją musi sobie poradzić jego CPE, które, jak ustaliliśmy wcześniej, zwykle po cichu dropuje ruch za NAT-em. Ochrona nieaktywnych zakresów i obrona aktywnych klientów to zatem dwa uzupełniające się elementy, nie zamienniki.
Przykłady konfiguracji
Wracamy tu do zapowiedzianej obrony NAT na Twoich urządzeniach. Poniższe przykłady dotyczą właśnie urządzenia operatora wykonującego NAT (brzegowy BNG, CGNAT, router/firewall translujący ruch subskrybentów) – a nie abstrakcyjnego firewalla gdzieś z boku. To istotne, bo NAT i tak opiera się na tablicy stanów połączeń (conntrack / session table); skoro więc urządzenie już śledzi sesje na potrzeby translacji, można je skłonić, by na pakiet spoza tej tablicy odpowiadało resetem zamiast cichego dropu. Sam NAT RST-a nie wysyła – robi to moduł stanowy na tym samym urządzeniu.
Cała teza obronna sprowadza się więc do jednego: urządzenie robiące NAT ma na out-of-state SYN/ACK odpowiedzieć RST-em, a nie po cichu go zdropować. Poniżej konkretne realizacje na trzech popularnych platformach plus wariant z dedykowanym serwerem-responderem. Warto od razu zaznaczyć, że platformy różnią się tu zasadniczo – od mechanizmu wprost stworzonego do tego zadania (Juniper) po taki, który celuje w coś innego i wymaga obejścia (Cisco).
Juniper SRX
Najczystszy przypadek – Junos ma dedykowaną opcję, która wysyła RST w odpowiedzi na segment TCP z dowolną flagą inną niż czysty SYN, jeśli nie pasuje on do żadnej istniejącej sesji. Dokładnie scenariusz reflektora:
set security flow tcp-session tcp-rst
Decyzja zapada na ścieżce first path obsługi flow: przychodzący SYN/ACK nie tworzy sesji (bo nie jest pakietem SYN), więc zamiast cichego dropu urządzenie odsyła RST do nadawcy – czyli do serwera-reflektora. Domyślnie funkcja jest wyłączona, trzeba ją włączyć jawnie.
MikroTik (RouterOS)
Tu realizacja opiera się na regule filtra odrzucającej ruch w stanie invalid z jawnym resetem. Haczyk dotyczy klasyfikacji stanu: przy domyślnym loose-tcp-tracking=yes błąkający się SYN/ACK może zostać oznaczony jako new zamiast invalid i ominąć regułę. Dlatego najpierw zaostrzamy śledzenie połączeń:
/ip firewall connection tracking set loose-tcp-tracking=no
/ip firewall filter add chain=forward protocol=tcp connection-state=invalid \
action=reject reject-with=tcp-reset
Po tej zmianie pakiet TCP niepasujący do żadnego wpisu w conntracku trafia w stan invalid, a reguła odsyła tcp-reset, dając reflektorowi jednoznaczny sygnał końca połączenia.
Cisco ASR (IOS-XE / ZBFW)
To przypadek, w którym trzeba uważać. Feature TCP Reset Segment Control w parameter-map type inspect nie służy do resetowania pakietów spoza sesji – odsyła RST dopiero w momencie usuwania (wygaśnięcia) sesji half-open, half-close lub idle, po upływie odpowiedniego timera:
parameter-map type inspect pmap-name tcp synwait-time 10 tcp half-open reset on tcp idle reset on
Domyślne zachowanie ZBFW dla pakietu niepasującego do żadnej sesji to natomiast cichy policy drop (class-default), bez RST. Innymi słowy: na ASR powyższa konfiguracja przyspieszy uprzątanie półotwartych sesji i wyśle dla nich reset po timerze, ale nie zareaguje resetem natychmiast na błąkający się SYN/ACK od reflektora – a o to właśnie chodzi w tym ataku. Na tej platformie pewniejszym rozwiązaniem jest skierowanie nieobsadzonych zakresów na dedykowany serwer-responder (poniżej), a samą konfigurację ZBFW pod kątem stray SYN/ACK warto zweryfikować w labie na konkretnej wersji IOS-XE.
Dedykowany serwer-responder (Linux)
Najbardziej przewidywalny wariant, niezależny od specyfiki vendora. Maszyna musi najpierw przygarnąć całą pulę jako lokalną – inaczej, jak omówiono wyżej, sama stanie się czarną dziurą. Na Linuksie służy do tego trasa typu local (AnyIP), która każe jądru traktować cały zakres jak własne adresy:
ip route add local 198.51.100.0/24 dev lo
Następnie polityka default-deny z jawnym resetem dla ruchu spoza istniejących (zainicjowanych od wewnątrz) sesji. Ponieważ ten host nigdy sam nie inicjuje połączeń do tych adresów, każdy przychodzący SYN/ACK jest z definicji nieoczekiwany i zostaje zresetowany:
# nftables
table inet responder {
chain input {
type filter hook input priority 0; policy drop;
ct state established,related accept
ct state invalid tcp reset
tcp flags & (syn|ack) == syn|ack ct state new reject with tcp reset
}
}
Przy bardzo dużym wolumenie nawet to ma sufit wydajnościowy stosu – wtedy generowanie RST przenosi się do jądra przed właściwym stosem sieciowym (XDP/eBPF), co pozwala odpowiadać przy znacznie wyższym PPS.
Firewall z Żabki – czy warto płacić okup?
Wróćmy na chwilę do maila z pogróżkami, od którego zaczęliśmy. Jego autorzy liczą dokładnie na to, że zapłacisz – bo wydaje Ci się, że nie masz wyboru i że obrona jest poza Twoim zasięgiem. Tymczasem cały ten atak żywi się jedną rzeczą: ciszą. Ciszą serwera-reflektora, który nie dostaje RST-a i retransmituje. Ciszą czarnej dziury na nieobsadzonym zakresie. Ciszą CPE, które po cichu dropuje za NAT-em. I – u samego źródła – ciszą sieci, które pozwalają wychodzić spoofowanym pakietom, bo nikt nie skonfigurował filtrowania.
Każdą z tych cisz da się przerwać, a narzędzia istnieją od lat: stanowy firewall odsyłający TCP/RST, świadome zarządzanie nieużywanymi prefiksami, responder na martwych zakresach, a przede wszystkim – filtrowanie ruchu wychodzącego zgodnie z RFC 2827. Żadne z tych rozwiązań nie wymaga płacenia okupu w bonach. Wymaga za to czegoś, czego przestępca Ci nie sprzeda: kilkunastu minut pracy i odrobiny wspólnotowej odpowiedzialności.
I to jest sedno. Obrona przed tym atakiem nie jest grą w pojedynkę. Twoja poprawnie skonfigurowana sieć chroni nie tylko Ciebie – chroni wszystkich pozostałych, bo o jedno źródło spoofingu mniej to mniej amunicji dla atakujących w całej Polsce. Działa to też w drugą stronę: korzystasz z higieny innych operatorów. Im więcej nas, tym ciaśniej atakującym.
Co możesz zrobić już dziś?
- Wdróż filtrowanie ruchu wychodzącego (RFC 2827 / BCP 38). Na brzegu własnej sieci zadbaj, by z każdego zakresu mogły wychodzić wyłącznie pakiety o adresach źródłowych faktycznie do ciebie należących – najprościej mechanizmem uRPF. To najważniejszy punkt na tej liście.
- Nie rozgłaszaj prefiksów, których nie używasz. Czego nie ma w tablicach routingu, to nie ściągnie na siebie odbitego ruchu. Bardziej wrednym rozwiązaniem prygotowanie sobie szybkiej ścieżki wyłączenia rozgłaszania nieużywanych prefiksów w przypadku wykrycia ataku – takie działanie spali część zasobów atakującego.
- Skonfiguruj stanowy firewall/NAT tak, by odsyłał TCP/RST na pakiety spoza tablicy sesji, zamiast po cichu je dropować – zgodnie z przykładami dla Twojej platformy powyżej.
- Skieruj nieobsadzone zakresy do respondera odsyłającego RST, pamiętając, by ograniczyć go wyłącznie do własnych adresów i nie stać się przy okazji reflektorem dla kogoś innego.
- Pozamykaj porty 80 i 443 na dostępnych z zewnątrz ONTkach/CPE abonentów – Twoja sieć nie będzie multiplikatorem ataku.
- Sprawdź, czy sam nie jesteś częścią problemu. Zweryfikuj, czy z Twojej sieci nie wychodzi ruch ze sfałszowanymi adresami źródłowymi – nawet jeśli dziś nikt nie atakuje Ciebie.
Nie czekaj, aż to Twoja sieć stanie się celem. Najlepszy moment na wdrożenie tych zmian był 26 lat temu, gdy powstał RFC 2827. Drugi najlepszy jest teraz.
Masz pytania, potrzebujesz wsparcia przy konfiguracji albo chcesz porozmawiać o ochronie swojej sieci? Odezwij się do nas – jako społeczność EPIX jesteśmy po to, żeby wspólnie utrudniać życie atakującym.
Czytaj także:


