012026_Q7B7 Run Advertisement 012026_Q7B7 Run Advertisement 012026_Q7B7 Run Advertisement

Python a kybernetická bezpečnosť / 29. časť

0

V tejto časti seriálu pretavíme teoretické poznatky získané z predošlých článkov do praxe. Pripravíme jednoduchú aplikáciu a skript, pomocou ktorých budeme demonštrovať jednu z možných zraniteľností binárnych súborov. Súčasne s predstavením kódu a funkcionality aplikácie vrátane exploit skriptu v Pythone si doplníme informácie týkajúce sa zabezpečenia binárnych súborov a možností jeho prelomenia.

0126 Q7B7Energy Advertisement

Spustenie tajnej funkcie

V predchádzajúcej časti seriálu sme uviedli, že kernel OS prideľuje každému spustenému procesu hŕbu a zásobník, ktorý je dôležitý na fungovanie funkcií. Do zásobníka, resp. registrov (64-bit arch) sa umiestňujú argumenty a premenné spúšťaných funkcií vrátane údajov (návratové adresy), ktoré sú potrebné na návrat z týchto funkcií po vykonaní ich kódu.

Predstavme si situáciu, keď sa v zásobníku vyhradí pamäťový priestor určený na uloženie údajov, za ktorým nasleduje adresa, na ktorú má byť program presmerovaný po vykonaní kódu funkcie. Keby sme vyhradený pamäťový priestor vedeli zaplniť údajmi a popri tom by sme vedeli zmeniť uloženú návratovú adresu, dokázali by sme program presmerovať na nami požadovanú (podhodenú) adresu a vykonať tak kód, ktorý sa na nej nachádza. Presne toto robí náš skript exploit.py.


Obr. 1 Programový kód vzorovej aplikácie app.cpp a skriptu exploit.py

Na praktickú demonštráciu spomínanej situácie sme pripravili jednoduchý kód v jazyku C, ktorý spúšťa funkciu problemovaf(), v rámci ktorej je používateľ vyzvaný na zadanie textu, ktorý sa následne vypíše na obrazovku. Problém tkvie v „nebezpečnosti“ funkcie scanf(), ktorá nekontroluje, aký dlhý text používateľ zadá. Na uloženie jednotlivých znakov sme vyčlenili iba 20 miest – premenná mchar[20]. Len čo používateľ zadá viac ako 20 znakov, funkcia scanf() nadbytočné znaky zapíše do pamäťového miesta za miesto vyčlenené premennej mchar. Veľmi ľahko tak dôjde k zápisu údajov na miesto, ktoré nemá bežiaci proces k dispozícii, čo vyvolá „notoricky“ známu chybu Segmentation Fault (SIGSEGV).

My však nemáme v úmysle vyvolať kolaps aplikácie. Naším cieľom je spustiť funkciu tajnaf(), o ktorej vieme, že je definovaná v rámci programového kódu aplikácie. Túto informáciu, ako aj adresu spomínanej funkcie dokážeme získať pomocou funkcií balíka pwntools. Potom nám stačí správne vyplniť pamäťové miesto v zásobníku a prepísať adresu návratovej funkcie adresou funkcie tajnaf().

Pwntools (https://pypi.org/project/pwntools)

Ide o CTF framework (pozri 27. časť seriálu), resp. knižnicu nástrojov, ktoré sú určené na vykonávanie prienikov (exploit) do aplikácií. Nástroje pwntools komunikujú s procesmi, soketmi či sériovými portmi prostredníctvom tzv. tunelov (tubes), pričom to robia programovo alebo interaktívne. Nás najviac zaujíma schopnosť komunikácie a manipulácie so spustiteľnými súbormi ELF. V rámci skriptu exploit.py načítavame obsah slovníka elf.symbols (alias elf.sym) na získanie zoznamu všetkých symbolov použitých v aplikácii app.cpp vrátane adresy funkcie tajnaf()elf.sym[‘_Z6tajnafv’]. Následne využívame funkciu recvuntil() na získanie dát z tunela, až pokiaľ nie je načítaný reťazec „Zadaj text: “. Ďalej do tunela pomocou funkcie send() zašleme reťazec písmen ‘A’ doplnený o adresu funkcie tajnaf(). Pri správne nastavenom počte písmen ‘A’ umiestnime adresu funkcie tajnaf() presne na to miesto, kde bola predtým zapísaná adresa funkcie main() = návratová adresa. Výsledkom je to, že namiesto vrátenia výkonu funkcii main(), z ktorej bola volaná funkcia problemovaf(), bude vykonaná funkcia tajnaf(). Počet znakov ‘A’, ktoré musíme zapísať do zásobníka, sme určili postupným hľadaním správneho čísla. Vieme, že toto číslo musí byť väčšie ako 20 a musíme ho postupne zväčšovať, pokiaľ sa nám nepodarí nájsť správne miesto na umiestnenie podhodenej adresy funkcie tajnaf().

    
Obr. 2 Výstup spusteného skriptu exploit.py vrátane textu, ktorý je vypísaný po spustení funkcie tajnaf()

Binary Security

Uvedený triviálny spôsob, ako spustiť ľubovoľnú funkciu v rámci spustiteľného súboru, má však jeden háčik. Tým je už spomínané zabezpečenie binárnych súborov (pozri 28. časť seriálu). Všimnime si, že na preklad programového kódu aplikácie app.cpp sme použili výraz g++ -fno-stack-protector -no-pie app.cpp. Zabezpečíme tak vytvorenie spustiteľného súboru, po ktorého spustení nebude vykonávaná kontrola zásobníka. Spustenému procesu bude navyše pridelený vždy rovnaký adresný priestor. V prípade, že by sme použili štandardný výraz g++ app.cpp, kernel nám nedovolí upravovať obsah zásobníka, pričom zareaguje chybovým hlásením „*** stack smashing detected ***: terminated“ (obr. 3).


Obr. 3 Chybové hlásenie v prípade aktivovanej ochrany zásobníka

Ochranné mechanizmy spustiteľných súborov sú teda nesmierne dôležité, a preto ich predstavíme detailnejšie.

NX (Non-eXecutable) bit / DEP (Data Execution Prevention)

Označí niektoré bloky bežiaceho procesu (zásobník) ako neexekutívne. To značí, že tu uložené údaje, aj keby išlo o programový kód, nemožno spustiť. Ak útočník uloží do zásobníka nejaký shellcode, ten nebude možné vykonať. Táto ochrana sa dá v niektorých prípadoch obísť prostredníctvom ROP, a to volaním systémových procedúr, ktoré zabezpečia opätovnú aktiváciu Executable Bit pre zásobník.

PIE (Position Independent Executable)

Pre spustený proces bude vyhradené vždy iné, náhodne umiestnené pamäťové miesto. To znamená, že po každom spustení sa zmenia adresy použitých symbolov (funkcií), gadgetov a zásobníka. Problémom je však skutočnosť, že sa zmení iba štartovacia adresa procesu, ostatné adresy symbolov v rámci procesu sú zväčša ofsetom oproti štartovacej adrese. Útočníkovi teda stačí nájsť štartovaciu adresu procesu a následne vie vypočítať všetky ostatné adresy.

ASLR (Address Space Layout Randomization)

Randomizácia umiestnenia programu, zdieľaných knižníc, zásobníka a hŕby. Tento mechanizmus je iba čiastočne efektívny. Útočník nie je nútený zmeniť programovú logiku svojho exploitu. Jediné, čo musí ručne alebo automatizovane zmeniť, sú adresy jednotlivých blokov procesu. Tie sa síce menia, ale v tejto zmene možno nájsť istú pravidelnosť.

Stack Canaries

Kontrola platnosti náhodne vygenerovaných údajov, tzv. kanárikov, ktoré sa umiestnia na určené miesta v rámci zásobníka. Kanáriky začínajú nulovým bajtom, ktorý zabezpečuje, že keby chcel útočník načítať obsah zásobníka, kanáriky nebudú súčasťou načítaných reťazcov. Aj tu však existujú isté spôsoby obídenia tohto ochranného mechanizmu. Patria medzi ne napr. načítanie obsahu zásobníka, jeho modifikácia, vykonanie požadovanej činnosti a následná obnova pôvodného obsahu zásobníka vrátane kanárikov zo zálohy.

Pri použití nástrojov pwntools je automaticky vypisovaná informácia (checksec) o použitých bezpečnostných mechanizmoch zvoleného binárneho súboru. V bežných prípadoch (ako default) sú aktivované všetky dostupné mechanizmy súborov, ktoré majú útočníkom maximálne sťažiť možnosti ich kompromitácie.

Poznámka: Všetky zdrojové kódy možno stiahnuť zo stránky softengine.sk.

Zobrazit Galériu

Marek Sopko

Všetky autorove články

Pridať komentár

Mohlo by vás zaujímať

Mohlo by vás zaujímať