Za tajemstvím vzniku bezpečnostních mezer

Setkáváme se s nimi každý den. Bezpečnostní chyby, záplaty a potenciální útoky jsou tématem, které živí odborný...


Setkáváme se s nimi každý den. Bezpečnostní chyby, záplaty a potenciální útoky
jsou tématem, které živí odborný tisk a vytváří již po několik let pracovní
realitu nejednoho správce IT systému. Hovoříme o nebezpečnosti takových chyb, o
nutnosti je omezovat, o jejich zneužitelnosti či problematice jejich
zveřejňování. V čem však spočívá původ bezpečnostních chyb a jak prakticky
fungují? Existuje k nim obecná koncepce přístupu a lze se jich vůbec zbavit? To
jsou otázky, které nejsou pokládány příliš často, neboť odpovědi na ně se
hledají velmi špatně.
Už před mnoha lety si programátoři složitých aplikací a softwarových systémů
uvědomili, že nemá valný smysl je vytvářet monolitickým způsobem.
Naprogramování monstrózního brontosaura, dokonalého co do funkce, avšak stejně
tak nepřehledného a vnitřně jednotvárného, bylo jednak příliš obtížné a jednak
příliš nebezpečné.
Hledání jakékoliv chyby uvnitř bloku jednolitého kódu čítajícího tisíce či
miliony řádků v uživatelsky přítulném Basicu či Pascalu, ne-li dokonce v mnohem
méně přehledných variantách jazyka C, je obrazně řečeno sebevraždou. A tak se
složité aplikace začaly drobit do menších celků, které mezi sebou komunikují
pomocí stanovených rozhraní a komunikačních protokolů někdy veřejných a
standardizovaných, jindy proprietárních a uzavřených.
To vše umožňuje vytvářet pomocí rozsáhlého týmu programátorů a softwarových
inženýrů i velmi složité aplikace, kde má každý přidělenou svou část práce,
aniž by se musel zbytečně zaobírat těmi částmi, na kterých nepracuje.
Jednotlivé moduly aplikace, mezi něž je rozdrobena její funkčnost, spolu
komunikují a využívají společných funkcí uložených v knihovnách. Výsledkem je
moderní a funkční aplikace například moderní operační systém.
Bohužel s využitím dříve popsaných technik dochází ve velké míře u velmi
složitých systémů k vytváření živné půdy pro nezjevné nedostatky a nedodělky.
Nejen ty, ale také neočekávané chování korektně vytvořených komponent, jejich
vzájemná interakce a spolupráce s okolím, vedou často ke generování toho, co
obecně nazýváme bezpečnostními chybami. Tyto chyby, navzdory přesvědčení
některých odborníků, nelze nikdy zcela eliminovat. Již jen identifikovat, kdy
přesně bezpečnostní chyba vzniká, je problém, na který se podíváme jako na
první.

Co a kdy
Bezpečnostní mezera může mít, jak jsme už nastínili, několik podob. První z
nich je skutečná chyba. Určitá část kódu uvnitř modulu aplikace nebo systému se
za normálních okolností chová korektně (jinak by neprošla testováním). Pokud
však dojde k abnormalitě jakéhokoliv druhu nebo k vzácně se vyskytující
situaci, stane se zdrojem problému. Nastává neočekávané a autory aplikace
neošetřené chování standardní části.
To následně vede buď k havárii jedné podskupiny či celé aplikace nebo k
umožnění provádění i takových operací, které by neměly být za daných okolností
dostupné.
Jinou variantou je kolize. Dochází k ní tehdy, nemohou-li se vzájemně
"domluvit" různé části jednoho systému nebo i systémy mezi sebou. Ačkoliv se
všechny zúčastněné části chovají zcela korektně, výsledkem jejich souhry není
správná spolupráce, ale vyvolání chyby, jež opět vede k nelegitimní funkci nebo
ke zhroucení.
Další formou bezpečnostní chyby je opomenutý kód. Vývojové verze aplikací
obsahují značné množství ladicího kódu. Ten je v nich přítomen, ale v konečném
produktu je buď zcela odbourán, nebo umrtven a odpojen. Pokud dojde k opomenutí
a v ostré verzi aplikace se nachází část ladícího kódu, může takový stav vést k
možnosti přístupu do aplikace či systému nezdokumentovaným, a tedy potenciálně
nebezpečným způsobem.
S vývojem souvisí ještě jedna část. Funkce, které mají za normálních okolností
jasnou strukturu argumentů, bývají někdy pro účely testování napsány tak, aby
akceptovaly i syntakticky špatná zadání. Eventuálně bývají vyvinuty tak, aby se
při předání syntakticky správného, avšak velmi zřídka se vyskytujícího
argumentu, chovaly jinak než standardně. Toho se využívá při testování chování
aplikace v extrémních situacích. Například tehdy, je-li třeba krokovat či
sledovat místo, které by šlo pomocí standardních prostředků ověřit jen stěží.
V reálném nasazení je krajně nepravděpodobné, že by funkce dostala právě ten
argument či parametr, který její nestandardní chování spouští. Nicméně pokud k
tomu dojde, může následovat neočekávaná reakce celé aplikace či systému.
Posledním velmi podstatným nedodělkem vedoucím k vytváření bezpečnostních mezer
je chyba v dimenzování. Mnoho funkcí, u kterých se předpokládá, že budou
zásobovány požadavky na činnost rychleji, než je stačí vyřizovat, nebo u
kterých je nutná plynulost provozu obsahu, obsahují vyrovnávací zásobníky či
fronty.
Jejich velikost je obvykle dynamická (přizpůsobuje se aktuálnímu stavu
naplnění) nicméně i tak má své limity. Za určitých okolností může dojít k tomu,
že se takový zásobník zcela vyprázdní či naopak přeplní, aniž by příslušná
řídicí instance byla na tuto situaci schopna adekvátně reagovat.
Pak nastává "zmatení" aplikace, která je v lepším případě (neumí-li takový stav
automaticky opravit) kriticky ukončena, v případě horším funguje dál ovšem ve
stavu ztráty kontroly nad sebou samotnou. Do stejné skupiny patří také další
nedostatky, jako například dělení nulou v prostředí s vypnutým automatickým
ošetřením vzniklé výjimky, předání příliš dlouhého nebo nekorektního argumentu
a podobně.
V důsledku toho pak vzniká situace, kdy je možné, při dodržení určitého postupu
a se znalostí umístění výše uvedených nedostatků, v aplikaci vyvolat uměle stav
jejího nekorektního chování. Cílem může být ukončení aplikace, její poškození
anebo také zneužití. S její pomocí totiž lze omezit kontrolu nad daty
přivlastnit si je, zkopírovat, změnit či vymazat. Rovněž je možné narušit
spojení systému s okolím a v krajním případě na něm spustit neautorizovaný kód,
který pracuje proti zájmům uživatelů systému.

Jak vzniká díra
Velmi spekulativním, přesto podstatným tématem je nejenom to, co to
bezpečnostní mezera je, ale také kdy vlastně vzniká. V současné době existují
dvě hlavní koncepce pohledu na vznik bezpečnostních nedostatků.
1.Bezpečnostní mezera je chybou autorů aplikace. Vzniká při procesu její tvorby
a není zachycena během testování a odlaďování, takže se dostane spolu s finální
verzí k uživatelům.
2.V podmínkách velmi složitých systémů se nelze chybám, nebo nezamýšleným
důsledkům, nikdy vyhnout. Chyba nevzniká při tvorbě (ta pouze dává předpoklady
pro její vznik), ale až v okamžiku, kdy je objevena a popsána.
V případě, že by platila první z nich, pak je nejspíše pravdou i to, že mnoho
tvůrců a dodavatelů softwaru přináší na trh či vypouští mezi uživatele již
dopředu vadné a zneužitelné výrobky, protože nedostatečně odstranili jejich
nedostatky a potenciálně slabá místa.
V opačném případě nejsou "těmi zlými" výrobci, ale bezpečnostní experti, kteří
se chyby snaží odhalovat. Nebudeme zde žádnou z těchto koncepcí hodnotit
přirovnáními k lamentaci nad zlovůlí gigantů či chováním mrtvého brouka.
Podstatné je to, že existují a že pravdu je nutné hledat spíše mezi nimi než v
extrémních pozicích obou dvou.

Útok a oprava
Máme tedy zdokumentovanou bezpečnostní chybu a popis, jak ji využít pro
napadení systému (viz exploit ve slovníčku). Toho lze využít dvěma způsoby.
Prvním z nich je pochopitelně útok. Využití známého nedostatku k napadení
systému, k jeho zneužití, vykradení, změně, znepřístupnění či jiné kompromitaci
obsažených dat. Anebo prostě jen k vyřazení daného systému z provozu.
Druhou možností je vytvoření opravy, nahrazení dotčené komponenty jejím
bezpečným a chybu nevyvolávajícím ekvivalentem. Otázkou pochopitelně je, k čemu
dojde dříve.
Obecně platí, že opravit chybu ve složitém systému, jakým je například operační
systém Windows libovolné verze, je mnohem obtížnější, než ji využít. Problém
spočívá právě ve vzájemné provázanosti komponent, respektive jejich
funkcionality. Sebemenší změna jedné části se může projevit nejen v těch
částech, které komponentu využívají, ale i v těch, které s ní mají teoreticky
společného jen velmi málo, nebo snad dokonce vůbec nic.
Oprava jedné chyby tak může vést k nestabilitě či v krajním případě k vytvoření
jiného nedostatku stejně tak nezamýšleného jako byl ten původní. Problematická
je rovněž aplikace již vytvořené opravy. Některé programy či systémy jsou totiž
vytvořeny na konkrétní verze různých komponent, knihoven, částí operačního
systému a jsou s nimi testovány. Nahrazení některých z nich může snadno vést ke
ztrátě či narušení kompatibility, k poškození funkce programu, k jeho
nepředvídatelnému chování či dokonce k aktivaci druhotných bezpečnostních mezer
a nedodělků v něm samotném.
Měnit při nalezení každé nové chyby celý systém nebo celé jeho funkční jádro by
pravděpodobně nebylo v silách žádného výrobce softwaru ani žádné komunity. I
když právě ty jsou obvykle v ohledu bezpečnosti mnohdy aktivnější a vytvářejí,
byť je to trochu paradoxní, bezpečnější kód. Proto nahrazení a oprava každé
chyby, především v masově rozšířeném softwaru, představuje ohromný problém,
který vyžaduje další, složité a také nákladné testování. Jedná se o investici
do závodu s potenciálními útočníky. Závodu, ve kterém nemusí jít o nic, ale
také o ohromné intelektuální a koneckonců i fyzické majetky.

Nezdokumentované problémy
Připusťme nyní na chvíli, že platí první z koncepcí vzniku bezpečnostní chyby
tedy ta, že chyba je dílem autorů aplikace. Pokud není objevena, nachází se v
latentním stavu. Riziko jejího zneužití je sice kvantitativně menší, avšak
kvalitativně mnohem více závažné. Útok na to, co útočník zná, ale o čem obránce
nemá ani potuchy, je totiž útokem, proti kterému přinejmenším v raných fázích
není obrany.
Chyby, které jsou odkryty a zveřejněny formou exploitů, vedou k jejich
urychlenému opravování. Avšak ty, které se dlouhou dobu schovávají "pod
povrchem", mohou vést naopak k mnohem masivnějšímu zneužití. Nedávný červ
Blaster/LoveSan/MSBlast nezpůsobil gigantické škody prakticky jen proto, že
využíval známé a zdokumentované chyby v implementaci RPC do Windows třídy NT.
Kdyby tato chyba nebyla známa a neexistovala vůči ní obrana a kdyby sám červ
neobsahoval programátorskou chybu, zřejmě by se mohl šířit nezpozorován mnohem
delší dobu. Byl by objeven až teprve při provedení útoku na servery Microsoftu
nebo náhodně analýzou logu některého z velkých síťových prvků metodou data
miningu při úplně jiné příležitosti.
To, co zachránilo internet (a Microsoft zvláště), před zdrcujícím DDoS útokem a
následnými výpadky všech možných služeb, byla mimo jiné i skutečnost, že chyba
byla již ošetřena a opravu stačilo začít intenzivně distribuovat.
Situace, která ohrozila síťový svět globálně, se denně týká malých, ale
důležitějších sítí. Útoky na IT infrastrukturu soukromých společností a
institucí nemusejí být vedeny ani zdaleka pomocí využití známých a potenciálně
ošetřených mezer, ale mohou být spojeny s vyhledáváním nových, neznámých a
nepopsaných.
I když jejich riziko je mnohem menší, fakticky jsou nebezpečnější. Jedinou
obranou, z této optiky vidění, je tak hledání chyb a zveřejňování exploitů. Je
ovšem nutno dodat, že se tomu některé softwarové společnosti velmi intenzivně
brání.

Zajímavé adresy
www.root.cz server zabývající se otevřeným softwarem a rovněž jeho bezpečností
neworder.box.sk slavný slovenský server o bezpečnosti
www.hysteria.sk hacky, hackerství a využívání bezpečnostních mezer

Lze vytvořit bezchybné prostředí?
Pravděpodobně ne. Aplikace jsou příliš složité a operační systémy rovněž.
Připravovaný OS Longhorn společnosti Microsoft bude možná po Windows 2000
nejdůkladněji testovaným systémem, avšak je takřka jisté, že i on bude
obsahovat značné množství slabých míst.
Totéž platí i pro aplikace, pro servery a zvláště tam, kde je programový kód
vystaven značnému provozu na instrukční i na datové úrovni. Jednoduché řešení
zde prakticky neexistuje, ačkoliv se již objevilo několik pokusů. Jednalo se
buď o naprosté otevření či naopak proprietarizaci softwarového díla s cílem
zamezit napadení.
Oba tyto extrémy prozatím nevedly ke kýženému výsledku, odborná veřejnost se
nicméně domnívá, že první z možností představuje uličku o něco méně slepou, než
je ta druhá. Software, zejména v podmínkách, kdy je stavěn tak, aby komunikoval
v globálním měřítku, bude ještě hodně dlouho slabým místem informační
infrastruktury a zcela stoprocentně se na něj nebude možné spolehnout nikdy.
Existuje bezpečnostní certifikace, existují autority, existují dokonce modely
odhadu a hledání chyb, avšak ani ony nejsou zcela dokonalé. To však není projev
tvůrčí impotence či krátkozrakosti vývojářů, v celkovém pohledu se spíše jedná
o logický důsledek směru, kterým posledních zhruba deset let kráčí celé odvětví
informačních technologií.

Jak vzniká chyba
Opomenutím v kódu programu nebo komponenty.
Zapomenutím části kódu pro ladění a testování.
Nedostatečným prověřením interoperability různých komponent a protokolů.
Ignorováním možného využití techniky, která je určena například pro
zjednodušení činnosti aplikace.
Ignorováním možnosti nestandardního chování dočasného datového skladiště.
Neošetřením práce s čísly a ukazateli.
Nelogičností v přidělování práv pro zpracování různých instrukcí nebo komponent
systému atd.

Slovníček
OS - operační systém
Exploit - zveřejněný popis bezpečnostní chyby a jejího možného zneužití.
DoS, DDoS - (Denial of Service, Distributed Denial of Service) útok na server
zahlcením požadavky po síti.
Nezdokumentovaná funkce taková, - která je sice obsažena v komponentě systému/
aplikace, ale kterou výrobce z rozličných důvodů neuvádí v oficiálním popisu.
Je proprietární, slouží pouze pro vnitřní potřebu a často může být zneužita.
Ladící kód - Programový kód sloužící k testování aplikací. Před jejich
uvolněním pro skutečné používání bývá odbourán, nebo alespoň deaktivován.
Archaický kód - u velmi složitých systémů, jako je třeba operační systém, se
stává, že jsou vyvíjeny roky nebo desítky let v mnoha verzích. Protože obsahují
miliony řádků kódu, je velice obtížné je napsat "od začátku", a tak si každá
nová verze nese části kódu verzí předchozích. Tyto části se nacházejí v různých
vrstvách operačního systému. Některé z nich již neplní svou funkci, jiné pak
odlišnou než původně měly. Obtížně se v nich orientuje a jsou také zdrojem chyb.

Chybu lze zneužít:
Neautorizovanou prací člověka nebo softwaru se systémem.
Omezením činnosti nebo odpojením systému.
Neautorizovaným okopírováním nebo změnou dat.
Neautorizovaným smazáním dat.
Kompromitací bezpečnostních prvků.

Typické bezpečnostní mezery
Přetečení zásobníku (buffer overrun) nebo jeho podtečení (underrun).
Zneužití neveřejné instrukce.
Neošetřené předání nekorektního parametru.
Neošetřené předání korektního, ale vzácně se vyskytujícího parametru, který
vede k jinému než standardnímu chování.
Výpadek interoperability mezi protokoly nebo komponentami.
Špatná implementace standardního protokolu nebo jeho implementace mimo
standardizovaný rámec.
Neošetřené řízení práv operace s komponentou systému z nadřízené nebo podřízené
vrstvy.









Komentáře
K tomuto článku není připojena žádná diskuze, nebo byla zakázána.