Hlavní navigace

Zabezpečte svůj DNS server

24. 7. 2012
Doba čtení: 8 minut

Sdílet

V poslední době se často hovoří o zneužívání DNS serverů ke kybernetickým útokům. Většina doporučení ohledně zabezpečení doporučuje pouze vypnutí DNS serveru. Co když ale jeho služby potřebujete? V článku si představíme praktickou realizaci zabezpečení DNS serveru pomocí linuxového netfiltru.

Zesilující DNS útok

Služba DNS je jedna z mála základních internetových služeb, které jsou provozovány nad transportním protokolem UDP. Protože UDP nenavazuje žádné spojení, je jím možné posílat data protistraně, aniž ta by o tom věděla, a mohla to nějak ovlivnit. Dokonce je velice snadné odeslat UDP paket se zfalšovanou adresou odesílatele.

Protože odpovědi DNS serveru jsou obvykle řádově větší než dotazy, dají se veřejné DNS servery využít jako spolehlivé zesilovače. Prostě jim pošlete dotaz s falešnou adresou odesílatele, mířící ve skutečnosti na oběť vašeho útoku. DNS server na něj odpoví a vaše ruce zůstanou čisté. Když se zeptáte několika serverů a každého zásobujete několika sty dotazy každou sekundu, dokážete na cílový server poslat desítky i stovky Mbit/s zbytečného provozu, který může kompletně zahltit linku k serveru.

Schéma zesilujícího DNS útoku.
Autor: Martin Haller

Schéma zesilujícího DNS útoku. Zdroj: Lupa.cz

DNSSEC bohužel nepomůže

Aby byl zesilovací faktor co největší, musíte vymyslet takový dotaz, který ze serveru vyloudí co největší odpověď. Jako ideální se jeví typ dotazu ANY, kterým se DNS serveru ptáme na všechno, co o daném jméně ví. A zeptáme se nejlépe na nějaké jméno, které je začátkem zóny (tzv. apex). Máme jistotu, že dostaneme SOA záznam, několik NS a MX záznamů a často i nějaké A, či AAAA záznamy. To ilustruje následující snímek Wiresharku. Na jednoduchý dotaz zabírající 78 bajtů přišla odpověď dlouhá 3,4 kilobajtů.

V tomto konkrétním případě (se kterým jsem se v praxi setkal) je každý paket zesílen přibližně 44×. Můžeme to připisovat chybě v nastavení domény, která obsahuje evidentně zbytečně mnoho TXT záznamů. Ale i perfektně nastavenou doménu je možné zneužít k zesílení s faktorem 5 až 15. Je-li doména chráněna DNSSECem, máme jistotu, že dosáhneme velkého zesílení použitím dotazu na DNSKEY, ke kterému server navíc přidá podpisy.

BCP38, obrana nejúčinnější

Tou hlavní ochranou před podobnými druhy útoků by mělo být filtrování zdrojových adres. Zjednodušeně řečeno, provozovatel každé koncové sítě by na hraničních směrovačích měl propouštět ven do internetu pouze takové zdrojové adresy, které jsou koncové síti přiděleny. Podrobněji se tomu věnuje doporučení IETF BCP 38. Problém je, že takové filtrování je na odpovědnosti každého provozovatele koncové sítě. Na úrovni tranzitní sítě, kde je směrování dynamické a klienti jsou připojeni v různých místech, se podobné filtrování realizuje velmi obtížně. Je tedy potřeba smířit se s tím, že vždy bude existovat nějaké místo na internetu, odkud bude možné posílat falšované pakety, které nikdo nezahodí.

Vypnutí nepoužívaných DNS serverů

Další možností, jak zmírnit následky zesilujícího útoku, je omezit počet DNS serverů. Na internetu je provozována spousta otevřených rekurzivních serverů, ochotných komukoli přeložit jakékoli jméno. U velké části z nich přitom rekurzivní funkce není používána a zůstala zapnutá jen proto, že jde o výchozí konfiguraci DNS serveru. Právě na tyto případy dlouhodobě upozorňuje jak CZ.NIC, tak i bezpečnostní tým CSIRT.cz, jako třeba v nedávné zprávičce.

Odkazované texty bohužel vyvolávají dojem, že otevřené rekurzivní nameservery jsou jediným způsobem, jak službu DNS zneužít, a jejich eliminací bude internet záchráněn. Ve skutečnosti se otevřené rekurzivní DNS servery používají k útokům proto, že jsou k dispozici. Pokud k dispozici nebudou, útočníci se velice rychle přeorientují na autoritativní servery, které z principu funkce musí být schopny odpovědět komukoli. Tím nechci bagatelizovat snahu zmíněných institucí o omezení počtu otevřených serverů, což je jistě prospěšná činnost, jen bych byl opatrný ohledně očekávaných výsledků takové akce.

Omezení četnosti dotazů pomocí hashlimit

Pokud veřejný DNS server provozovat musíte (a je jedno, jestli autoritativní nebo rekurzivní), je vhodné omezit počet dotazů, které dokáže obsloužit. Pro útoky je totiž typické, že stejná adresa (ve skutečnosti jde o adresu oběti) posílá serveru stovky dotazů za sekundu. Omezení by se mělo vztahovat na danou IP adresu, aby překročením povoleného limitu nebyli omezeni ostatní uživatelé serveru. Přesně tohle umí modul linuxového netfiltru zvaný hashlimit. Stačí umístit do iptables následující pravidla:

# iptables -N dns_udp
# iptables -A INPUT -p udp --dport 53 -j dns_udp
# iptables -A dns_udp -m hashlimit --hashlimit-above 25/sec \
           --hashlimit-burst 100 --hashlimit-mode srcip \
           --hashlimit-name DoS-DNS -j DROP
# iptables -A dns_udp -j ACCEPT

Prvním příkazem jsme si pro větší přehlednost založili nový řetězec dns_udp a druhým příkazem do něj poslali veškerý příchozí provoz na port udp/53. V nově vzniklém řetězci nejprve voláme hashlimit, a pokud ten paket nezahodí, v dalším kroku jej přijmeme.

Nastavení hashlimitu si můžeme vysvětlit na klasickém příkladu s děravým vědrem. Pro každou možnou zdrojovou IP adresu má hashlimit připraveno vědro s kapacitou 100 paketů (označeno jako burst), ve kterém je díra taková, že z něj každou sekundu 25 paketů vyteče (hodnota above). Jak pakety přicházejí, hashlimit vyhledá podle zdrojové adresy příslušné vědro a vhodí do něj paket. Pokud se mu to povede, nic se neděje a paket pokračuje k dalšímu pravidlu, kterým je přijat. Pokud je vědro plné a paket není kam uložit, je zahozen. Stav věder je možné kontrolovat ve speciálním souboru  /proc/net/ipt_hashlimit/DoS-DNS.

9 1.1.1.1:0->0.0.0.0:0 128 128000 1280
9 2.2.2.2:0->0.0.0.0:0 118528 128000 1280
9 3.3.3.3:0->0.0.0.0:0 128000 128000 1280

Význam sloupců je zleva stáří vědra (9 je nejmladší), zdrojová a cílová IP adresa a port, aktuální stav vědra v jakýchsi fiktivních jednotkách, maximální kapacita vědra a velikost jednoho paketu. Oproti předchozímu výkladu je zde logika opačná, vědro je v základním stavu plné a s přicházejícími pakety ubývá. Jakmile je jeho stav nižší, než hodnota velikosti jednoho paketu, jsou pakety z dané adresy zahazovány.

Hashlimit je poměrně univerzální nástroj, kromě použitého módu, kdy má každá IP adresa své vědro, dokáže také pracovat se sdíleným vědrem pro určitý společný prefix. To se může hodit třeba u IPv6, kde by mohl útočník generovat pro každý dotaz jinou adresu z 64bitového prefixu. To docílíme přidáním volby --hashlimit-srcmask 64, samozřejmě při použití  ip6tables.

Ještě větší restrikce pro dotazy typu ANY

Jak už jsem napsal, dotazy typu ANY jsou dnes nejčastějším způsobem zneužívání DNS serverů. Zároveň se tento typ dotazů běžně nepoužívá, tedy snad kromě ladění DNS serverů správci. Proto také některé DNS servery (například Knot DNS) nabízejí možnost na dotazy typu ANY neodpovídat a stejně se chová i známá služba Google Public DNS. Úplné zakázání těchto dotazů ale ztěžuje ladění, nehledě na to, že jak bylo ukázáno, útočníci mají už teď mnoho jiných možností, jak vylákat z DNS serverů dostatečné zesílení. Bylo by tedy dobré, kdybychom mohli dotazy typu ANY nějakým způsobem klasifikovat ve firewallu a aplikovat pro ně odlišná, přísnější pravidla.

Problém je, že tvůrci protokolu DNS moc nepočítali s tím, že by někdo chtěl třídit pakety na základě typu dotazu, takže typ dotazu umístili nikoli na pevný ofset, ale na plovoucí umístění až za poptávané jméno, jak je vidět na obrázku. Klasifikování pomocí obecného modulu u32 je možné pouze pro konkrétní jména, nikoli pro všechny typy dotazů.

Naštěstí už podobný problém řešil (byť za účelem jakési antispamové ochrany) Bartłomiej Korupczyński, a tak existuje modul do netfiltru zvaný xt_dns, který dokáže klasifikovat UDP DNS dotazy podle druhu. Autor zvolil poměrně nestandardní, ale funkční řešení, kdy polohu pole s typem dotazu neodměřuje od začátku, ale od konce paketu, kde je ofset konstantní. Tím se vyhnul potřebě procházet jméno po jménu, a filtr je tedy rychlý. Jedinou nevýhodou filtru je, že nedokáže klasifikovat DNS dotazy používající rozšíření EDNS0. Takové dotazy na konci obsahují ještě pole OPT, specifikující rozšířené volby:

Právě dotazy s EDNS0  jsou mezi útočníky hojně rozšířeny, protože povolují serveru posílat odpověď větší než 512 bajtů. Z toho důvodu jsem modul xt_dns forknul a přidal do něj podporu i pro dotazy s EDNS0. Původně jsem používal stejný nestandardní způsob nalezení pole s typem dotazu odečítáním od konce paketu, pak jsem jej ale přepsal na verzi s klasickým procházením od začátku. Ta je robustnější a kromě EDNS0 si poradí i s pakety, které mají na konci nadbytečné bajty (například z důvodu zarovnání).

Po nainstalování modulu zbývá doplnit firewall o další limit pro dotazy typu ANY. Abychom mohli na počítadlech netfiltru sledovat funkčnost filtru, vytvoříme pro tyto dotazy další samostatný řetězec:

# iptables -N dns_udp
# iptables -N dns_any
# iptables -A INPUT -p udp --dport 53 -j dns_udp
# iptables -A dns_udp -m hashlimit --hashlimit-above 25/sec \
           --hashlimit-burst 100 --hashlimit-mode srcip \
           --hashlimit-name DoS-DNS -j DROP
# iptables -A dns_udp -m dns --dns-query ANY -j dns_any
# iptables -A dns_udp -j ACCEPT
# iptables -A dns_any -m hashlimit --hashlimit-above 1/sec \
           --hashlimit-burst 10 --hashlimit-mode srcip \
           --hashlimit-name DNS-ANY -j DROP
# iptables -A dns_any -j ACCEPT

Sledovat účinnost filtru můžeme například následujícím příkazem. Ten každou sekundu zobrazí stav počítadel v obou řetězcích a dále vypíše stav hashlimitu pro dotazy typu  ANY.

root_podpora

watch -n1 'iptables -L dns_udp -xv && iptables -L dns_any -xv &&
           cat /proc/net/ipt_hashlimit/DNS-ANY'

Závěr

Popsaná implementace filtrování dokáže nejen zmírnit následky DoS útoků, ale také ochránit uživatele před sebou samými. Při náhodném sledování provozu na DNS serveru ještě bez filtrování jsem pomocí nástroje iftop odhalil zacyklený počítač, generující více než 400 totožných dotazů za sekundu. Server k němu několik dní ochotně posílal odpovědi rychlostí 10 Mbit/s. Přitom běžný provoz daného serveru se pohybuje kolem rychlosti 1 Mbit/s pro stovky klientů dohromady. Po upozornění majitele serveru provoz ustal, je tedy zřejmé, že nešlo o zfalšovanou adresu odesílatele.

Uvedený postup je plně použitelný i pro IPv6 provoz, stačí vyměnit iptables za ip6tables. Ačkoli při současném provozu IPv6 k naplňování limitů nedochází, štěstí přeje připraveným.

Byl pro vás článek přínosný?

Autor článku

Ondřej Caletka vystudoval obor Telekomunikační technika na ČVUT a dnes pracuje ve vzdělávacím oddělení RIPE NCC, mezinárodní asociaci koordinující internetové sítě.