material zum praktikumsversuch buffer overflows · sie werden in diesem praktikum einer auswahl...

23
Material zum Praktikumsversuch Buffer Overflows Betreut von: Dipl. Ing. Sebastian Gajek und Tim Werthmann Stand: 22. April 2008 Lehrstuhl f¨ ur Netz- und Datensicherheit Ruhr-Universit¨ at Bochum

Upload: others

Post on 24-Oct-2019

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Material zum Praktikumsversuch Buffer Overflows · Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem Umfang den Rahmen einer einzigen Vorlesung

Material zum Praktikumsversuch Buffer Overflows

Betreut von: Dipl. Ing. Sebastian Gajek und Tim Werthmann

Stand: 22. April 2008

Lehrstuhl fur Netz- und Datensicherheit

Ruhr-Universitat Bochum

Page 2: Material zum Praktikumsversuch Buffer Overflows · Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem Umfang den Rahmen einer einzigen Vorlesung

Inhaltsverzeichnis

1 Vorwort 1

2 Hinweise 1

3 Einleitung 2

4 Grundlagen 24.1 Die IA-32 Architektur . . . . . . . . . . . . . . . . . . . . . . . . . . 24.2 Buffer Overflow Varianten . . . . . . . . . . . . . . . . . . . . . . . . 54.3 Das Prinzip von Buffer Overflow Attacken . . . . . . . . . . . . . . . 64.4 Das Prinzip von Code Injection (Shellcode) und Obfuscation (Ver-

schleierung) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74.5 Auffrischung beim Umgang mit Pointern . . . . . . . . . . . . . . . . 9

5 Vorbereitung/Durchfuhrung 11

6 Hilfsfragen 12

7 Verwendete Programme 13

8 Aufgaben 14

i

Page 3: Material zum Praktikumsversuch Buffer Overflows · Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem Umfang den Rahmen einer einzigen Vorlesung

1 Vorwort

Ziel des Praktikums soll sein, ihnen grundlegendes Wissen der Netz- und Datensi-cherheit praktisch darzustellen. Neben dem didaktischen Erfolg soll der Spaß anKryptographie, Internetsicherheit und Programmierung im Vordergrund stehen.Nichtsdestotrotz sollten sie den Aufwand dieser Veranstaltung nicht unterschatzen!Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solcheinem Umfang den Rahmen einer einzigen Vorlesung uberschreiten wurden. Viel-mehr wird ihnen Wissen vermittelt, das Bestandteil einiger Grundlagenvorlesungenist, oder Basis fur vertiefende Vorlesungen sein wird.Aus diesem Grund ist ihre Vorbereitung entscheidend fur den Erfolg des Prak-tikums. Das Studium der angegebenen Literaturreferenzen ist Voraussetzung fureinen erfolgreichen Praktikumsversuch. Durch das Studium der Referenzen eignensie sich theoretisches Wissen an, das Grundlage fur die Durchfuhrung eines Versuchsist und welches anschließend in einem Versuch praktisch untermauert werden soll.Die Aufgabe eines Betreuers ist somit nicht die Vermittlung des Grundlagenwissens,sondern die Unterstutzung bei der Durchfuhrung ihres Versuchs.Vor Beginn eines Versuchs wird in einem Vortestat uberpruft, ob sie die Referenzenausreichend studiert haben. Damit wird sichergestellt, dass sie in der vorgegebenZeit die gestellten Aufgaben losen konnen. Sollte vom Betreuer festgestellt werden,dass sie nachweislich nicht vorbereitet sind, werden sie von dem Versuch ausgeschlos-sen und mussen zu einem Nachholtermin erscheinen. Ihr Ziel sollte es demnach sein,das Testat auf den direkten Weg zu erhalten.

2 Hinweise

Lesen sie sich zuerst das Grundlagenkapitel durch. Recherchieren sie bei Unklar-heiten im Internet, diskutieren sie mit Kommilitonen oder kontaktieren sie beischwerwiegenden Problemen ihren Betreuer. Nehmen sie bei ihrer Recherche dieangegebenen Quellen zur Hilfe, und versuchen sie sich an den Hilfsfragen zu orien-tieren. Sie sollten unter allen Umstanden auch Versuchen die Aufgaben so weit wiemoglich zu bearbeiten. Es ist ebenfalls moglich die Aufgaben vollstandig in Heim-arbeit zu losen, sofern ihnen alle Materialien zur Verfugung stehen. Ihre Losungenwerden vom Betreuer wahrend des Praktikums kontrolliert und bei nachweislichselbststandiger Erarbeitung erhalten sie vorab das Testat.Nach einem Versuch muss jede Gruppe ein Protokoll anfertigen, in dem die Herlei-tung, die Losung der Aufgaben, und vor allem deren Begrundung unter Ausnutzungdes gesammelten Wissens erortert werden. Bei der Begrundung konnen Zeichnun-gen helfen! Das Protokoll kann wahlweise in deutscher oder englischer Sprache er-stellt werden. Es sollte den orthographischen und grammatischen Anforderungender Sprache genugen. Sie haben bis zu einer Woche Zeit, um ihr computergefertig-tes Protokoll in ausgedruckter Form beim Betreuer abzugeben, ansonsten erhaltensie ihr Endtestat nicht.Sollte ihre schriftliche Ausarbeitung nicht den Hinweisen in [1] genugen, so ist diesein Grund ihnen kein Testat zu erteilen.Bei offenen Fragen richten sie sich immer an den jeweiligen Betreuer!

Viel Spaß

1

Page 4: Material zum Praktikumsversuch Buffer Overflows · Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem Umfang den Rahmen einer einzigen Vorlesung

3 Einleitung

1988 verursachte der sog. Morris Wurm die erste, groß angelegte Buffer OverflowAttacke. Seit diesem Zeitpunkt vergeht kaum ein Tag, an dem in der Fachpressekeine Meldungen von neuen Verwundbarkeiten in Betriebssystemen und Applika-tionen zu lesen sind, welche auch wirtschaftliche Schaden zur Folge haben.2001 verursachte zum Beispiel der Code Red Wurm einen Schaden von schatzungs-weise 2.5 Milliarden US Dollar.Gewohnlich sind schlechte Implementierungen Ursachen fur Buffer Overflow At-tacken. Sie treten vorallem in Zusammenhang mit Programmen auf, die mit pro-prietaren Sprachen wie z.B. Assembler, C oder C++ geschrieben wurden. DieseSprachen erwarten vom Programmierer, dass er die Speicheradressen eines Pro-gramms manuell verwaltet (alloziieren/allokieren), diese Aufgabe wird bei Hoch-sprachen jedoch nicht vollstandig durch den Programmierer, sondern vielmehr durchden Compiler (Ubersetzer) ubernommen. Im Gegensatz dazu verfugen modernereProgrammiersprachen wie Java, PHP oder Perl Verwaltungsmechanismen, die denbenotigten Speicher automatisch verwalten (z.B. garbage collection), vor der Kom-pilierung nach fehlerhaften (Rucksprung-)Adressen prufen oder uberdimensioniertePuffer auf die erlaubte Große reduzieren. Nichtsdestotrotz reichen diese Mecha-nismen fur einen prinzipiellen Schutz vor Buffer Overflows nicht aus, denn dieseSchutzmaßnahmen (z.B. durch Compiler durchgesetzt) sind in der Regel selbst mitproprietaren Sprachen entwickelt worden (Abbildung 1 zeigt einen Auszug unsiche-rer Funktionen in der C Standardbibliothek).Die Folgen eines Buffer Overflows sind, dass ein Angreifer eigenen Code einzuschleu-sen kann, um z.B den Programmfluss zu verandern oder einen Denial of Service(DoS) Angriff auszufuhren .

Abbildung 1: Einige unsichere Funktionen der standard C Bibliothek

4 Grundlagen

4.1 Die IA-32 Architektur

Heutige Computer basieren zumeist auf der Intel IA-32 Architektur (auch als x86Architektur bezeichnet). Diese Architektur beinhaltet ein Speichermanagement,dass ein Text/Data/BSS/Heap und Stack Segment aufweist (Abbildung 2). SeitEinfuhrung der 64Bit Prozessoren existiert auch eine IA-64 Architektur, diese istjedoch zur IA-32 Architektur inkompatibel und wird in den Itanium Prozessorenvon Intel verwendet. Die heutigen ”Heim-CPUs” auf 64Bit Basis gehoren zu denArchitekturen: AMD64 (auch x86 64 genannt) bzw. Intel64, wobei die Architektu-ren zu einander kompatibel sind sich jedoch auch in einigen Punkten unterscheiden.Der interessierte Leser sei hier auf weitere Literatur verwiesen.

2

Page 5: Material zum Praktikumsversuch Buffer Overflows · Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem Umfang den Rahmen einer einzigen Vorlesung

Das Text Segment ist schreibgeschutzt und beinhaltet die sog. ”opcodes” (ope-ration codes), welche das Programm definieren (sie werden ausgefuhrt, wenn dasProgramm gestartet wird). Das Data/BSS (Block Started by Symbol) Segment bein-haltet globale und statische Variablen, wobei die initialisierten Variablen im DataSegment und die uninitialisierten Variablen im BSS Segment gespeichert werden.Das Heap Segment wird zur dynamischen Zuweisung von Datenstrukturen benotigt(malloc Routinen), wobei der Programmierer fur die Verwaltung des Speicherplat-zes verantwortlich ist (free). Das letzte Segment ist das Stack Segment. Dies ist eineabstrakte Datenstruktur, basierend auf dem LIFO (Last In, First Out) Prinzip, wel-che lokale Variablen speichert (gultig innerhalb einer Funktion siehe [2, 3, 4, 8, 9]).Objekte werden per ”push” auf den sog. top of stack (das obere Ende des Stacks)gelegt und mit ”pop” kann das letzte Objekt des Stacks zuruckgeladen werden.Wichtig zu verstehen ist noch, dass das Stack Segment in der von uns betrachtetenArchitektur dynamisch von hohen zu niedrigen und das Heap Segment von niedrigenzu hohen Adressen wachst (Abbildung 2).

Dynamicgrowth

Highaddresses

Lowaddresses

Abbildung 2: IA-32 Speicherlayout

Intern nutzt die CPU1 Register zur Datenverarbeitung. Die fur dieses Praktikumwichtigen Register sind:

• EIP (Extended Instruction Pointer)

• EBP (Extended Base Pointer)

• ESP (Extended Stack Pointer)

• Generelle Verwendung finden die Register EAX/EBX/ECX/EDX2

Der EIP beinhaltet immer eine Adresse, die auf den nachsten auszufuhrenden Be-fehl zeigt. Das EIP Register wird von der CPU verwaltet und ist fur alle anderenVorgange (auch wenn dies u.U. erwunscht wird) schreibgeschutzt. Das EIP Registerwird jedoch von der CPU bei einer ”ret” (return) Anweisung mit 4 Byte aus demStack uberschrieben (normalerweise eine Adresse bei 32 Bit Adressierung; 8 Byte

1Central Processing Unit (der sog. Prozessor).2EAX wird z.B. immer fur Ruckgabewerte verwendet und ECX wird immer als counter fur

”loop” Aufrufe benutzt. Ubergabewerte fur Funktions-/API-Aufrufe werden mit Hilfe dieser Re-gister ubergeben (weitere Verwendungszwecke konnen sie z.B. aus [3, 4] entnehmen).

3

Page 6: Material zum Praktikumsversuch Buffer Overflows · Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem Umfang den Rahmen einer einzigen Vorlesung

in nativer 64 Bit Adressierung). Der ESP zeigt vor dem Return auf diese 4 Byte.Der ESP zeigt auf den ”top of Stack”, somit benotigt die CPU nur zwei Befehle(push und pop) um mit dem Stack zu arbeiten.Es ist jedoch notwendig innerhalb einer Funktion indirekt zu adressieren. Da sich derWert von ESP oft andert (bei jeder Stackoperation), ist der ESP denkbar ungeeig-net fur diese Aufgabe3. Darum wird fur diesen Zweck der EBP (auch Framepointergenannt) genutzt.Wenn eine Funktion mit dem Befehl ”call” aufgerufen wird, wird ein neuer Stack-frame fur diese Funktion erstellt (Abbildung 3). Die Grenzen dieses Abschnittessind der ESP (Ende des Stackframes) und der EBP (Anfang des Stackframes). Die”call” Direktive sichert zuerst den EIP mit dem Befehl ”push” auf dem Stack undlad die neue Adresse in das EIP Register. Dann beginnt der sog. Funktionsprolog.Der vorherige EBP wird per ”push” gesichert und der ESP wird mit ”mov” (move)in den EBP transferiert. Nun wird Platz fur die lokalen Variablen reserviert, indemderen Große vom ESP subtrahiert wird4 (Abbildung 4 zeigt einen exemplarischenFunktionsaufruf).Am Ende einer Funktion wird der EBP wieder in den ESP transferiert und derursprungliche EBP wird per ”pop” zuruckgeladen. Am Ende eines jeden Funktions-aufrufes steht dann letztendlich eine ”ret” Anweisung, die den EIP wiederherstelltund an dessen Position springt.

PUSH

POPStackframe

EBP (Start of the stackframe)

ESP (End of the stackframe)

Abbildung 3: Stackframe3Der ESP konnte als Referenz benutzt werden, jedoch wurde so mehr Overhead entstehen, da

die Anderungen des ESP nachgehalten werden mussten.4Wenn deren Große nicht durch Vier (4 Bytes→ 32 bit) teilbar ist, wird die Große zum nachsten

Vielfachen von Vier aufgerundet

4

Page 7: Material zum Praktikumsversuch Buffer Overflows · Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem Umfang den Rahmen einer einzigen Vorlesung

Abbildung 4: C Sourcecode und das Assembler Derivat

Zu erwahnen gilt noch der Aufbau eines Registers, bisher haben die Registerimmer das Format E X gehabt. E bedeutet dabei extanded und sagt aus, dasses sich um ein 32Bit Regsiter handelt und somit 4Byte groß ist (Hinweis: 32Bitbedeutet eigentlich 232, bei dieser Bezeichung bezieht sich 32Bit jedoch nur auf32 = 4 ∗ 8, wobei 8Bit ein Byte bilden). Ein 32Bit Register ist unterteilt in zwei16Bit Register, wovon jedoch nur das unterste direkt angesprochen werden kann (furuns interessant: AX, BX, CX, DX, SP, BP). Die 16Bit general purpose Regsiter sindwiederum in zwei acht Bit Register unterteilt, diese sind einzeln ansprechbar (AH,AL, BH, BL, CH, CL, DH, DL). Zu erwahnen sei noch, dass bei Codeoptimierungendiese Gegebenheiten oft mittels Logikverknupfungen ausgenutzt werden (z.B. AXand 0xFF loscht AH, AX and 0xFF00 loscht AL usw.).

4.2 Buffer Overflow Varianten

Heutzutage sind einige Buffer Overflow Attacken bekannt und man versteht auchdie Ursachen, die zu Buffer Overflows fuhren. Generell kann jeder Puffer, der durchunsichere Funktionen angesprochen wird, kompromitiert werden5. In der Fachlite-ratur werden die gangigsten Attacken wie folgt unterteilt (siehe dazu [5]):

• ”Stack smashing” wird benutzt um eigenen, bosartigen Code einzubringen(Shellcode) oder um DoS (denial of service) Attacken durchzufuhren

• ”Variable Attack” wird benutzt um den Programmzustand zu modifizieren(verwand mit Stack smashing)

• ”Heap Overflow” wird benutzt um beliebigen Code auszufuhren oder um Va-riablen zu modifizieren

• ”Off-By-One” ist ein klassischer Programmierfehler, bei dem genau ein Byteuberschrieben wird (z.B. durch falsche Schleifengrenzen wie: zahle von 1 bis10 realisiert als for(i=0;i<=10;i++), wobei hier elf Iterationen durchgefuhrtwerden)

5Es existieren Moglichkeiten die Unsicherheit durch Ausnahmefehler oder Vorabprufungen zureduzieren oder aufzuheben.

5

Page 8: Material zum Praktikumsversuch Buffer Overflows · Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem Umfang den Rahmen einer einzigen Vorlesung

• ”BSS Overflow” ist verwand mit Heap Overflows/Variable Attack

• ”Signed/Unsigned Overflows” treten aufgrund von Fehlinterpretationen auf.Negative Zahlen werden mit Hilfe des Zweierkomplements dargestellt und sindriesig, sofern sie als positive Zahlen interpretiert werden (das hochste, mostsignificant Bit ist dabei immer gesetzt)

• ”Frame Pointer Overflow” ist verwand mit Stack smashing und missbrauchtden EBP zur indirekten Adressierung oder um den Stackframe zu schadigen(DoS)

4.3 Das Prinzip von Buffer Overflow Attacken

Zur Veranschaulichung eines Buffer Overflows soll uns das Stack smashing als Bei-spiel dienen (die anderen Attacken sind ahnlich6). Beim Stack smashing werdenalle Variablen uber der angegriffenen Variable uberschrieben (da der Stack vonoben nach unten, Variablen, insbesondere Strings (Array of Char), aber von untennach oben geschrieben werden). Da der EBP uberschrieben wird, ist der Stackframenach einer solchen Attacke, ohne weitere Schutzmaßnahmen getroffen zu haben [5],irreparabel beschadigt, so dass eine weitere Ausfuhrung des Programmes oder derUnterfunktion zu einem Segmentierungsfehler (Segmentation Fault) fuhrt (Abbil-dung 5).

Abbildung 5: Stack smashing durch die Funktion strcpy

Ein interessanter Aspekt an der Attacke ist, dass der gesicherte EIP der einzigeWeg ist, um den Ausfuhrungspfad des Programmes zu verandern (da der EIP von

6Die Attacken sind i.d.R komplexer, da einfache Fehler meist schon in der Entwicklung behobenwerden, unser Beispiel soll auch nur das Schema darstellung und ist desshalb in einer einfachenForm gewahlt. Wie sie aber im Verlauf des Praktikums bemerken werden, existieren Programmeauf denen genau dieses Schema zutrifft.

6

Page 9: Material zum Praktikumsversuch Buffer Overflows · Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem Umfang den Rahmen einer einzigen Vorlesung

der CPU verwaltet wird, kann der EIP nie durch einen Prozess/Benutzer manipu-liert werden). Stack smashing kann dazu benutzt werden, um beliebigen Code in denPuffer einzubringen, um dann spater den EIP auf den Start dieses Puffers zeigen zulassen. Hierfur wird der gesicherte EIP verandert (er liegt im Stack uber dem EBP),welcher spater von der CPU wiederhergestellt wird (weiterfuhrende Informationenin [6, 7]).

4.4 Das Prinzip von Code Injection (Shellcode) und Obfus-cation (Verschleierung)

Wenn ein Angreifer eine Buffer Overflow Schwache in einem Programm gefundenhat, kann er ein Programm einschleusen, den sog. Shellcode7. Dieser Angriff ist furdas Opfer sehr gefahrlich, denn wenn es dem Angreifer gelingt eine solche Shell zuoffnen, hat dieser die volle Kontrolle uber den Computer8.Ein solcher Shellcode unterliegt einigen Regeln, welche es erschweren Shellcodeszu schreiben. Zum einen muss der Code klein sein (je kleiner desto besser) under darf unter keinen Umstanden sog. Terminatoren enthalten (z.B. ist 0x00 derStringterminator, er markiert das Ende eines Strings). Verarbeitet die betroffeneFunktion (z.B. strcpy) einen String und der Shellcode enthalt 0x00, bricht strc-py das Kopieren ab dem Terminator ab (dies ist naturlich fur den Angreifer nichtwunschenswert). Es gibt daher einige spezielle Funktionen, die man zum Schreibenvon Shellcodes einsetzt [6]. Die Große fur einen Shellcode, die zur Verfugung steht,ist definiert durch den reservierten Speicher auf dem Stack (die Große der ange-griffenen Variable plus alle Variablen uber dieser Variable plus dem EBP und dasganze nach 32 Bit Grenzen (4 Byte) gerundet).Der Code selbst wird in Assembler geschrieben und in das Format Flat- bzw. Raw-Binary kompiliert, d.h. die Assemblerbefehle werden nur ”eins zu eins” ubersetzt,ohne Optimierungen oder Einfugen von weiteren (zur Laufzeit benotigten) Infor-mationen. Dadurch konnen sie den Code zwar einschleusen, ihn aber nicht direktausfuhren, da er keinem ausfuhrbaren Format entspricht (Abbildung 6 zeigt einenShellcode der ”Obfuscation” Techniken anwendet [6]). Warum dieser Code nichtdirekt ausfuhrbar ist, wird erst klar, wenn man sich die Umgebung ansieht, in derdieser Code ausgefuhrt werden soll, also das Betriebssystem (Operating System,OS). Da wir uns in diesem Praktikum auf das OS Windows beschranken, sei hierdarauf hingewiesen, dass alle ausfuhrbaren Dateien (stand-alone, also nicht zu ver-wechseln mit Batch Dateien) dem Portable Executeable (PE) Format unterliegen.Dieses Format besitzt eine Praeamble, den sog. PE Header, welcher dem Loaderalle wichtigen Informationen uber die Datei liefert. Da wir wirklich nur den Codehaben, ohne weitere Angaben ist diese Datei nicht im geringsten ausfuhrbar. Derinteressierte Leser sei hier auf weiterfuhrende Literatur zum PE Header verwiesen.

7Benannt nach seinem ursprunglichem Ziel eine Root-Shell (Administratorkonsole im Un-ix/Linux Bereich) zu offnen.

8Unter der Annahme, dass der Prozess zum starten der Shell mit Administrator-/Root-Rechtenausgefuhrt wurde

7

Page 10: Material zum Praktikumsversuch Buffer Overflows · Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem Umfang den Rahmen einer einzigen Vorlesung

Abbildung 6: Shellcode geschrieben in Assembler, mit XOR Code Obfusciation

Als Code Obfuscation bezeichnet man alle Moglichkeiten, ein Programm so zuverandern, dass Analysen des Programmcodes schwierig werden. Das eigentlicheProgramm wird dabei aber nicht verandert. Es gibt Methoden zur Verschleierung,die polynomiell bei der Erzeugung sind, fur die man aber exponentielle Zeit benotigt,um die Verschleierung ruckgangig zu machen. Einige wichtige Methden sind:

• Encryption (Verschlusselung). Dazu verwendet man aufgrund des Platzman-gels meist XOR Techniken (One-Time-Pad) oder andere Techniken, sofern sievon Platz realisierbar sind, um den Code zu tarnen

• Splitting. Dabei werden Variablen und Arrays (Felder) verteilt, um einen Ana-lysten zu verwirren und um (automatische) Flussanalysen zu erschweren bzw.zu verhindern

• Einfugen von uberflussigen Daten, verhindert einige Disassemblierungsversu-che, verwirrt Leser des Quelltextes

• Einfugen von uberflussigen Sprungroutinen, erzeugt riesige Referenztabellenbei Analysen, ist schwer zu lesen und erzeugt bei Flussgraphen z.T. nichtunterscheidbare Ablaufe

Alle Verschleierungen konnen (derzeitig) ruckgangig gemacht werden, jedoch ver-hindern polymorphe (sich selbst verandernde) Shellcodes die Uberprufung durchSignaturen. Wenn ein Shellcode mit der XOR Methode verschlusselt wird, existie-ren nach dem ASCII Zeichensatz 255 Signaturen pro Shellcode (dies erfordert eineMenge Speicherplatz).

Als letztes soll noch auf eine Technik hingewiesen werden, die von Angreifern sehroft eingesetzt wird, dem sog. NOP-Sliding. Bei einem NOP handelt es sich um denhexadezimalen Wert ”0x90”. Dieser bewirkt, dass die CPU einen Takt lang ”pau-siert” (NOP = No Operation). Wenn ein Shellcode eingeschleust wird, muss immeran den Anfang des Shellcodes ”gesprungen” werden (ohne Abweichungen!), damitdieser korrekt ausgefuhrt wird. Wird der Shellcode vor dem neuen EIP platziert

8

Page 11: Material zum Praktikumsversuch Buffer Overflows · Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem Umfang den Rahmen einer einzigen Vorlesung

(der sich noch im Stack befindet) und der Puffer mit NOPs aufgefullt, kann irgend-wo in den mit 0x90 gefullten Bereich gesprungen werden (also irgendwo vor demShellcode). Die NOPs werden die Ausfuhrung zum Anfang des Shellcodes ”tragen”(man gleitet (to slide) formlich uber die NOPs hinweg).

4.5 Auffrischung beim Umgang mit Pointern

Sie sollten im Laufe ihres bisherigen Studiums bereits eine Vorlesung uber Pro-grammiersprachen gehort haben in der Pointer (Zeiger) verwendet werden. Da indiesem Praktikum besonders die Programmiersprache C verwendet wird und derZusammenhang zwischen Pointern und Adressen eines Computers gut sichtbar ist,soll hier eine kurze Wiederholung stattfinden.Eine Architektur mit x Adressleitungen wird auch xBit Architektur genannt undkann, da Bits verwendet werden, 2x Datentypen adressieren. Der kleinste adres-sierbare Datentyp in der IA-32 Architektur ist ein Byte, zwei Byte bezeichnet manauch als Word und vier Byte als DWord oder Double Word. Es existieren jedochauch Bezeichnungen wie Nibble (vier Bit, also ein halbes Byte) und Quad Word(acht Byte). Die IA-32 Architektur ist eine 32Bit Architektur, d.h. es existieren 32Adressleitungen, wobei jede Leitung binar angesteuert wird. Aus der Kombinatorikkennt man das ungeordnete Ziehen mit Zurucklegen von k Elementen aus einer nelementigen Menge mit nk, hieraus folgt, dass 232 Byte (= 210∗210∗210∗22 = 4GigaByte) existieren bzw. adressierbar sind.Ein Pointer wird in C wie folgt beschrieben:

TYPE * NAME (z.B. int * Zahlen)

Dies ist eine dynamische Datenstruktur welche im Heap liegt, und bisher nur ei-ne Adresse aus dem oben beschriebenen Adressraum darstellt. Um diese Variableals Speicherplatz zu verwenden, muss der Adresse noch Speicherplatz zugewiesenwerden, dies geschieht mit

malloc (z.B. (int *) malloc(size))

Dabei reserviert malloc ”size” viele Bytes, diese sind noch typenlos (wie z.B. In-teger), daher wird mittels Casting (hier (int *)) der Speicherplatz als Array ofinteger deklariert. Um Fehler zu vermeiden wird daruber hinaus ”size” i.d.R. alsy*sizeof(TYPE)geschrieben, dabei wird y viel Speicherplatz der Große TYPEreserviert, wobei TYPE i.d.R. zwischen einem und x/8 Byte (wobei x die Anzahlder Adressleitungen darstellt) beansprucht.Es ist eigentlich klar, dass

int * Zahlen = (int *) malloc (4*sizeof(int))und

int Zahlen[4]

die selbe Struktur haben, nur ist die zweite Form statisch, die erste dynamischund damit auch wahrend der Laufzeit in der Große veranderbar. Dafur muss derProgrammierer den Speicherplatz fur die erste Form am Ende selber wieder freigeben

free(Zahlen)

Nach der Alloziierung bezeichnet die Variable ”Zahlen” das erste Element des Fel-des, es ist also aquivalent mit ”Zahlen[0]”. Einer Adresse bzw. einem Pointer kannman nun Offsets (Verschiebungen) hinzufugen, wie z.B. Zahlen++ oder Zahlen+v,

9

Page 12: Material zum Praktikumsversuch Buffer Overflows · Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem Umfang den Rahmen einer einzigen Vorlesung

mit v eine Ganze Zahl UND innerhalb des definierten Arrays9. Um auf den derzei-tigen Wert der Adresse/des Pointers zuzugreifen, muss der Pointer dereferenziertwerden (z.B. *Zahlen), der Compiler sorgt in diesem Fall dafur, dass die richtigeAnzahl an Bytes in der richtigen Reihenfolge zuruckgeliefert wird. Soll ein festerWert hingegen als Pointer ubergeben werden, also die Adresse des Wertes, so musser referenziert werden (&Wert). Somit kann man einer Funktion

int test (int * a)

die Variable c = 3 ubergeben, indem

test(&c)

aufgerufen wird (fur das Arbeiten mit diesem Pointer innerhalb der Funktion geltenwieder alle Aussagen wie oben erlautert).Zu Sagen bleibt noch, dass eine dynamisch erzeugte Struktur, da sie aquivalent zueinem Array ist, auch wie ein Array genutzt werden kann. Auf int * Zahlen =(int *) malloc (4*sizeof(int))kann statt mit

Zahlen, Zahlen+1, Zahlen+2, Zahlen+3

auch mit

Zahlen[0], Zahlen[1], Zahlen[2] und Zahlen[3]

zugegriffen werden (dies wird im Laufe dieses Versuchs auch noch Anwendung fin-den). Die Werte konnen aber wiederum referenziert werden, z.B. ist

&Zahlen[0]

das selbe wie

Zahlen bzw. Zahlen+0

(siehe Fußnote).Wichtig ist also zu verstehen, dass eine Adresse wie 0x7C586912 im Computer einPointer auf genau ein Byte darstellt. Sollte nun ein Typ großer als ein Byte referen-ziert werden, so mussen wir zur Erklarung kurz auf die Low-Level Ebene wechselnund etwas Assembler besprechen. Ein Compiler macht an sich nichts weiter als dieHochsprache in Assembler zu ubersetzen, wobei dies nicht ganz korrekt ist. DerCompiler ubersetzt in Opcodes, diese konnen jedoch direkt als Assembler inter-pretiert werden (daher kann man kompilierte Dateien auch disassemblieren). Wennein Wert aus dem Speicher gelesen wird, wird der Wert in ein Register geschrie-ben (es existieren auch direct memory Befehle, der interessierte Leser sei hier aufweiterfuhrende Literatur verwiesen). Wird als Ziel ein 32Bit Register angegeben,so werden 4 Byte gelesen. Wird ein 16Bit Register angegeben, so werden 2 Bytegelesen. Wird ein 8Bit Register angegeben, so wird ein Byte gelesen. Die Organisa-tion dieser Vorgange liegt im CPU und interessiert den Programmierer daher nicht.Es existieren auf CISC CPUs wie bei der IA-32 Architektur auch Befehle um klei-nere Datentypen in großere Register zu laden und um mit RegisterkombinationenZahlen doppelter Breite zu handhaben (64 Bit verteilt auf zwei Register, z.B. beiMultiplikation zweier 32Bit Zahlen), diese sind hier aber nicht wichtig. Wichtig ist,dass der Compiler anhand des Datentyps das Zielregister und den entsprechendenLadebefehl (z.B. ”mov”) wahlt und somit die korrekte Anzahl an Bytes gelesen

9Wenn Zahlen nach malloc nicht verandert wurde, so sind Zahlen+v und Zahlen[v] aquivalent,dies ist nicht mehr der Fall, nachdem etwas wie Zahlen = Zahlen+v ausgefuhrt wurde, diessollte klar sein, da man sich nun beim Aufruf von Zahlen nicht mehr an Position Null sondern anPosition v befindet.

10

Page 13: Material zum Praktikumsversuch Buffer Overflows · Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem Umfang den Rahmen einer einzigen Vorlesung

wird. Der Programmierer hat dann aber die Aufgabe die nachsten Daten korrektzu adressieren. Der Befehl mov ebx, [eax]10, wobei eax eine Adresse enthalt(”[]” bedeutet Referenzierung, also in C &eax) kopiert die vier Byte ab der Posi-tion eax nach ebx. Das nachste DWord bekommt man nur, wenn als nachstes movebx, [eax+4]adressiert wird. Da eax das erste, eax+1 das zweite usw. Byteadressiert, werden bei mov ebx, [eax]die Bytes

eax, eax+1, eax+2 und eax+3

kopiert, also startet das nachste DWord bei eax+4. Alle anderen Adressierungenfolgen diesem Schema.

5 Vorbereitung/Durchfuhrung

1. Lesen sie die Einleitung durch. Benutzen sie ggf. die Referenzen zur Vertiefungihres Wissens.

2. Untersuchen sie die C/Assembler Quellcodes aus den Aufgaben. Welche Funktionhaben sie? Hinweis: Es ist nicht notwendig die Bedeutung jedes Befehls zu kennen,sondern sie sollen den Sinn der Skripte verstehen (Fuzzer/Exploit/etc.).

3. Gehen sie die Aufgaben Schritt fur Schritt durch.

4. Schreiben sie eine ca. 10-seitige Auswertung. Gehen sie (außer in Aufgabe 10)davon aus, dass sie ein Angreifer sind und beschreiben sie:

a. Welche Software haben sie benutzt?

b. Wie sind sie vorgegangen?

c. Was haben sie (fur Probleme) bemerkt?

d. Warum sind die Probleme entstanden?

e. Wie haben sie diese Probleme gelost?

f. Wo enstand ein Buffer Overflow?

g. Wie haben sie ihn ausgenutzt?

h. Wie sahen die verwendeten (Angriffs-)Parameter (z.B. Puffer) aus?

5. Geben sie ihre Dokumentation binnen einer Woche beim Betreuer ab.

10Der Standardsyntax in Assembler lautet Befehl Destination, Source , Befehl ist dabeiein Assembler Befehl (Mnemonic), Destination ist der Ort fur das Ergebnis der Operation, Sourceist der zweite Operand, sofern vorhanden (abhangig vom Befehl).

11

Page 14: Material zum Praktikumsversuch Buffer Overflows · Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem Umfang den Rahmen einer einzigen Vorlesung

6 Hilfsfragen

• Was ist ein Puffer?

• Wie ist der Speicher aufgebaut?

• Wie ist ein Stack aufgebaut?

• Wie ist ein Stackframe aufgebaut?

• Was ist ein Stack Pointer? Wofur brauche ich ihn? Wie ist er aufgebaut?

• Was ist ein Base Pointer? Wofur brauche ich ihn? Wie ist er aufgebaut?

• Was ist ein Pointer? Gibt es Zeiger in Java?

• Was braucht man, um einen Buffer-Overflow auszunutzen?

• Welche Varianten von Buffer Overflows gibt es?

• Warum sind Buffer Overflows (in der Theorie) nicht mit Java moglich?

• Wie konnen Buffer Overflows verhindert werden?

• Skizzieren Sie den Ablauf eines Buffer Overflows!

• Wie sieht der Speicher aus, wenn eine Funktion main() eine lokale Variableauf 100 zahlt?

• Wozu benutzt man Shellcodes?

• Was ist NOP-Sliding?

• Wie findet man Buffer Overflows (generell, keine Details)?

• Was ist ein Jumpcode?

• Nennen sie mindestens zwei Verschleierungsmethoden (obfuscation)!

• Was ist der Unterschied zwischen mov eax, 0 und xor eax, eax?

• Beschreiben sie, wie sie ein dynamisches Array of char der Große 100 erzeugen!

• Was macht folgender Aufruf:char** strArray = (char**) malloc (anz*sizeof(char*))?Konnen sie nach diesem Aufruf mit strArray arbeiten? Wenn ja, wie arbeitensie damit? Wenn nein, was muss als nachstes geschehen und wie arbeitensie dann mit strArray? Gibt es noch mehr Methoden um mit strArray zuarbeiten?

• Wie lautet die little endian Darstellung von 0x7C239088?

• Warum wahlt man mogliche Sprungadressen in Exploits in Betriebssystemmo-dulen? Gibt es eine/mehrere weitere gute Moglichkeit solche Sprungadressenzu finden? Wenn ja, nennen sie mindestens eine!

12

Page 15: Material zum Praktikumsversuch Buffer Overflows · Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem Umfang den Rahmen einer einzigen Vorlesung

7 Verwendete Programme

Im Praktikum werden sie folgende Programme verwenden (Programmname/Funktion/Pfad):

Dev-C++ Ver. 4.9.9.0: Kompiler mit IDE fur C/C++. Installiert, zu finden uberdas Startmenu

Netwide Assembler (NASM) Ver. 0.98.39: Kompiler fur Assembler.C:\BO\Programme\NASM\nasmw.exe Aufruf zum Kompilieren eines Shellcodes:”nasmw -f bin shellcode.asm -o shellcode”

OllyDbg Ver. 1.10: Ein 32 Bit Debugger zum Analysieren von Programmen (insbe-sondere benotigt, wenn der Quelltext nicht verfugbar ist).C:\BO\Programme\Ollydbg\OLLYDBG.EXE

XVI32: 32 Bit Hexeditor zum betrachten des Binarcodes im hexadezimalen For-mat. C:\BO\Programme\xvi32\XVI32.exe

Das verwendete Betriebssystem ist Windows XP mit Service Pack 2.

13

Page 16: Material zum Praktikumsversuch Buffer Overflows · Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem Umfang den Rahmen einer einzigen Vorlesung

8 Aufgaben

Im Nachfolgenden sollen sie nacheinander die drei Programme strcpy.exe, lame gets.exeund Winamp (Ver. 5.12) auf die Anfalligkeit bei Buffer Overflow Attacken testenund diese Anfalligkeit ausnutzen, sowie ein sog. Exploit11 fur jedes der drei Pro-gramme schreiben. Die ersten beiden Programme (strcpy.exe und lame gets.exe)bestehen nur aus einer Routine, dem Einlesen eines Strings. Dazu werden die un-sicheren Funktionen strcpy und gets verwendet. Des Weiteren sind in den beidenProgrammen eine ”geheime” Funktion enthalten, die sie zuerst manuell und spaterdann automatisch aufrufen sollen.

In Aufgabe 3 werden sie ein reales Beispiel kennenlernen. Dazu werden sie einenBuffer in dem Multimedia Programm Winamp ausnutzen, um beliebigen Code ein-zuschleusen und auszufuhren. Nachdem sie auch fur dieses Beispiel ein Exploit ge-schrieben haben, sollen sie das Exploit von einem local in ein remote12 Exploitumwandeln. Sollte danach noch genugend Zeit vorhanden sein, werden sie den Blick-winkel eines Security Advisors einnehmen und sie werden die beiden Offsets zu denbeiden Schleifen herausfinden, die fur den Buffer Overflow verantwortlich sind.

Hinweis: Achten sie darauf, dass Ollydbg im JIT (Just In Time) Debugger Moduslauft (Options → Just-in-time debugging → Make OllyDbg just-in-time Debugger).Dies konfiguriert Ollydbg dazu bei Ausnahmefehlern zu reagieren (sonst reagiertDrWatson, eine Windows Applikation).

Aufgabe 1.1

Benutzen sie das Fuzzer13 Programm

C:\BO\Aufgaben\1\strcpy_test.exe

um das Programm

C:\BO\Aufgaben\1\strcpy.exe

auf die benotigte Puffergroße zu testen. Der Aufrufsyntax ist dabei wie folgt:

C:\BO\Aufgaben\1\strcpy_test.exe strcpy.exe <PUFFERGROßE>

Da Ollydbg im JIT Modus lauft, wird Ollydbg bei einem Ausnahmefehler denProgrammfluss unterbrechen. Daraufhin sollten sie sich in Ollydbg die EIP Adresseanschauen. Lautet diese 41414141 (AAAA), haben sie die richtige Puffergroßegetroffen14. Ansonsten mussen sie die Puffergroße variieren.Geben sie die Große des Puffers an, der den EIP zu uberschreibt.

Tipp: Die Große des Puffers liegt zwischen 520 und 530 Byte.11Ein Exploit ist ein automatisierter Angriff auf ein Programm (to exploit = ausbeuten), wel-

ches i.d.R. dazu verwendet wird Computer zu kompromittieren (um z.B. Administratorrechte zuerlangen).

12Local Exploits funktionieren nur, wenn man auf dem angegriffenen Computer eingeloggt ist,remote Exploits funktionieren uber das Netzwerk.

13Ein Fuzzer testet ein Programm auf Buffer Overflows, indem ein beliebig großer Puffer generiertwird um einen Ausnahmefehler in dem getesteten Programm zu verursachen.

14In ihrer Ausarbeitung sollten sie kurz erklaren, warum der EIP 41414141 seien sollte, wie derRest des Puffers aussieht und warum der Fuzzer nur vier mal 41 in den Puffer schreibt (Tipp: Eshat etwas mit der Adressierung zu tun).

14

Page 17: Material zum Praktikumsversuch Buffer Overflows · Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem Umfang den Rahmen einer einzigen Vorlesung

Aufgabe 1.2

Nachdem sie nun wissen, wie groß der Puffer ist, modifizieren sie den Fuzzer

C:\BO\Aufgaben\1\strcpy_test.c

so, dass dieser nicht mehr strcpy.exe aufruft (Tipp: den ”execve”Aufruf auskom-mentieren), sondern den Puffer in eine Datei ausgibt (Tipp: im Quelltext sind vierauskommentierte Befehle/Befehlsfolgen. Wenn sie die Kommentare entfernen unddas Programm erneut kompilieren (in DevC++ Strg+F9), wird der Fuzzer den Puf-fer in die Datei out.txt (im selben Verzeichnis) ausgeben).Fuhren sie den Fuzzer danach erneut aus und benutzen sie den ausgegebenen Puffer(Kopieren und Einfugen) als Parameter in Ollydbg. Dazu offnen sie Ollydbg undklicken auf File → Open. Die zu offnende Datei ist strcpy.exe und das Argument istder von ihnen kopierte Puffer.Nachdem Ollydbg die Datei geladen hat sehen sie dessen Opcodes in disassemblier-ter Form. Suchen sie zuerst nach der ”geheimen” Funktion (in unserem Fall fuhrtdiese ”calc.exe” aus) und merken sie sich die Adresse (Tipp: Die Adresse muss derAnfang einer Funktion sein (in Ollydbg links durch einen schwarzen Strich gekenn-zeichnet, der sich uber die gesamte Funktion zieht)). Danach suchen sie den Aufrufvon strcpy und markieren sie den Aufruf mit einem Breakpoint (F2).Nun fuhren sie das Programm aus (F9). Ollydbg sollte an der strcpy Funktion hal-ten. Nun tracen15 sie (F8) bis zum nachsten ”Return” (RETN) und schauen sie sichden Stack am ESP an (→follow in dump). Dieser sollte nun 41414141 aufweisen.Modifizieren sie diesen Wert mit der Adresse der geheimen Funktion (Rechtsklickmit der Maus auf den Stackwert→ Modify) und lassen sie das Programm weiterlau-fen (F9).Dokumentieren sie ihre Sprungadresse und erlautern sie ihre Beobachtungen.

Aufgabe 1.3

Nun sollen sie strcpy.exe mit einem Exploit angreifen, dazu offnen sie

C:\BO\Aufgaben\1\strcpy_exploit.c

und tragen ihre gefundenen Werte an die richtigen Stellen ein (BUF LEN sowieteststr benotigen noch Werte).BUF LEN sollte ihre gefundene Puffergroße sein (innerhalb des Exploits wird danndie exakte Puffergroße berechnet, denn sie konnen mehr Daten in den Puffer schrei-ben als sie es herausgefunden haben16. Dadurch konnen sie einen sog. Jumpcode17

einschleusen (vorgegeben = stage1) und diesen mit einem Sprung zur Adresse vonESP ausfuhren (jmp esp)). Wir bedienen uns dabei der Tatsache, dass der An-fang der Daten die nach dem gesicherten EIP auf dem Stack liegen, durch den ESPmarkiert wird. Dazu mussen sie jedoch einen Weg finden, um ESP ausfuhren zukonnen (Tipp: jmp esp hat den Opcode FFE4, sie konnen diesen Code mit Hilfevon Ollydbg in geladenen Modulen suchen (sie offnen dazu strcpy.exe innerhalb von

15Es gibt zwei Moglichkeiten manuell Befehle in einem Programm mitzuverfolgen: execute(F7) und step over (F8). Dabei ”uberspringt” F8 einen call, F7 springt zur Call-Adresse (diesich ggf. in einem anderen Modul befindet) und man muss bis zum nachsten return tracen um zurAugangsposition + eine Adresse zu kommen.

16Wenn sie zu viele Daten hineinschreiben, uberschreiben sie ggf. sog. Exceptionhandler desBetriebssystems (SEH (Structured Exception Handler)). Dadurch wird der Prozess vom Betriebs-system abgefangen und i.d.R. beendet. Sie konnen es selbst testen, indem sie einen Breakpoint aufden Return-Befehl (siehe Aufgabe 2) setzen und als Puffergroße z.B. 20 Byte mehr nehemen undsich die Adresse des ESP anschauen.

17Ein Jumpcode ist dem Shellcode nicht unahnlich, jedoch ist seine Aufgabe den Programmflusszum Shellcode umzuleiten.

15

Page 18: Material zum Praktikumsversuch Buffer Overflows · Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem Umfang den Rahmen einer einzigen Vorlesung

Ollydbg). In Ollydbg bietet sich hierfur die Datei ntdll.dll an18. Wenn sie diese Da-tei in Ollydbg laden (ALT+E → Doppelklick auf den Eintrag von ntdll.dll), konnensie mit Strg+B diesen Opcode suchen. Die gefundene Adresse mussen sie dann als”Array of Char” (teststr ist als Array of Char deklariert worden) in den Quelltexteinbringen (Hinweis: der Computer benutzt das sog. little endian Format, d.h. siemussen die Adresse ”verkehrt herum” schreiben (z.B. 12345678 → 78563412)19).Orientieren sie sich an dem Format von stage1, so sollte auch das Array fur test-str aussehen). Der Shellcode ist vorgegeben und offnet einen Telnetserver auf Port4444 (zu testen mit netstat -ano)20. Sie konnen nach dem erfolgreichen Kompilierentesten, ob sie sich einloggen konnen (telnet 127.0.0.1 4444).Erlautern sie, welche Adresse sie gewahlt haben, um ESP anzuspringen und welcheWerte sie im Exploit verwendet haben.

Aufgabe 2.1

Benutzen sie nun das Fuzzer Programm

C:\BO\Aufgaben\2\gets_test.exe

um das Programm

C:\BO\Aufgaben\2\gets.exe

auf die benotigte Puffergroße zu testen. Die Aufrufsyntax ist dabei wie folgt:

C:\BO\Aufgaben\2\gets_test.exe gets.exe <PUFFERGROßE>

Da Ollydbg im JIT Modus lauft, wird Ollydbg bei einem Ausnahmefehler den Pro-grammfluss unterbrechen. Daraufhin sollten sie sich in Ollydbg die EIP Adresseanschauen. Ist diese 41414141 (AAAA), haben sie die richtige Puffergroße getrof-fen.Geben sie die Große des Puffers an, um den EIP zu uberschreiben.

Tipp: Die Große des Puffers liegt zwischen 40 und 50 Byte.

18Man sollte diese Adresse in einem Modul des Betriebssystems finden, damit ist diese fur jedenComputer mit der selben Betriebssystemversion und -sprache gultig→ nahezu universell einsetzbarund muss nur bei Anderungen des Betriebssystems neu ermittelt werden.

19Ein unsigned Char hat den Wertebereich 0 bis 255 oder hexadezimal 0x00 bis 0xFF (ge-nau ein Byte), es werden also die Bytes gedreht; Das most significant byte wird also das leastsignificant byte, die anderen wechseln entsprechnd die Position. Anmerkung: ein Nibble (4 Bit)kann genau als ein Hexadezimalzeichen geschrieben werden (4 bit hat den WerteBereich 0 bis 15,ein Hexadezimalzeichen den Wertebereich von 0 bis F, wobei F = 15). Bsp.: 1010 = A. Mehrereaneinanderergereihte Nibble konnen dann wie aneinandergereihte Hexadezimalzeichen geschriebenwerden; Ein Byte = zwei Nibble = zwei Hexadezimalstellen.

20Ein Screenshot von ”netstat -ano” unterstreicht ihre Versuchsbeschreibung in der Ausarbei-tung.

16

Page 19: Material zum Praktikumsversuch Buffer Overflows · Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem Umfang den Rahmen einer einzigen Vorlesung

Aufgabe 2.2

Auch hier gilt wieder, dass sie mehr Daten in den Puffer schreiben konnen als siezum Ausnahmefehler brauchen. Darum konnen sie wieder den ESP anspringen, umeigenen Code auszufuhren. Diesmal sollen sie jedoch keinen Shellcode einbringen,sondern nur einen Jumpcode der die ”geheime” Funktion anspringt (gehen sie zurFindung des Offsets vor wie in Aufgabe 1.2. Es ist der selbe Aufruf). Nachdem siedie Adresse gefunden haben, schreiben sie einen eigenen Jumpcode und kompilierendiesen mit NASM (nasmw -f bin jumpcode2.asm -o jumpcode2, wobei die ASM Dateimit einem Texteditor erstellt wird). Tipp: Schauen sie sich die Datei

C:\BO\Aufgaben\1\jumpcode1.asm

an und erstellen sie die Datei nach dem selben Syntax (es existiert bereits eineDatei Namens ”jumpcode2.asm” im Aufgabenverzeichnis, sie konnen/sollten dieseverwenden).Tipp: verwenden sie das EBX Register und loschen sie dieses unter Verwendungdes XOR Befehls. Fullen sie es danach mit 0x90909090 unter der Verwendungder MOV Anweisung und subtrahieren sie die Differenz zum Offset21 der geheimenFunktion in hexadezimaler Schreibweise (0x...) mit der SUB Direktive. Zu guterLetzt ”springen” sie nach EBX mit der JMP Anweisung. Uberprufen sie nach demKompilieren die Ausgabedatei mit dem Hexeditor

C:\BO\Programme\xvi32\XVI32.exe

und denken sie daran, dass keine 0-Folgen (z.B. 00, 0000 o.a.) enthalten sein durfen.Ist dies doch der Fall, mussen sie andere Operationen in ihrem Jumpcode durchfuhren.

Aufgabe 2.3

Benutzen sie nun ihren Jumpcode als Wert fur ”shellcode” (in XVI32 konnen sieden Jumpcode markieren und als String kopieren) und die Adresse des EIP ausAufgabe 1.3 als Parameter fur ”jmpesp” um ”gets exploit.c” anzupassen. Sollten siealles korrekt durchgefuhrt und kompiliert haben, sollte das Expoit die Programm-ausfuhrung umleiten.Dokumentieren sie ihren Jumpcode und ihre anderen Werte. Was konnten sie nachdem Ausfuhren beobachten?

Aufgabe 3.1

Benutzen sie nun das Fuzzer Programm

C:\BO\Aufgaben\3\test.exe

um das Programm Winamp auf die benotigte Puffergroße zu testen. Der Aufruf-syntax ist dabei wie folgt:

C:\BO\Aufgaben\3\test.exe <PUFFERGROßE>

Da Ollydbg im JIT Modus lauft, wird Ollydbg bei einem Ausnahmefehler den Pro-grammfluss unterbrechen. Daraufhin sollten sie sich in Ollydbg die EIP Adresseanschauen. Ist diese 41414141 (AAAA), haben sie die richtige Puffergroße getrof-fen.Hier ist jedoch eines zu beachten, wenn der von ihnen gewahlte Puffer zu klein ist,geschieht nichts (normaler Programmablauf). Ist der von ihnen gewahlte Puffer zu

21Der Taschenrechner von Windows (calc.exe) kann im wissenschaftlichen Modus mit hexadezi-malen Zahlen rechnen.

17

Page 20: Material zum Praktikumsversuch Buffer Overflows · Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem Umfang den Rahmen einer einzigen Vorlesung

groß, wird der Ausnahmefehler abgefangen (Ollydbg reagiert nicht). Das ”Fenster”,welches ihnen zur Verfugung steht, um den Puffer zu testen ist 7 Byte, wobei das4. Byte ahnlich reagiert wie als wenn der Puffer zu groß ist.Geben sie die Große des Puffers an, um den EIP zu uberschreiben.

Tipp: Die benotigte Puffergroße liegt zwischen 1015 und 1025 Byte.

Aufgabe 3.2

Das hier betroffene Modul ist ”in mp3.dll”, wenn sie sich die Adressierung in Ol-lydbg anschauen, werden sie bemerken das diese keine vorangestellte 0-Folge besitztund Adressen somit direkt ”anspringbar” sind (sie benotigen jmp esp nicht mehraus der ntdll.dll). Darum werden sie ”call esp (FFD4)” aus der in mp3.dll stattdem vorherigen EIP benutzen (das Vorgehen zur Findung der Adresse ist das Sel-be wie in Aufgabe 1.3, darum wird ihnen die Adresse vorgegeben). Des Weiterenmussten sie einen neuen Jumpcode erstellen, auch dieser wird ihnen vorgegeben.Schauen sie sich dessen Quelltext

C:\BO\Aufgaben\3\jumpcode3.asm

an und probieren sie einmal die ”BYTE” Parameter wegzulassen (danach mussensie den Quelltext neu kompilieren und mit XVI32 betrachten). Was bemerken sieund wie konnen sie sich das erklaren (sollten sie das nicht erklaren konnen, las-sen sie die Erklarung weg. Schildern sie jedoch ihre Beobachtung und warum derJumpcode nicht funktionieren wurde. Sie mussen mindestens eine Hochsprache derProgrammierung beherrschen (die Casting unterstutzt) um dieses Phanomen zu be-schreiben)?Modifizieren sie

C:\BO\Aufgaben\3\exploit.c

mit Hilfe der Puffergroße und kompilieren sie den Quelltext (Hinweis: Sie mussenBUF LEN und drei memcpy Funktionen verandern. Orientieren sie sich an den vor-herigen Exploits um die memcpy Funktionen anzugleichen).Was konnen sie beobachten, wenn sie das Exploit ausfuhren?

Tipp: Sollten sie etwas selbst nachprufen wollen (Sprungweiten o.a.), die Returnan-weisung der in mp3.dll, nach welcher der Ausnahmefehler eintritt, liegt bei Offset02005CB7. Außerdem besteht die Moglichkeit den ESP in Stack/Dump zu verfol-gen (Rechtsklick mit der Maus auf das Register), damit sollten sie in der Lage seindie Parameter auch selbst zu finden.

Aufgabe 3.3

Modifizieren sie nun die Datei

C:\BO\Aufgaben\3\Internetseite\attack.html

so, dass das local Exploit zu einem remote Exploit wird (Tipp: schauen sie sich denQuellcode genau an, es ist sehr einfach.).Beschreiben sie was sie geandert haben, und schlagen sie mind. eine Gegenmaßnah-me zum Schutz gegen diese Attacke vor.

18

Page 21: Material zum Praktikumsversuch Buffer Overflows · Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem Umfang den Rahmen einer einzigen Vorlesung

Aufgabe 3.4 (Optional sofern genugend Zeit vorhanden)

Nun wechseln sie die Betrachtungsweise. Sie arbeiten nun (erfolgreich) als Ange-stellter bzw. sind selbststandig in der ITS Branche. Sie haben erfahren, dass in derSoftware einer ihrer Auftraggeber eine Sicherheitslucke besteht (Winamp). Sie ha-ben bereits getestet, unter welchen Bedingungen das Programm absturzt (Aufgabe3.1).Benutzen sie die Testplayliste (sie liegt in dem Aufgabenverzeichnis (test.pls)) umdie zwei Funktionen (dies wussten sie unter realen Bedingungen nicht) herauszu-finden, die in dem Modul in mp3.dll (auch das mussten sie erst herausfinden) dieRucksprungadresse uberschreiben (eine Funktion uberschreibt nicht den EIP selbstsondern schreibt ohne Uberprufung eine beliebige Menge an Daten auf den Stack).

Das Vorgehen ist nun (eigentlich) wie folgt: sie gehen in das Modul in mp3.dll undlassen alle ”intermodularen calls” anzeigen (Rechtsklick in den Code → Search for→ All intermodular calls), dann setzen sie alle Aufrufe als Breakpoint und lassen dasProgramm ausfuhren (F9) (ausgenommen sie wissen welcher Call am wahrschein-lichsten ist, dann neben sie nur diese/n Call/s). Nach jedem Breakpoint untersuchensie den Stack (klicken sie in das Stackfenster und drucken sie Strg+B, danach gebensie als Suchstring 41414141 oder etwas anderes aus ihrem Puffer ein). Wird ihreSuchabfrage gefunden, geschieht das Uberschreiben vor dem jetzigen Breakpoint(sie mussen das Debuggen neu starten). Wurde der Suchwert nicht gefunden, lassensie das Programm weiter ausfuhren (F9).Bei jedem neuen Breakpoint mussen sie den Stack untersuchen. Sie sollten dabeiauch die Register beobachten (diese geben manchmal Hinweise darauf, wann etwaspassiert. Man benotigt dazu aber i.d.R. meist Erfahrung mit den API Calls vonWindows). Sie konnen also nun zahlen wie oft sie F9 drucken mussen, bis der Stackuberschrieben wird. Es ist jedoch so, dass sog. Threads22 erstellt werden und verur-sachen, dass es variiert wie oft sie weiter tracen mussen (dann konnen die Registerwiederum helfen).

Wenn sie herausgefunden haben, wann sie F9 nicht mehr drucken sollten, gehensie von dort an mit F8 weiter vor. Sollten sie dabei uber einen ”call” kommen,mussen sie den Stack wieder durchsuchen und diesen ”call” als Breakpoint setzen(Hinweis: Mit ”Minus” konnen sie einen Schritt zuruck gehen. Außerdem empfiehltes sich die anderen Breakpoints zu deaktivieren, um das Tracen zu beschleunigen),falls der Stack uberschrieben wurde. Nach einem Neustart des Debuggingprozesses,wird beim Ausfuhren der neue Breakpoint ausgefuhrt. Nun gehen sie mit F7 inden ”call” hinein und fahren mit F8 fort. Dies wiederholt sich solange, bis sie (inunserem Beispiel) in eine Schleife kommen. In dieser Schleife zeigt Ollydbg ihnenInformationen uber jeden Befehl innerhalb der Schleife an, sobald beim Tracen diePosition des Befehls erreicht wird. Somit konnen sie die Stackpositionen leicht fin-den und beobachten wie der Stack uberschrieben wird.

Da dies sehr zeitaufwandig ist, bekommen sie einige Breakpoints und API Calls(intermodular calls) vorgegeben: Die erste Routine wird leichter gefunden, wenn sienur Breakpoints auf

CreateFileA

setzen. Sie sollten dadurch auf die Adresse 02009836 stoßen (probieren sie trotz-dem einmal das Tracen aus und geben sie an, wie oft sie F9 drucken mussten). Wennsie nun den Stack durchsuchen, sollte dieser schon uberschrieben worden sein (einMal). Daher scrollen sie etwas nach oben, dort finden sie einen Funktionsprolog (s.

22Unterprozesse, die (hier) zur Verwaltung gestartet werden)

19

Page 22: Material zum Praktikumsversuch Buffer Overflows · Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem Umfang den Rahmen einer einzigen Vorlesung

Kapitel 4.1). Wenn sie dort alle Sprungreferenzen anzeigen lassen (Find ReferencesTo), sollten sie neun calls finden. Starten sie den Debugprozess neu und setzen siealle Calls der Form 02019xxx als Breakpoints. Sollten sie feststellen, dass auchbei diesen Breakpoints der Stack uberschrieben wurde, nehmen sie den ersten callVOR ihrem Breakpoint und testen sie dies erneut. Wiederholen sie dies, bis sieeinen Breakpoint gefunden haben andem folgendes gilt: vor dem call ist der Stackok, danach ist er uberschrieben. Tracen sie in diesen call und suchen sie dort ge-nauso weiter. So sollten sie die erste Funktion schnell finden.Wenn sie die erste Funktion gefunden haben, lassen sie das Programm bis zumnachsten Return ausfuhren und kehren sie zum Aufrufer zuruck. Danach lassen siedas Programm wieder bis zum Return ausfuhren und sollen so nahe der zweitenFunktion sein (sie konnen dies immer bis zu einem Return wiederholen und denStack uberprufen, diese Methode ist ahnlich der mit den Calls). Nun tracen sie wei-ter und beobachten wieder das Programm (nach jedem Call den Stack untersuchen,denn er wird zweimal uberschrieben). Sie sollten nun die zweite Funktion schnellfinden konnen.

Tipp: Offnen sie vor der Untersuchung einmal Winamp und laden sie die Testplay-liste. Danach schließen sie Winamp wieder. Damit mussen sie die Playliste nichtimmer neu laden, wenn sie die Untersuchung neu beginnen mussen.Tipp: Wenn sie eine Funktion gefunden haben, bei der sie vermuten das diese denStack uberscheibt, benutzen sie die Option ”Lock Stack” um den Stack an der jetzi-gen Position im Auge zu behalten (Rechtsklick mit der Maus auf das Stackfenster.Es ist dabei immernoch moglich sich andere Teile des Stacks anzuschauen (Scrol-len)).

Geben sie die beiden Offsets an, die sie herausgefunden haben. Beschreiben sieden von ihnen eingeschlagenen Weg unter der Benutzung von F7/F8/F9 und denvon ihnen verwendeten Breakpoints23. Damit konnen sie ihrem Auftraggeber einedetailierte Auflistung der von ihnen gefundenen Ergebnisse liefern (Hinweis: DieserFehler wurde ab Version 5.13 in Winamp behoben.).Sollten sie diese Aufgabe erfolgreich bewaltigt haben, haben sie eine gute Grundlageim Umgang mit Dateianalysen erworben. Interessierte Teilnehmer seien darauf hin-gewiesen, dass die letzte Aufgabe zum sog. Reverse Engineering gehort. Zu diesemThemenkomplex existieren sehr viele, sehr interessante Anwendungen.

23Es gibt sehr viele Moglichkeiten diese Aufgabe zu erfullen, die obige Vorgehensweise ist nurein Vorschlag.

20

Page 23: Material zum Praktikumsversuch Buffer Overflows · Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem Umfang den Rahmen einer einzigen Vorlesung

Literatur

[1] http://www.nds.rub.de/lehre/praktika/grundpraktikum its/index.html

[2] Kernighan, Ritchie, Programmieren in C, 2. Auflage, Hanser 1990.

[3] Hyde, R. The Art of Assembly Language Programming.http://webster.cs.ucr.edu/AoA/index.html

[4] Iczelion, Win32 Assembly Tutorials.http://win32assembly.online.fr/tutorials.html

[5] Werthmann, T. Survey on Buffer Overflow Attacks and Countermeasures,Horst Gortz Institute for IT-Security, Ruhr-University Bochum, Germany, Ju-ne 2006.

[6] Opatz, F. Buffer Overflows fur Jedermann, July/August 2005.

[7] Klein, T. Buffer Overflows und Format-String-Schwachstellen. Dpunkt Heidel-berg, 2004, ISBN 3-89864-192-9.

[8] Schwenk, J. Vorlesung Programmiersprachen.http://www.nds.rub.de/lehre/vorlesungen/programmiersprachen/index.html

[9] Ackermann, K. Programmieren in C - Eine Einfuhrung.http://www.uni-giessen.de/hrz/software/programmiersprachen/C/c teil1.html

21