default-pic

Bezpečnosť pri paralelných aplikáciách

Fakt, že niekto našiel dieru vo väčšine windowsových antimalware produktoch (a verím tomu, že tento prístup funguje aj na iných OS) je sám o sebe dosť zaujímavý. O dosť zaujímavejšie je zistiť, aký jednoduchý postup použili.

Aby sme sa dostali k popisu, trochu odbočím k problému s threadmi, ktorý (okrem mnohých iných) popísal prof. Edward A. Lee vo svojej publikácii The Problem With Threads. Autor sa zaoberá problémami paralelného programovania, rozmýšľania programátorov a hlavne tým, aké možnosti pre paralelné programovanie nám dávajú programovacie jazyky. Vo väčšine moderných programovacích jazykov je možné vytvoriť tzv. “vlákno”, ktoré sa vykonáva paralelne. Dokonca je to potrebné, aby sme vedeli vyťažiť súčasné viacjadrové procesory. Problém je v tom, že programovacie jazyky boli navrhnuté na sekvenčné programovanie, väčšina z nich nepočítala z tým, že medzi prečítaním a zapísaním jednej premennej môže dôjsť k jej zmene iným vláknom. Tento problém čiastočne riešia tzv. locky, kedy vieme povedať, že daná časť kódu sa môže vykonávať iba jedným vláknom a všetky ostatné musia počkať, kým jedno vlákno skončí s danou “chránenou” časťou kódu (syntaktická a čiastočne aj sémantická realizácia je v rôznych jazykoch odlišná, v jazyku Java sa používa kľúčové slovo synchronized). Toto znamená, že často vlákna nerobia nič, len čakajú na to, kedy skončí iný kód. Niekedy sa ani nemusia dočkať – takáto situácia sa nazýva deadlock (prísne vzaté, deadlock má trošku inú definíciu, ale táto pre naše potreby postačí). Nastáva (napríklad) vtedy, ak jedno vlákno čaká na to, aby druhé vlákno uvoľnilo prostriedky, ale druhé vlákno ich neuvoľní, kým nezíska prostriedky, ktoré drží prvé vlákno (slovo “napríklad” sa vzťahuje na to, že situácia môže byť zložitejšia – môže ísť o sériu viacerých procesov, ktoré sa dostanú do zablokovaného stavu, z ktorého nikdy neskončia). Tento problém je v informatike tak trochu fundamentálny, totiž zistiť, či sa program dostane do stavu deadlocku je vo všeobecnosti dokázateľne nemožné.

Samozrejme, riešenie je jednoduché – najmeme dobrých programátorov, ktorí rozmýšľajú a vedia, čo robia, najdeme ešte rozumnejších ľudí, ktorí sa vyznajú v problémoch paralelného programovania a necháme ich ten kód ohodnotiť. Toto presne spravil prof. Lee so svojim tímom ľudí v roku 2000. Okrem neho systém, ktorý mal byť ukážkou, ako sa robí správne paralelné programovanie, ohodnotili ďalší ľudia z univerzity, ktorí sa zaoberajú paralelným programovaním (medzi nimi aj ďalší traja profesori, nie len študenti). Implementovali automatizované testy so stopercentným pokrytím kódu na viacprocesorových počítačoch.

Kód sa zasekol v apríli 2004, o štyri roky neskôr. Ak nedokážu profesori, ktorí sa profesionálne celú svoju kariéru venujú programovaniu paralelných systémov nájsť deadlock v kóde, kto to potom dokáže? (Odpoveď nepoznáme, ale pravdepodobne bude zahŕňať vymyslenie novej paradigmy programovania, o čo sa snažia mnohé univerzity).

Teraz k bezpečnostnému problému. V skratke vysvetlím (a zjednoduším): Keď chce program napr. spustiť iný program, zavolá systémové volanie. Odovzdá mu adresu v pamäti, kde sa nachádza meno programu na spustenie. Antimalware program (či už antispyware, antivírus alebo podobný program) časť svojej ochrany robí tak, že tieto systémové volania odchytáva a filtruje. Postup je teda nasledovný:

  1. Program si myslí, že volá systémové volanie
  2. V skutočnosti zavolá rutinu antimalware programu, ktorá spraví svoje bezpečnostné aktivity (skenovanie, kontrola práv, ...).
  3. V prípade, že kontrola prejde v poriadku, zavolá sa pôvodné systémové volanie, inak sa vráti chyba.

Problém je, že pri systémovom volaní sa vždy odovzdáva (pri reťazcoch a zložitejších dátových štruktúrach, neplatí to napr. o číslach) adresa v pamäti pôvodného procesu. Útok funguje takto:

  1. Malware zavolá systémové volanie s adresou v pamäti, kde je cesta k neškodnému programu.
  2. Zároveň vytvorí druhý thread, ktorý cestu zmení za cestu k škodlivému programu.
  3. V niektorých prípadoch kontrola prejde (antimalware si prečíta ešte cestu k "čistému" programu), ale keď odovzdá adresu pôvodnému systémovému volaniu, nachádza sa tam už cesta k novému (napr. škodlivému) kódu. Toto je možné tak, že obe vlákna prebiehajú súčasne, čiže je to len otázka správneho časovania.

Vzhľadom na to, že malware má času dosť, môže tieto kroky skúšať až kým sa mu to raz nepodarí. Samozrejme, toto systémové volanie bol len príklad, takýmto istým spôsobom ide “oblbnúť” aj firewall, prípadne iné volania.

Spol. Difinex, ktorá problém odhalila riešenie ponúka len plateným zákazníkom. Príklad nášho volania však môže byť opravený jednoducho. Stačí, ak sa antimalware bude správať takto:

  1. Naalokuje nové miesto v kernelovej pamäti (kam pôvodný proces nemá právo písať)
  2. Skopíruje tam cestu
  3. Spraví svoju bezpečnostnú kontrolu
  4. Spustí pôvodné systémové volanie
  5. Po jeho ukončení (alebo kedykoľvek neskôr) uvoľní pamäť

Problém je, že toto riešenie pravdepodobne nezafunguje na všetky systémové volania (niektoré napríklad môžu meniť dátovú štruktúru priamo, prípadne by to bolo pomalé a neefektívne).

Ostáva len dúfať, že antimalware autori práve teraz sedia za počítačmi a pracujú na riešení tohto problému. Pre nás ostatných je to len ďalší dôkaz toho, že inštalácia antimalware produktu, akokoľvek dobrého je len veľmi malá časť počítačovej bezpečnosti, ktorá navyše častokrát zlyháva…

Podobné blogy