Přetečení na zásobníku
Přetečení na zásobníku (anglicky stack buffer overflow) je v informatice technika napadení programu nebo operačního systému, která využívá přetečení na zásobníku volání ke spuštění libovolného strojového kódu, například přepsáním návratové adresy pro návrat z podprogramu.
Přetečení na zásobníku je jedním z nejznámějších způsobů získání neautorizovaného přístupu k počítači.[1][2]
Příklad útoku
Zdrojový kód
Kód, který je náchylný k útoku, typicky obsahuje část, kde se manipuluje s datovou strukturou, jejíž velikost je pevně stanovena. Problém nastane ve chvíli, kdy se při vkládání dat do proměnné nekontroluje a neošetřuje, zda se data do této proměnné vejdou.
void kopiruj (char *str) {
char buffer[8];
strcpy (buffer, str);
}
int main () {
char *str = "excessive";
kopiruj(str);
}
Vizualizace útoku v paměti
- SP – Stack Pointer – ukazatel na vrchol zásobníku
- RET – návratová adresa z funkce kopiruj do hlavního programu
8bajtový buffer | SP | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
hodnota | žádný obsah | RET | ||||||||
HEX | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 1E | E7 |
Pokud zapíšeme na zásobník řetězec delší než 8 bajtů, dojde k přetečení vyhrazeného bufferu (zde ve formě lokální proměnné, která je umístěna na zásobníku). Zapisovaný řetězec "excessive" je dle zvyklostí zakončen znakem \0
(tj. binárně nula). Po jeho zápisu do proměnné buffer bude situace v paměti vypadat tak, jak je znázorněno v následující tabulce:
8bajtový buffer | SP | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
hodnota | excessiv | e\0 | ||||||||
HEX | 65 | 78 | 63 | 65 | 73 | 73 | 69 | 76 | 65 | 00 |
Při zápisu došlo k přepsání vrcholu zásobníku hodnotou "e\0". Při pokusu o návrat do hlavního programu (instrukcí RET) dojde k odskoku na libovolné místo v paměti. Pokud vhodně zvolíme přetečenou hodnotu a přepíšeme i následující paměťový prostor (typicky vlastním strojovým kódem), dojde k jeho spuštění. Útok je nebezpečný zejména v případě, kdy data přepisující zásobník přicházejí z (nekontrolovatelného) vnějšku počítače (tzv. remote exploit).
Obrana proti útoku
Obrana proti přetečení zásobníku je možná několika způsoby:
Z pohledu programátora
- pokud to není nutné nepoužívat jazyky, které používají přímý přístup k paměti (typicky C, C++)
- důsledná kontrola psaného kódu
- používání tříd a funkcí, které manipulují s pamětí bezpečně
- použití automatizovaných nástrojů v součinnosti s kompilátorem
Využití automatických nástrojů
Většina automatických nástrojů, které se snaží tomuto způsobu zneužití zabránit, používají tzv. kanárky (pojmenováno podle kanárků, kteří se používali v dolech na odhalení nebezpečných plynů). Jedná se o specifická data, která se umístí do paměti za nadefinované proměnné. Ve chvíli, kdy dojde k přetečení zásobníku, je přepsána i hodnota kanárka a přetečení může být odhaleno. Kanárků se používá několik druhů - statický, náhodný nebo také XOR.
- Statický kanárek
- Statický kanárek je snadný na implementaci, ale neposkytuje příliš efektivní ochranu, neboť ve chvíli, kdy je hodnota kanárka vyzrazena, může útočník upravit vstupní data, tak aby nezměnili hodnotu kanárka a přetečení zůstane neodhaleno.
- Náhodný kanárek
- Náhodný kanárek je podobný a jeho účinnost je závislá na kvalitě generátoru náhodných čísel.
- XOR kanárek
- XOR kanárek používá hodnotu, která je výsledkem operace XOR nad náhodnou hodnotou kanárka a výsledkem funkce nad nadefinovanými proměnnými. Tím přidává další úroveň složitosti do případného útoku, protože je třeba zjistit jak náhodnou hodnotu, tak funkci, tak odpovídající vstupní hodnoty funkce (tedy obsah nadefinovaných proměnných).
Další možností je přeskupení pozice proměnných v paměti tak, aby struktury náchylné na přetečení byly na začátku paměťového prostoru. Změna způsobí, že přepsáním dalších proměnných dojde pravděpodobně k chybě v programu, takže přetečení bude odhaleno. Kromě toho se zvětší šance, že vstupní data nebudou dostatečně dlouhá a k přetečení dojde mimo účinný prostor.
Použití bezpečnějších ekvivalentů funkcí
Pro většinu C/C++ funkcí existuje ekvivalentní "n" funkce.[3] V případě funkce strcpy
též "l" funkce. "n" funkce nezapíší více, než stanovenou délku, "l" funkce navíc doplňují \0.
strcpy → strncpy → strlcpy strlen → strnlen strcmp → strncmp strcat → strncat strdup → strndup sprintf → snprintf wcscpy → wcsncpy wcslen → wcsnlen
Z pohledu uživatele
Uživatel se může pouze omezit následky takového útoku tím, že nebude spouštět nedůvěryhodné programy s právy privilegovaného uživatele, případně se mu vyhnout použitím aktualizovaných verzí programů. Stoprocentní obrana však neexistuje. I v současnosti přes široké povědomí o tomto typu útoku se objevují programy, které jsou na tento typ útoku náchylné. Chyby tohoto typu se objevují i v jádře operačního systému[4] a dalších kritických programech. Zde je nespornou výhodou použití opensource programů, neboť u nich díky podpoře komunity dochází k velmi rychlému vydání opravných balíčků.
Hardwarová ochrana
Dalším ze způsobů ochrany je NX bit (hardwarová ochrana paměti implementovaná v procesoru) který umožňuje zabránit spuštění kódu v datové části paměti, což je jeden ze způsobů, který buffer overflow využívá.
Reference
- ↑ LEVY, Elias. Smashing the stack for fun and profit. Phrack. 1996-11-08, s. 14. Dostupné v archivu pořízeném dne 2012-10-27. (anglicky) Archivovaná kopie. www.phrack.org [online]. [cit. 2012-10-18]. Dostupné v archivu pořízeném z originálu dne 2012-10-27.
- ↑ PINCUS, Jonathan; BAKER, Brandon. Beyond Stack Smashing: Recent Advances in Exploiting Buffer Overruns. IEEE Security & Privacy. July-August 2004, s. 20–27. Dostupné online. (anglicky)
- ↑ http://stackoverflow.com/questions/1253053/cs-bad-functions-vs-their-good-alternatives
- ↑ http://www.debian.org/security/2010/dsa-1998