Błąd przepełnienia bufora

Przepełnienie bufora

Atak wykorzystuje tablice, przy zapisie do których nie jest sprawdzany zakres. Pisząc poza ich zakresem można zamazać inne zmienne lub rekord aktywacji procedury. Aby zrozumieć jak dokładnie działa atak, trzeba się przyjrzeć organizacji pamięci podczas wywoływania procedur.

Organizacja stosu

Stos służy do przechowywania argumentów, zmiennych lokalnych oraz rekordu aktywacji procedury. Do zarządzania nim używa się zazwyczaj rejestrów: %esp, który pokazuje koniec stosu (aby łatwo dokładać kolejne elementy), %ebp, który pokazuje początek części stosu dla procedury.

W architekturze intela stos rośnie w dół (gdy odkładamy nań jakiś element wartość rejestru SP zmniejsza się). Adresy kolejnych komórek tablic rosną w przeciwną stronę.

Wywołanie procedury zazwyczaj polega na:

Atak

Wśród zmiennych lokalnych znajduje się również bufor (tablica) - główny bohater prezentacji. Przypomnijmy, że tablica rośnie w przeciwną stronę niż stos.

Sam atak polega na podaniu ciągu danych, na tyle długiego, aby nadpisał adres powrotu, oraz na ustaleniu wartości jaka powinna się w nim znaleźć.

Jako, że stosy procesów miały (dlaczego czas przeszły patrz: PaX oraz Vista) zwykle to samo przesunięcie względem początku strony, atakujący mógł podać we wprowadzonym buforze kawałek skompilowanego kodu, i podmienić adres powrotu na wskaźnik do niego. Przy tworzeniu kodu będzie pamiętał o kilku rzeczach:

Może też podmienić go na adres jakiejś zewnętrznej funkcji (np.: execve) i umieścić na stosie argumenty dla niej

Sterta

Nie tylko stos jest miejscem, gdzie może znajdować się bufor. Programy trzymają również swoje dane na stercie - dynamicznie alokowanym obszarze pamięci. Przepełniony bufor na stercie nie nadpisze co prawda adresu powrotu, ale może zmienić zawartość naszych zmiennych. Zwłaszcza ciekawe efekty mogą przynieść zmiany:

Użycie przepełnienia bufora na stercie jest trudniejsze niż gdy bufor znajduje się na stosie - ale nie nie możliwe.

Niebezpieczne konstrukcje

Najprostszym sposobem, na znalezienie miejsc podatnych na atak jest grepowanie kodu. Atakujący poszukują wywołań funkcji:

strcat(), strcpy(), sprintf(), vsprintf()

Nie sprawdzają one zakresów tablic do których piszą.

gets()

Czyta całą linię ze standardowego wejścia.

scanf(), fscanf()

Formatowanie %s oznacza wczytanie ciągu nie pustych znaków.

getc(), fgetc(), getchar()

Funkcje te czytają po jednym znaku. Niebezpieczne są w pętlach, które nie sprawdzają rozmiaru bufora, czytając wszystko do końca linii, napisu lub pliku.

Bibiografia