Koncept rozšířených hlaviček měl být jedním z klíčových trháků protokolu IPv6. Problematice jsme se již před několika léty věnovali v seriálu na Lupa.cz. Vzhledem k tomu, že téma rozšířených hlaviček je poměrně obsáhlé a komplikované, tak si dnes uděláme krátkou rekapitulaci jak rozšířené hlavičky fungují a na jaké problémy můžeme narazit při jejich zpracování. V dalším dílu si pak ukážeme, jak tento nový koncept může zneužít útočník a jaké jsou případně možností obrany.
Na rozdíl od protokolu IPv4 je základní hlavička každého IPv6 paketu tvořená minimalistickou strukturou, která obsahuje pouze naprosto nezbytné informace pro doručení paketu na cílové místo. Díky tomu je délka IPv6 hlavičky pouze dvakrát větší než základní hlavička IPv4, a to i přesto, že se zdrojové a cílové IPv6 adresy zvětšily čtyřikrát. Koncept základní IPv6 hlavičky poměrně chytře předpokládá, že takto tvořená hlavička je postačující pro naprostou většinu přenášených paketů. Aby však bylo možné protokol IPv6 rozšiřovat o další zajímavé vlastnosti, je možné základní hlavičku doplnit o další hlavičky, pro které IPv6 používá termín "rozšířené hlavičky" - Extension Headers. Technicky vzato lze rozšířené hlavičky přirovnat k datové struktuře v podobě jednocestného lineárního seznamu, kde první prvek tvoří základní IPv6 hlavička, rozšířené hlavičky jsou položkami seznamu a celý seznam je zakončen hlavičkou protokolu nesoucího data (TCP, UDP, ICMP, …), případně ukončující hlavičkou (No Next Header). Následující obrázek nám pak ilustruje několik variant uspořádání hlaviček.
U první varianty následuje za základní IPv6 hlavičkou přímo hlavička protokolu TCP. U další je mezi základní IPv6 hlavičku a protokol TCP vložena hlavička Hop-by-Hop, které by měly věnovat pozornost všechny uzly po cestě. U poslední varianty je vložena navíc ještě hlavička Destination Options, kterou by se mělo zabývat pouze koncové zařízení.Vlastní rozšířené hlavičky můžeme rozdělit do dvou základních skupin. První z nich nesou informace určené směrovačům, které doručují pakety. Druhý typ hlaviček je určen pouze pro cílové uzly. Příkladem z první skupiny může být hlavička Routing Header, která se používá pro rozšíření IPv6 o mobilitu. Do druhé skupiny pak můžeme zařadit podpůrné hlavičky pro IPsec (ESP, AH), hlavičku nesoucí informaci o fragmentaci aj. Rozšířené hlavičky by měly být v paketu řazeny dle určitých pravidel. Základní pravidla jsou specifikována v RFC 2460, které je ale aktualizováno několika dalšími RFC, jak si popíšeme dále v článku. Obecně ale platí, že hlavičky zpracovávané uzly po cestě by měly být zařazeny na začátku seznamu a hlavičky týkající se koncového uzlu by měly být umístěné na konci. Na první pohled to tedy vypadá, že konceptu rozšířených hlaviček nelze nic vytknout. Pro většinu paketů se použije úsporná základní IPv6 hlavička následována hlavičkou vlastního protokolu transportní vrstvy. Současně je ale otevřená možnost budoucího rozšiřování protokolu IPv6 o nové vlastnosti. Rozšířené hlavičky ovšem přináší i některé komplikace a nové možnosti vedení útoků. Zkusme se tedy podívat, jaké záludnosti nás mohou v souvislosti s rozšířenými hlavičkami potkat.
Každý pes jiná ves
Na začátku si dovolíme menší odbočku, abychom problematiku rozšířených hlaviček lépe pochopili. Rozšířená hlavička je obecně datová struktura, která přenáší další informace, které se nevešly do základní hlavičky IPv6. U struktur obdobného rázu jakými jsou rozšířené hlavičky, bývá často u síťových protokolů zvykem používat formátování dat, které se označuje pojmem TLV (Type - Length - Value). Formát TLV má jasně dané rozložení, kde typicky v prvním bajtu je definován typ informace, ve druhém bajtu její délka a zbytek je již informace samotná. Výhoda této datové struktury je, že pokud zařízení danému typu nerozumí, může ho bez problémů přeskočit, protože ví jeho velikost. Položka o velikosti datové části (přenášené informaci) je totiž vždy na přesně definované pozici. Tímto je umožněno poměrně snadné rozšiřování protokolů a současně se zachovává kompatibilita se staršími verzemi a implementacemi. Protokoly, které tímto způsobem informace přenáší (např. EIGRP, ISIS, CDP) lze pak vcelku jednoduše rozšířit o nové informace a jejich stávající implementace s tím nemají problém. Nyní se vraťme zpět k rozšířeným hlavičkám a podívejme se detailněji na jejich vlastní formát.
V počáteční specifikaci protokolu IPv6 bylo definováno několik rozšířených hlaviček sloužící pro fragmentaci, šifrování aj. Vlastní formát rozšířených hlaviček ale nebyl nijak unifikován a byl zcela v rukou tvůrce příslušné rozšiřující hlavičky. Názorně si můžeme rozdílné formáty rozšířených hlaviček ukázat na příkladu hlaviček Fragment Header, Hop-by-Hop Header a IPsec ESP, které lze vidět na následujícím obrázku.
Jak vidíte na obrázcích, formát hlaviček je rozdílný, protože první návrhy protokolu IPv6 ani v náznaku nepředpokládaly využití TLV. Některé hlavičky, jakými je například hlavička Hop-by-Hop, používají formát podobný TLV. Podobný proto, že typ (políčko Next Header) nenese informaci o vlastním typu, ale o typu hlavičky následující. Následuje pak délka vlastní Hop-by-Hop hlavičky a následně již samotná informace. Tento rozpor, kdy typ nepopisuje danou hlavičku, ale délka ano, nám pak způsobí další komplikace, jak si popíšeme dále v textu. U hlavičky fragmentace je tomu pro změnu úplně jinak. Hlavička má fixní velikost a tudíž neobsahuje políčko, které by její velikost definovalo. Hlavička IPsec ESP to má také kompletně jinak. IPsec ESP slouží k šifrování přenášených dat (políčko Payload Data), kde si můžete představit třeba protokol TCP. Identifikace, která data vlastně jsou takto šifrovaná, je až na konci celého paketu. Políčko Next Header u IPsec ESP tedy slouží jako zpětný ukazatel na začátek políčka Payload Data. Ostatní definované hlavičky se víceméně snaží dodržovat formát podobný TLV jako používá hlavička Hop-by-Hop, i když výpočet délky hlavičky (Hdr Ext Len) je také občas pro různé hlavičky rozdílný.
Z tohoto neustáleného formátu rozšířených hlaviček plyne poměrně nepříjemný závěr, kdy každé zařízení, které má umět zpracovat rozšířené hlavičky, musí vždy rozumět i syntaxi všech existujících rozšířených hlaviček, a to i přesto, že příslušná hlavička nenese pro dané zařízení žádné relevantní informace. Pracovní skupina IETF 6man si tento problém uvědomila a v roce 2012 vydala RFC 6564, kde zavádí jednotnou strukturu. Ta se podobá TLV formátu použitém pro Hop-by-Hop hlavičku. Tato nová struktura však celkem pochopitelně závazně platí pouze pro nově vytvářené hlavičky a dříve definované hlavičky již navždy zůstanou v původním formátu. Bohužel ani tato jednotná struktura neřeší celkový problém, jak si ukážeme dále.
Cesta ke sjednocení
Původní specifikace protokolu IPv6 z roku 1998 v zásadě nijak neřešila zpracování rozšířených hlaviček mezilehlými zařízeními (firewall, IDS, aj.). V té době zkrátka panovala představa, že síťová zařízení jako například směrovače budou pouze “bezmyšlenkovitě” doručovat data na základě cílové IP adresy a vyšší protokolové vrstvy je nemají co zajímat. Nepředpokládalo se, že by provoz po cestě měl být analyzován, filtrován či by do něj mělo být nějak zasahováno. Původní autoři IPv6 totiž veškerá mezilehlá zařízení (middlebox) považují za čisté zlo, které by se nemělo v síti vůbec vyskytovat. Z toho důvodu původní RFC 2640 doporučuje, aby mezilehlá zařízení všechny rozšířené hlavičky zkrátka ignorovala a nechala vše v režii koncového uzlu. Výjimku tvoří pouze hlavička Hop-by-Hop, která je určena pro všechna zařízení po cestě. Požadavky se však od roku 1998 značně změnily a prakticky ladění čtenáři nám jistě dají za pravdu, že v dnešní době, kdy DoS či DDoS útoky jsou takřka na denním pořádku, je možnost filtrace, například podle portů nebo příznaků v TCP, naprosto nezbytnou provozní nutností. Tento trend ostatně odrážejí i novější RFC, kde kupříkladu filtrace pro domácí sítě je aktuálními standardy přímo doporučována v RFC 4864. Vyvažování zátěže, Firewally, IDS/IPS systémy a QoS mohou být dalšími příklady služeb, kterým informace v základní IPv6 hlavičce nestačí a musí pracovat i s informacemi z transportního či dokonce aplikačního protokolu.
Tento posun v nahlížení na mezilehlá zařízení reflektují i novější standardy a snaží se najít z tohoto problému únikovou cestu. Jednou z počátečních komplikací pro správnou implementaci rozšířených hlaviček bylo vůbec zjistit, jaké rozšířené hlavičky jsou vlastně definované. Identifikátory a popis rozšířených hlaviček nebyly totiž od začátku přidělovány organizací IANA, takže nebyl nikde k dispozici celkový přehled. Jednotlivé specifikace rozšířených hlaviček tak byly "rozstrkány" v jednotlivých RFC různých pracovních skupin. Tento problém byl vyřešen v roce 2013 schválením RFC 7045. Dané RFC přesně definuje všechny rozšířené hlavičky, které musí umět zařízení zpracovat a současně předává přidělování identifikátorů organizaci IANA. Seznam všech současných a budoucích rozšířených hlaviček je tedy na jednom standardním místě. RFC 7045 rovněž diskutuje problematiku filtrování a připouští, že zpracovávání či zahazování rozšířených hlaviček může být problém. Přináší proto následující doporučení. Všechny současně definované rozšířené hlavičky musí zařízení podporovat a jejich zahození/přeposlání je pak záležitost nastavené síťové politiky. Všechny nově definované rozšířené hlavičky musí mít jednotnou strukturu dle RFC 6564. Pokud zařízení takovou nově definovanou hlavičku ještě nezná, RFC 7045 ji doporučuje “přeskočit” a pokračovat dál ve zpracování řetězce hlaviček. Jinými slovy postupovat tak, aby se nekomplikovalo zavádění nových rozšíření. Nicméně i přes tuto snahu je vyřešená pouze první část problému.
Protokol nebo rozšířená hlavička?
Druhou částí problému je totiž fakt, že identifikátor rozšířené hlavičky i čísla protokolů spolu sdílí stejné políčko (Next Header). Pokud zařízení identifikátor použitý v políčku Next Header nezná, nedokáže pak rozlišit, zda se jedná o nově definovanou rozšířenou hlavičku nebo o nově definovaný protokol. Důsledkem je, že nové rozšiřující hlavičky a protokoly nelze vlastně inkrementálně zavést. Celé si to můžeme ilustrovat na následujícím příkladu.
Představte si situaci, kdy budete chtít definovat nový protokol, například nové geniální TCP, říkejme mu třeba XTCP. Firewall nicméně nemůže tušit, že se jedná o zcela nový protokol. Pokud bude brát doporučení z RFC 7045, pokusí se data interpretovat jako neznámou rozšířenou hlavičkou a pokusí se ji “přeskočit”. Na místě, kde se má nacházet identifikace navazující hlavičky a její délka jsou ale již data související s XTCP, která jsou tím pádem mylně interpretována jako informace popisující další rozšířenou hlavičku. V této fázi už lze těžko předvídat další chování systému. V ideálním případě se nezhroutí a rozhodnutí, jak naloží s paketem, provede podle své implicitní bezpečnostní politiky (propustit/zahodit), nicméně dané rozhodnutí je značně nedeterministické. V koncovém důsledku tedy nejsme schopni rozumně projít celým zřetězeným seznamem hlaviček, dostat se až na koncový transportní protokol a bezpečně ho detekovat.
Pracovní skupina IETF 6man si je i tohoto problému vědoma a nabízí částečné řešení v již zmíněném RFC 6564. Už jsme si popsali, že toto RFC definuje jednotný formát pro nové rozšířené hlavičky. Navíc také ale říká, že nová rozšířená hlavička nesmí být definovaná, pokud se pro nesení požadovaných informací dá použít již nějaká hlavička stávající. Vzhledem k tomu, že do hlavičky Destination Options lze zakódovat vcelku cokoliv, je přímo daným RFC doporučováno, aby se raději pro přenos případných dalších informací použila tato hlavička. Výsledkem tedy víceméně je snaha zachovat současné rozšířené hlavičky a žádné nové nedefinovat.
Efektivní zpracování hlaviček
Nepříjemným problémem rozšířených hlaviček je také jejich efektivní zpracování. Pokud hlavičky mají být zpracovány v software (např. v jádře operačního systému), je zpracování poměrně jednoduché - vše je řešitelné jednoduchým cyklem, který se zastaví v místě, kde je nalezena koncová hlavička (např. TCP). Cyklické procházení datových struktur je ovšem velká komplikace v případě, že paket má být zpracován ve specializovaném a ideálně paralelizovaném hardware, jakým je ASIC nebo FPGA čip.
Zastánci striktně oddělených síťových vrstev (tj. zařízení na jedné vrstvě nezasahuje do vrstvy vyšší nebo nižší) jistě namítnou, že toto není žádný problém, protože zpracování rozšířených hlaviček je ryze záležitostí buď koncových systémů (kde se zpracovávají v SW) anebo specializovaných zařízení jako jsou firewall, IDS systém či monitorovací sonda, které mají dostatek zdrojů i pro složitější zpracování paketu. Praxe nicméně ukazuje, že tohoto striktního oddělení nejde vždy dosáhnout a někdy je třeba, aby zařízení zasahovala i do protokolových vrstev, které jim “nepřísluší”. Typickým příkladem je efektivní přeposílání multicast provozu (IGMP/MLD snooping), kdy přepínač, pracující primárně na linkové vrstvě, potřebuje získat data z vrstev vyšších. Dalším příkladem mohou být mechanismy First Hop Security, které jsme si popsali v minulém díle. Pro efektivní fungování by měly být implementované na přístupových portech L2 přepínače, nicméně pak L2 přepínač musí zasahovat i do provozu vrstev vyšších a tedy být schopen zpracovat celý řetězec rozšířených hlaviček až k hlavičce vlastního protokolu.
V příštím díle si tento problém ilustrujeme na příkladu implementace mechanismu RA-Guard, který slouží jako ochranný prvek proti falešným směrovačům. Abychom si však objasnili podstatu problému, je vhodné se nejdříve krátce seznámit, jak je vlastně uvnitř takový přepínač strukturován.
Obrázek převzat z Cisco Catalayst 6500 Architecture
Ve velice zjednodušené podobě si můžeme přepínač představit, jak je zobrazeno na obrázku. Provoz na jednotlivých portech zpracovává specializovaný čip ASIC. Ten s paketem provádí na vysokých rychlostech řadu stěžejních úkolů: vyhledává, na jaký port jej poslat; aplikuje filtrovací pravidla; QoS apod. Samotný ASIC čip ovšem dokáže provádět pouze omezenou množinu základních operací. V případě, že ASIC nedokáže rozhodnout sám, nebo je třeba podrobnější analýza paketu, předává zpracování procesoru, který složitější problém vyřeší za něj. Procesor však primárně neslouží k vyhledávání cesty, přeposílání paketů nebo filtraci. Procesor obsluhuje hlavně protokoly nutné pro správný chod sítě (směrovací protokoly, Spanning Tree Protocol) a vlastní správu (management) zařízení. Pro klasické přepínání a směrování je pro dnešní rychlosti totiž relativně pomalý. Bez této dělby práce mezi CPU a hardware bychom nedokázali zpracovávat data dostatečně rychle se zachováním možnosti detailního zpracování části provozu v CPU. Pro představu dodejme, že při zpracování provozu pomocí čipu ASIC, můžeme počítat s propustnosti v řádech 10, 100, či více Gb/s, zatímco u zpracování dat v CPU stěží přesáhneme několik Gb/s, u běžných zařízení spíše stovky Mb/s.
Pro správné fungování bezpečnostních mechanismů, filtrací apod. je ovšem důležité, aby ASIC dokázal rozpoznat IPv6 paket a zpracovat ho do té míry, že je schopen identifikovat protokol přenášený v rámci IPv6 paketu (např. ICMPv6) a nemusel veškerý IPv6 provoz přeposílat do CPU. Nicméně právě tato detekce je problém. ASIC čip a paměti TCAM, které slouží pro zpracování paketu, mají většinou omezenou velikost. Záleží na architektuře přepínače, ale typicky jsou schopny přepínače zpracovat v hardware prvních 64 - 128 bajtů daného paketu. To reálně stačí pro většinu provozu, jelikož u IPv4 máme pouze hlavičku, která má 20 bajtů (bez IP Options o kterých si povíme ještě dále) a hned za ní následuje protokol vyšší vrstvy. U IPv6 tomu tak ale není. Regulérní IPv6 paket má jednak dvojnásobnou délku hlavičky a navíc může obsahovat vcelku libovolné množství rozšířených hlaviček. I s několika běžnými hlavičkami lze překročit velikost hlavičky, kterou jsou dnešní přepínače schopny zpracovat v hardware. Přepínač pak má ve výsledku tři možnosti, jak s daným paketem naložit:
- zahodit, čímž ale znemožňuje zavádění případných budoucích rozšíření,
- propustit, tím je ovšem možné obejít případnou bezpečnostní politiku,
- předat CPU, kde může dojít k přetížení CPU a tím pádem degradaci výkonu a ovlivnění ostatních protokolů nutných pro chod sítě.
Žádné řešení tedy není ideální.
Dosud jsme také předpokládali, že čipy TCAM a ASIC disponují určitou mírou flexibility, která umožní definovat chování pro nové typy hlaviček, protokolů atd. Je však třeba upozornit, že řada přepínačů na trhu je vybavená jednoduššími čipy, které nemohou být takto přeprogramovány. Pokud se rozhodneme takovéto zařízení koupit, pak musíme počítat s tím, že nikdy nebude umět zpracovat v hardware některé funkce související s IPv6. Bohužel informace o tom, zda příslušné zařízení má plnohodnotnou podporu v hardware, je vesměs mezi výrobci obtížně dohledatelná.
A jak je to v IPv4?
Někteří si možná vzpomenou, že obdobná dynamická struktura je rovněž k dispozici v protokolu IPv4. Základní hlavičku IPv4 je možno rozšířit o položku označovanou jako IP Options, která, stejně jako rozšířené hlavičky v IPv6, má dynamickou velikost. Oproti rozšířeným hlavičkám v IPv6 však je možné položku IP Options "přeskočit" v jednom kroku a zcela jednoznačně identifikovat protokol vyšší vrstvy (TCP, UDP, ICMP, ...). Velikost položky IP Options je totiž možné určit přímo z velikosti hlavičky IPv4 a stejně tak jako identifikaci protokolu vyšší vrstvy (políčko Protocol). Firewall tak může bez problémů IP Options ignorovat. V principu však i toto rozšíření vykazuje mnohé nepříjemné vlastnosti, které můžeme najít u rozšířených hlaviček IPv6, tj. dynamická struktura s proměnlivou délkou, jejíž zpracování zpravidla nerealizuje specializovaný hardware, ale procesor. Z tohoto důvodu jsou IPv4 pakety obsahující IP Options většinou správců považovány za nebezpečné a na směrovačích rovnou zahazovány. Z dnešního pohledu můžeme říci, že toto rozšíření nikdy nebylo v minulosti nějak výrazně používáno a na některých novějších L3 přepínačích není ani možné doručování IPv4 paketů s IP Options povolit. Další forma rozšířených hlaviček, kterou v IPv4 můžeme potkat, jsou hlavičky ESP a AH protokolu IPsec, který byl ostatně do IPv4 převzat z IPv6. Zde je situace trochu podobná nicméně ani zde nedochází k onomu nepříjemnému řetězení hlaviček.
Závěr
V dnešním dílu seriálu jsme si popsali základní koncept a některé principiální problémy rozšířených hlaviček. Do budoucna nelze vyloučit, že rozšířené hlavičky v IPv6 postihne stejný osud jako IP Options v IPv4 - tj. nebudou se prakticky využívat a na směrovačích se pakety s rozšířenými hlavičkami budou rovnou zahazovat. Na půdě IETF, ale zatím převažuje snaha udržet rozšířené hlavičky v co nejotevřenější a tedy i nejflexibilnější podobě i do budoucna. V dalším díle seriálu se podrobně podíváme, jaké je vlastně reálné nasazení rozšířených hlaviček v dnešních IPv6 sítích, jak může celý koncept rozšířených hlaviček zneužít útočník a současně se také pokusíme najít cestu, jak se těmto útokům dá zabránit.