[WikiDyd] [TitleIndex] [WordIndex

Cel zajęć

Celem zajęć jest zapoznanie się z błędami popełnianymi przez programistów, które powodują obniżenie bezpieczeństwa systemu.

Wprowadzenie

Błąd przepełnienia bufora to klasyczny błąd popełniany przez programistów C, który przekłada się na drastyczne obniżenie bezpieczeństwa programu. Przyczyną błędu jest brak ochrony i kontroli nad pamięcią przydzieloną programowi. Dzięki temu, jeśli złośliwemu użytkownikowi uda się przepełnić pamięć przeznaczoną na jakąś zmienną, to zyskuje możliwość zmiany sąsiednich komórek pamięci.

Najprostszym atakiem wykorzystującym idee przepełnienia bufora jest atak na sąsiednią zmienną. Taka sytuacja może mieć bardzo poważne konsekwencje. Zamieszczony poniżej, źle napisany program jest podatny na tego typu błąd. Po podaniu hasła "tajne" użytkownik zostanie zalogowany, ale możliwe jest zalogowanie nawet bez znajomości hasła. Atakujący może ręcznie ustawić zmienną 'zalogowany' na 't'.

// login - bardzo zle napisany program
int main(int argc, char *argv[]){
  char zalogowany;
  char haslo[8];
  zalogowany = 'n';
  strcpy( haslo, argv[1] );
  if( strcmp( haslo, "tajne" ) == 0 ){
    zalogowany = 't';
  }
  if( zalogowany == 't' ){
    printf("Poprawne haslo, witamy :)\n");
  } else {
    printf("Bledne haslo, uciekaj :(\n");
  }
}

Przepełnienie bufora może zostać wykorzystane do uruchomienia dowolnego kodu podrzuconego przez intruza. Jest to szczególnie niebezpieczne, jeśli atakowany program działa z najwyższymi uprawnieniami root'a. Najczęstszym celem takiego ataku jest uzyskanie dostępu do linni poleceń (ang. shell). Wyobraźmy sobie prosty i źle napisany program:

// vuln - bardzo zle napisany program
int main(int argc, char *argv[]){
  char buffer[500];
  strcpy(buffer, argv[1]);
}

Bufor jest na tyle duży, że swobodnie możemy umieścić w nim kod uruchamiający linię poleceń (ang. shellcode) napisany w asemblerze. Wystarczy tak przekierować adres powrotu, aby skok powrotu nastąpił pod kontrolowany przez nas adres pamięci. Drobnym problemem jest ustalenie tego adresu. W wielu innych systemach łatwo przewidzieć ten adres, bo nie zmienia się on wiele podczas wywołań różnych programów. W systemie GNU/Linux istnieje mechanizm obrony przed takim atakiem polegający, ale możemy go wyłączyć poleceniem echo 0 > /proc/sys/kernel/randomize_va_space. Jeśli tak, to możemy uzyskać poszukiwany adres w prosty sposób:

int main(int ac, char** av){
  int x;
  printf("%x\n",&x);
}

Załóżmy, że szukany adres wynosi: da99fca1. Właściwy atak na program vuln sprowadza się tylko do jego wywołania z odpowiednio spreparowanymi danymi.

./vuln `perl -e 'print "\x90"x202;'``cat shellcode.bin``perl -e 'print "\xa1\xfc\x99\xda"x70'`;

Kilka przydatnych informacji:

Istnieje wiele zabezpieczeń przed błędami przepełnienia bufora, poczynając od prostych zmian w strukturze programu, poprzez specjalną kontrolę długości danych, wykorzystanie bezpieczniejszych odpowiedników funkcji kopiujących dane (np. strncpy, dynamiczną alokacje pamięci, aż po użycie specjalnych bibiotek kontrolujących rozmiar danych (np. Libsafe).

Kolejną grupą błędów programistycznych są błędy wynikające z nieuważnego kontrolowania typów zmiennych. Przykładem może być mylenie zmiennych 'bez znaku' ze zmiennymi 'ze znakiem' (np. unsigned int i int). Jedno nieprecyzyjne użycie instrukcji sscanf w zamieszczonym poniżej programie powoduje, że nie tylko użytkownik ADMIN może zostać administratorem:

// user - kolejny zle napisany program
#define ADMIN 1234
int main( int ac, char **av){
  int user;
  if( av[1][0] == '-' ){
    printf("Blad, numery sa tylko dodatnie!");
    exit(1);
  }
  sscanf(av[1],"%u", &user);
  if( user == ADMIN ){
    user = -2;
  }
  if( user == -2 ){
    printf("Jestes administratorem !\n");
  } else {
    printf("Witaj uzytkowniku %d!\n",user);
  }
}

Potrzebna wiedza

Dodatkowe informacje

Warto przypomnieć sobie notatki z wykładu dotyczące bezpiecznego programowania. Prezentowane ataki wymagają dogłędnego zrozumienia działania systemu operacyjnego. Takie umiejętności nazywane są angielskim terminem hacking, i tym hasłem warto się posługiwać szukając dodatkowych informacji w sieci. Szczególnie polecamy:

Informacje organizacyjne

Część zajęć dotycząca shellcode'u powinna zostać przeprowadzona na maszynie wirtualnej z systemem DVL (Damm Vulnerable Linux http://www.damnvulnerablelinux.org). Maszyna jest uruchomiona na serwerze maszyn wirtualnych na hostie: bel.iem.pw.edu.pl Aby uzyskać dostęp należy:

Po zalogowaniu do maszyny powinnien być widoczny znak zachęty w postaci:

dsl@0[dsl]$

Przykładowe zadania

  1. Przeprowadź atak na program login, tak aby hasło zostało uznane za poprawne bez jego podawania.

  2. Zmodyfikuj program login, tak aby nie był możliwy atak przez przepełnienie bufora. (Zaproponuj 2 różne modyfikacje.)

  3. Wykorzystując błąd w programie vuln uzyskaj dostęp do linii poleceń.

  4. Zabezpiecz program vuln przed atakiem polegającym na przepełnieniu bufora. Zaproponuj dwa różne rozwiązania.

  5. Przeprowadź atak na program o buforze o innej długośći niż 500 bajtów.
  6. Pokaż w jaki sposób w programie user można zostać administratorem i na czym polega pokazany tam błąd.

  7. Zaproponuj poprawioną wersję programu user, odporną na błąd typów zmiennych. (Zaproponuj 2 różne modyfikacje.)


2015-09-23 06:44