Python a kybernetická bezpečnosť / 28. časť
Prv ako sa začneme programovo venovať zabezpečeniu binárnych súborov a nástrojom Pwntools, musíme uviesť niekoľko základných faktov, ktoré sa týkajú súborov a procesov. V krátkosti predstavíme spustiteľné binárne súbory (executables), ich predprípravu (preprocess), preklad (compiling), spájanie (linking) a zostavovanie (assembly)/spätné zostavovanie (disassembly). Okrem toho si povieme pár slov o tzv. shellcode, ďalej o využívaní počítačovej pamäte a v závere poukážeme na bezpečnostné prvky spustiteľných binárnych súborov.
Spustiteľné binárne súbory (ďalej len spustiteľné súbory)
Operačné systémy (OS) pracujú s dvoma základnými abstraktnými entitami:
1. súbory (files) – statická reprezentácia zdrojov (resources),
2. procesy (processes) – dynamická reprezentácia zdrojov.
Prechod od statickej entity k dynamickej sa nazýva nahrávanie (loading). Loader, ako interná súčasť OS, počas nahrávania alokuje potrebné zdroje, vytvára potrebné štruktúry procesov a spúšťa ich prvé inštrukcie. Loader požaduje, aby mali spustiteľné súbory zodpovedajúci formát, pričom v prípade Linuxu hovoríme o tzv. ELF (Executable and Linkable Format) a v prípade Windows o tzv. PE (Portable Executable) formáte.

Obr. 1 Základná štruktúra formátu ELF
Štruktúry spomínaných formátov spustiteľných súborov možno podrobne naštudovať z ich špecifikácií, resp. referenčnej dokumentácie. Pre nás je dôležitý fakt, že z jednotlivých štruktúr možno získať napr. adresu prvej inštrukcie (Entry Point), adresy jednotlivých funkčných blokov (v prípade ELF adresy segmentov a sekcií) a ďalšie metadáta.
Spustiteľné súbory vznikajú zo súborov so zdrojovým (source) kódom napísaným v niektorom z programovacích jazykov, ktoré sú zrozumiteľné pre ľudí. Deje sa tak pomocou predprípravy a prekladu (okrem prekladu poznáme aj proces interpretácie, ktorému sa však nebudeme venovať). Pri preklade vznikajú tzv. assembly súbory, ktorých kód je nízkoúrovňový a začína sa podobať na strojový kód. Assembly súbory sú následne zostavené na tzv. object súbory, ktoré už obsahujú samotný strojový (machine) binárny kód, zrozumiteľný pre konkrétny CPU. Viaceré object súbory sa ďalej spájajú (statické/dynamické linkovanie), čím dochádza k vytvoreniu finálnych spustiteľných súborov alebo knižníc.
Rozdiel medzi statickým a dynamickým linkovaním je ten, že pri statickom linkovaní sa všetok kód vzájomne prepojených object súborov spojí do jedného spustiteľného súboru, pričom sa vyplnia všetky adresy používaných symbolov. Pri dynamickom linkovaní sa používajú tzv. tabuľky GOT (Global Offset Table) a PLT (Procedure Linkage Table), pričom príslušný komponent OS alokuje potrebné zdroje až v okamihu ich prvého použitia, a to iba na nevyhnutne potrebný čas. GOT a PLT obsahujú adresy dynamicky linkovaných funkcií, ktoré už boli raz programom volané, čím sa urýchľuje jeho výkon.
Zlinkované súbory možno spätne transformovať na assembly súbory prostredníctvom disassemblera.
Shellcode (shell-storm.org)
Shell kódom sa nazýva assembly kód, ktorý je predpripravený na použitie na vykonanie špecifickej činnosti. Svoj názov získal po tom, ako mal byť jeho vykonaním sprístupnený shell, najlepšie s eskalovanými superpoužívateľskými právami. Známe shell kódy však nie sú určené iba na spustenie shellu, ale možno pomocou nich vykonať množstvo rozličných „drobných“ činností. Pri vykonávaní útokov na procesy bežiace na cieľových zariadeniach možno v prípade úspešného prelomenia ich zabezpečenia nahradiť bežiace procedúry shell kódom s úmyslom vykonať nami požadované akcie.
Procesy
Jadro OS (kernel) po naštartovaní konkrétneho procesu pridelí tomuto procesu samostatný virtuálny adresový (pamäťový) priestor. Procesy tak navzájom nekomunikujú priamo odovzdávaním údajov v rámci jedného pamäťového bloku, ale kernel má na to vytvorený mechanizmus interprocesovej komunikácie.
Kernel navyše každému procesu prideľuje tzv. hŕbu (heap) a zásobník (stack). V tomto procese „hrá“ hlavnú rolu alokátor pamäte (mmap), ktorý v prípade potreby navyšuje veľkosť hŕby. V prípade, že alokovaná pamäť už nie je potrebná, alokátor ju neuvoľňuje, ale ponechá ju danému procesu pre prípad opätovnej potreby. Ďalšia prideľovaná pamäť je zásobník, ktorý má manažovateľnú veľkosť a ktorý sa spoločne s hŕbou „delí“ o voľne dostupnú pamäť. Zásobník je dôležitý na vykonávanie funkcií, pričom jeho princíp práce sa jemne odlišuje v prípade 32 a 64-bitovej architektúry.
S prideľovaním pamäte súvisia nám dôverne známe chyby ako Segmentation Fault alebo Buffer Overflow, ktoré nastávajú v prípadoch, keď procesy neoprávnene vykonajú nejakú pamäťovú operáciu v im nepridelenej časti pamäte.

Obr. 2 Pamäťové bloky pridelené bežiacemu procesu
Spomínané fakty týkajúce sa formátov spustiteľných súborov a prideľovania pamäťového priestoru sú extrémne minimalistické. Táto téma môže byť námetom na samostatný seriál. Spomíname ich však preto, lebo sa ich týkajú skutočností, o ktorých budeme hovoriť ďalej.
Binary Security
Pretože je filozofia prideľovania pamäťového priestoru a exekúcie spustiteľných súborov všeobecne známa, počítačovým hackerom sa otvoril priestor na možné prieniky. To nevyhnutne viedlo k zavedeniu bezpečnostných prvkov súvisiacich s fungovaním zásobníka, medzi ktoré patrí:
1. NX (Non-eXecutable) bit/DEP (Data Execution Prevention) – zabraňuje spúšťaniu shellcode, ktorý útočník umiestni do zásobníka,
2. PIE (Position Independent Executable) – umiestni programové kódy (.text, .data) na náhodné pamäťové adresy,
3. ASLR (Address Space Layout Randomization) – umiestni programové segmenty vrátane hŕby, zásobníka a zdieľaných knižníc na náhodne vybrané pamäťové adresy,
4. Stack Canaries – umiestni špeciálny náhodne vygenerovaný údaj medzi pamäťový blok v rámci zásobníka a návratovú adresu (ret) funkcie, pred ukončením (návratom z funkcie) dôjde ku kontrole platnosti canary, v negatívnom prípade sa program preruší,
5. RELRO (Relocation Read-Only) – pri preklade označí konkrétne sekcie spustiteľných súborov (GOT/PLT tabuľky) ako read-only.
ROP (Return Oriented Programming)
Ide o metódu, pomocou ktorej dochádza k takým manipuláciám zásobníka a registrov (64-bit arch), pri ktorých sa zmenia návratové hodnoty a dochádza k spusteniu nami „podhodených“ funkcií. Využívajú sa pri tom zreťazené drobné kúsky assembly kódu, nazývané gadgets.
Pokračovanie nabudúce...
Zobrazit Galériu