Buffer overflow (Linux)

zraniteľný kód

Ak zadáme príliš dlhý reťazec, tak nastane chyba - Segmentation fault.

Pozn.: presmerovanie chybového výstupu (stderr => stdout) je len kvôli Jupyter notebooku

Veľa znakov si môžeme aj naskriptovať, napr. v Python-e

Nájdenie adresy skrytej funkcie a jej spustenie cez pretečenie buffera

Buffer prepíšeme hodnotami, aby sme pri chybe vedeli zistiť pozíciu, ktorá prepíše návratovú hodnotu (Stack Pointer).

Vygenerujeme si 200 znakovú postupnosť pomocou Metasploit-u.

Dáme na vstup nášho programu:

Na zistenie adresy si program spustíme v ladiacom nástroji gdb:

príkaz názov popis
r run spustenie
x ? examine zobrazenie obsahu
q quit ukončenie
c continue pokračovanie (step over)
s step pokračovanie do vnútra funkcie(step into)
b ? breakpoint nastavenie prerušenia
info address ? zobrazí adresu

Pozn.: GDB je interaktívny nástroj, takže príkazy namiesto vstupu v Jupyter notebook-u zadávame pomocou presmerovani

Nájdenie pozície (offset-u):

Nájdenie adresy funkcie secret:

Spustenie funkcie secret prepísaním návratovej adresy (Little Endian, teda od najnižšieho bajtu):

Pozn.: Na výpis v Pythone (verzie 3) je použitý os.write, keďže print používa UTF-8 (nie jednobajtové znaky).

Spustenie shell-u

Samozrejme cieľom nie je spustiť funkciu, ktorá v programe už je, ale nejakú vlastnú, napríklad shell.

C++

https://ics.upjs.sk/~rkb/bpd1/shell.c

Assembler - spúštateľný súbor

https://ics.upjs.sk/~rkb/bpd1/shell.asm
https://ics.upjs.sk/~rkb/bpd1/shell64.asm

32bitová verzia

Assembler - strojový kód

Tento kód má len 32 bajtov, takže ho môžeme vložiť do zadaného textu do zásobníka.

Zistenie adresy premennej

Kompilovali sme s podporou ladenia, takže stačí pozrieť adresu premennej buf.

Vytvoríme teda vstup - kód na spustenie, vyplnenie (napr. znakmi A) a návratová adresa = adresa premennej buf (na predchádzajúcich dvov výstupoch vidno že sa mení aj v závislosti od vstupu.

V ladiacom nástroji sa nám podarilo spustiť shell (po úprave adresy), ale z príkazového riadku to nefunguje. V skutočnosti ešte dochádza k posunom podľa vaddr a zarovnania align. Takže ako vstup sa na začiatok dáva niekoľko inštrukcií NOP (nič nerobiacich) a skáče sa o niečo menej, teda na vyššiu adresu v pamäti. Viac napr. v [https://jvns.ca/blog/2018/01/09/resolving-symbol-addresses/]

Vytvoríme nový vstup

Spustenie exploitu

Namiesto nášho kódu môžeme spustiť ľubovoľný exploit, napr. otvorenie vzdialeného pripojenia sa terminálu-shellu. Ako kód použijeme exploit z Meta Sploit Framework-u

Address Space Layout Randomization

Tri rôzne úrovne, náhodne zásobník alebo aj halda

Data Execution Prevention

gcc -z execstack - nastaví stack ako spustiteľný (ináč sa kód uložení v danom segmente nedá spustiť)

gcc -fno-stack-protector - zapne kontrolu prepísania zásobníka, deteguje zmenu a ukončí program namiesto spustenia kódu na prepísanej adrese (canaries)