Proč je opravdu zapotřebí DNSSEC?

Amir Herzberg a Haya Shulmanová z izraelské Bar Ilan University na konferenci IETF 87 v Berlíně představili novou variantu otrávení DNS pomocí fragmentace IP paketů. Kompletní prezentaci lze najít v IETF 87 Proceedings.

Doporučuji si pro osvěžení tématu znovu přečíst o útoku na DNS, který před pěti lety objevil Dan Kaminsky. Kromě použití technologie DNSSEC, která je jedinou opravdu funkční ochranou proti podvrhávání DNS odpovědí, se jako jedna z obran začaly používat náhodné zdrojové porty, které přidaly dalších ~16 bitů entropie.

Už v té době jsme ve studii (kratší shrnutí) upozorňovali, že ani větší počet náhodných bitů nezaručuje ochranu před podvržením a otrávením DNS, a s dostatečně velkým datovým tokem (~100Mbps) je možné otrávit DNS za dobu lehce překračující jeden den (~25 hodin).

Izraelští výzkumníci nyní přišli s novými variacemi útoku na DNS, které ukazují, že opravdu potřebujeme kryptograficky silné DNS a potřebujeme jej pokud možno ihned.

Hlavička IPv4 paketu vypadá takto:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version|  IHL  |Type of Service|          <strong>Total Length</strong>         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         <strong>Identification</strong>        |Flags|      Fragment Offset    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Time to Live |    Protocol   |         Header Checksum       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Source Address                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    <strong>Destination Address</strong>                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options                    |    Padding    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Celá hlavička UDP datagramu vypadá takto:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version|  IHL  |Type of Service|          Total Length         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Identification        |Flags|      Fragment Offset    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Time to Live |    Protocol   |         Header Checksum       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Source Address                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    <strong>Destination Address</strong>                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options                    |    Padding    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Source Port          |       Destination Port        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|            Length             |           Checksum            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Důležité je vědět, že v případě, že spojení mezi dvěma směrovači má nižší MTU (Maximum Transmission Unit) dojde k fragmentaci paketu na několik částí, které jsou identifikovány stejným číslem v poli Identification (dále IP-ID). Fragmentovaný provoz může vypadat například takto:

14:56:02.608188 IP (tos 0x0, ttl 64, id 47557, offset 0, flags [+], proto ICMP (1), length 1500)
    217.31.204.249 > 12.22.58.30: ICMP echo request, id 22368, seq 1, length 1480
14:56:02.608193 IP (tos 0x0, ttl 64, id 47557, offset 1480, flags [none], proto ICMP (1), length 48)
    217.31.204.249 > 12.22.58.30: ip-proto-1
14:56:02.797078 IP (tos 0x0, ttl 60, id 61513, offset 0, flags [none], proto ICMP (1), length 1528)
    12.22.58.30 > 217.31.204.249: ICMP echo reply, id 22368, seq 1, length 1508

Jak lze vidět, tak odchozí ICMP zpráva typu echo request (tj. ping) byla rozdělena na dvě části s IP-ID = 47557 a rozdílnými offsety. Fragmentované části paketu pak budou v cíli spojeny do jednoho a aplikace, která přenesenou zprávu zpracovává, ji dostane v jednom bloku. A protože k defragmentaci paketů dochází až v cílové destinaci a směrovače fragmentované pakety nijak speciálně nesledují, tak je možné, že každá část fragmentovaného paketu dorazí k cíli například jinou cestou nebo v jiném pořadí, než byly fragmenty odeslány.

Toto skládání částí paketu mimo pořadí nahrává útočníkovi. Pokud ví, jaké je po cestě MTU, což nemusí být tak složité zjistit, tak může začít podvrhovat následné (tedy druhé a vyšší) části paketů. Takto podvrhnuté fragmenty můžou mít dvojí efekt – jednak je možné do druhé části paketu vložit vlastní obsah a jednak v případě rozdílné udané velikosti celého paketu je možné donutit operační systém, který je zodpovědný za defragmentaci paketu, aby (pro útočníka) nežádoucí pakety zahazoval (tj. taková trochu chytřejší varianta DDoS útoku).

Další (a poslední) část fragmentační skládačky spočívá v tom, že existuje ICMP zpráva typu fragmentation needed, kterou si počítače na cestě domlouvají maximální velikost paketu, kterou dokážou přenést. V případě IPv4 je minimální velikost MTU 68, v případě IPv6 je to 1280. Bohužel tuto zprávu lze celkem dobře podvrhnout a cílový server donutit snížit MTU na hodnotu, která je pro útočníka výhodná. Tato nová hodnota je v operačních systémech držena v dočasné paměti až několik minut.

Jaké to tedy má důsledky pro DNS? Na to se musíme podívat do hlavičky DNS zprávy:

                                1  1  1  1  1  1
  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                      ID                       |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    QDCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ANCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    NSCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ARCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

Již jsme si řekli, že ochranu proti spoofingu nám zajišťuje ID v hlavičce zprávy (16 bit) společně se zdrojovým portem v UDP zprávě (16 bit).

Když se ale podíváme zpátky pouze na IP vrstvu, tak zjistíte, že obě informace (DNS-ID i source port) jsou vždy uloženy pouze v prvním IP fragmentu, tudíž útočníkovi stačí podvrhnout druhou část paketu, kterou nahradí vlastním obsahem. Při podvrhávání potřebuje útočník uhádnout jenom správné IP-ID, aby se podvržený fragment spojil se začátkem platné odpovědi. Kromě toho, že hádání 16-bitového IP-ID je velmi jednoduché provést pouhou hrubou silou, tak celou situaci ještě zjednodušuje fakt, že hodnoty IP-ID se většinou negenerují úplně náhodně. Na některých operačních systémech existuje globální counter IP-ID, takže hodnotu aktuálního IP-ID systém vyzrazuje s každým odeslaným paketem (a útočník tedy přibližně ví, do jakého rozsahu se má trefovat). Pokud cíl útoku běží na Linuxu, tak je to pro útočníka naštěstí trochu složitější, protože pro každou cílovou adresu má Linuxové jádro zvláštní IP-ID counter, ale i toho však lze bohužel zneužít.

Poslední komplikace, kterou útočník musí vyřešit, je kontrolní součet v UDP hlavičce. Nicméně ani to není velký problém, protože jednak útočník ví, jak bude odpověď DNS serveru vypadat, protože se sám může zeptat, a v DNS paketu je vetšinou dost místa na to, aby kromě falešné odpovědi do DNS paketu ještě nacpal další data, kterými 16-bitový kontrolní součet nastaví na požadovanou hodnotu.

Poslední zefektivnění útoku probíhá opět již na IP vrstvě a závisí na implementaci IP stacku v jednotlivých operačních systémech, nicméně je možné říci, že ve většině případů je možné tuto optimalizaci dost efektivně využít. Již jsme si výše řekli, že fragmentované pakety mohou přijít mimo pořadí, a protože je UDP nespojovaný protokol a zároveň vrstva, která dělá defragmentaci v IP stacku nemá moc ponětí o vrstvách vyšších, je možné podvržené druhé fragmenty poslat dopředu na náš cíl útoku a ony se uloží do vyrovnávací paměti operačního systému. Teprve po tomto „nahrání“ druhých fragmentů útočník vyvolá Kaminsky-style dotaz, a odpověď, kterou cílová aplikace dostane, bude složena z přednahraného části a prvního fragmentu správné odpovědi.

Celý koncept útoku dále v Laboratořích CZ.NIC zkoumáme, a mimo jiné bychom rádi v rámci ověření efektivity takového útoku vyrobili funkční PoC (Proof of Concept) implementaci celého útoku. O tom, zda-li jsme uspěli, Vás budeme dále informovat.

Na závěr bych rád řekl jednu špatnou a jednu dobrou zprávu. Ta špatná zpráva je, že v současné době není proti tomuto útoku známa žádná jiná efektivní obrana než nasazení DNSSECu. Ta dobrá zpráva je, že pokud máte doménu .CZ, tak máte skoro 40% šanci, že Vás DNSSEC chrání. Jestli chcete vědět, jak s DNSSEC pracovat, přijďte do naší akademie. Kurz se jmenuje více než prozaicky – DNSSEC – zabezpečení DNS.

Ondřej Surý

Autor:

Komentáře (2)

  1. Ondřej Caletka říká:

    Díky, velmi zajímavé. Jen doufám, že se lidé před tímto útokem nebudou chránit zahazováním ICMP provozu. :)

    Jako obrana před tímto typem útoku by asi fungovalo nastavit na odchozím směru velikost UDP bufferu v EDNS0 zprávě na nízkou hodnotu a zároveň na firewallu zcela blokovat fragmentovaný provoz. To je sice prasárna, ale na druhou stranu, internet je plný míst, kde fragmentace jednoduše nefunguje.

  2. Ondřej Surý říká:

    Podobné řešení doporučují i autoři – prostě na koncovém (autoritativním) DNS serveru zakázat fragmentaci, a dělat fallback na TCP.

    Hlavní problém je, že aplikace (DNS server) do fragmentace vůbec nevidí, protože to odstíní síťový stack.

Zanechte komentář