Buffer Overflow Angriffe, Teil 2 - Ruhr

Transcription

Buffer Overflow Angriffe, Teil 2 - Ruhr
Grundpraktikum Netz- und Datensicherheit
Thema:
Buffer Overflow Angriffe, Teil 2
Lehrstuhl für Netz- und Datensicherheit
Ruhr-Universität Bochum
Versuchdurchführung: Raum ID 2/168
Betreuung: Florian Feldmann
Zusammengestellt von: Stefan Hoffmann & Hannes Oberender & Florian Bache & Patrick Meier
Stand: 8. Januar 2014
Version: 1.0
Inhaltsverzeichnis
Inhaltsverzeichnis
1 Vorwort
2
2 Hinweise
3
3 Einleitung
3
4 Grundlagen zum Shellcode-Programmieren
3
5 Start des Shellcodes
5.1 Parameter an Funktionen übergeben . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
4
6 Durchführung
6
7 Aufgabe 1
7.1 Aufgabe 1.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.2 Aufgabe 1.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.3 Aufgabe 1.3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
7
7
7
8 Aufgabe 2
8.1 Aufgabe
8.2 Aufgabe
8.3 Aufgabe
8.4 Aufgabe
8.5 Aufgabe
7
7
8
8
8
9
2.1
2.2
2.3
2.4
2.5
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
9 Fragen
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
11
1 Vorwort
Ziel des Praktikums soll sein, ihnen grundlegendes Wissen der Netz- und Datensicherheit praktisch
darzustellen. Neben dem didaktischen Erfolg soll der Spaß an Kryptographie, Internetsicherheit und
Programmierung im Vordergrund stehen. Trotzdem sollten sie den Aufwand dieser Veranstaltung nicht
unterschätzen! Sie werden in diesem Praktikum einer Auswahl an Themen begegnen, die in solch einem
Umfang den Rahmen einer einzigen Vorlesung überschreiten würden. Viel mehr wird ihnen Wissen
vermittelt, das Bestandteil einiger Grundlagenvorlesungen ist, oder Basis für vertiefende Vorlesungen
sein wird. Aus diesem Grund ist ihre Vorbereitung entscheidend für den Erfolg des Praktikums. Das
Studium der angegebenen Literaturreferenzen ist Voraussetzung für einen erfolgreichen Praktikumsversuch. Durch das Studium der Referenzen eignen sie sich theoretisches Wissen an, das Grundlage für
die Durchführung eines Versuchs ist und welches anschließend in einem Versuch praktisch untermauert werden soll. Die Aufgabe eines Betreuers ist somit nicht die Vermittlung des Grundlagenwissens,
sondern die Unterstützung bei der Durchführung ihres Versuchs. Vor Beginn eines Versuchs wird in einem Vortestat überprüft, ob sie die Referenzen ausreichend studiert haben. Damit wird sichergestellt,
dass sie in der vorgegeben Zeit die gestellten Aufgaben lösen können. Sollte vom Betreuer festgestellt
werden, dass sie nachweislich nicht vorbereitet sind, werden sie von dem Versuch ausgeschlossen und
müssen zu einem Nachholtermin erscheinen. Ihr Ziel sollte es demnach sein, das Testat auf den direkten
Weg zu erhalten.
Grundpraktikum NDS - Buffer Overflows 2
2
8. Januar 2014
2 Hinweise
2 Hinweise
Lesen sie sich zuerst das Grundlagenkapitel durch. Recherchieren sie bei Unklarheiten im Internet,
diskutieren sie mit Kommilitonen oder kontaktieren sie bei schwerwiegenden Problemen ihren Betreuer. Nehmen sie bei ihrer Recherche die angegebenen Quellen zur Hilfe, und versuchen sie sich an den
Hilfsfragen zu orientieren. Sie sollten unter allen Umständen auch Versuchen die Aufgaben so weit
wie möglich zu bearbeiten. Es ist ebenfalls möglich die Aufgaben vollständig in Heimarbeit zu lösen,
sofern ihnen alle Materialien zur Verfügung stehen. Ihre Lösungen werden vom Betreuer während
des Praktikums kontrolliert und bei nachweislich selbstständiger Erarbeitung erhalten sie vorab das
Testat. Nach einem Versuch muss jede Gruppe ein Protokoll anfertigen, in dem die Herleitung, die
Lösung der Aufgaben, und vor allem deren Begründung unter Ausnutzung des gesammelten Wissens
erörtert werden. Bei der Begründung können Zeichnungen helfen! Das Protokoll kann wahlweise in
deutscher oder englischer Sprache erstellt werden. Es sollte den orthographischen und grammatischen
Anforderungen der Sprache genügen. Sie haben bis zu einer Woche Zeit, um ihr computergefertigtes
Protokoll in ausgedruckter Form beim Betreuer abzugeben, ansonsten erhalten sie ihr Endtestat nicht.
Sollte ihre schriftliche Ausarbeitung nicht den Hinweisen in [1] genügen, so ist dies ein Grund ihnen
kein Testat zu erteilen. Bei offenen Fragen richten sie sich immer an den jeweiligen Betreuer! Viel
Spaß! Grundpraktikum
3 Einleitung
Der Versuch Buffer-Overflow 2 baut auf das erlernte Wissen aus Buffer-Overflow 1 auf. Alle Informationen aus Teil 1 sollten verstanden worden sein, sonst ist ein nochmaliges durchgehen Dieser
empfehlenswert.
In diesem Versuch beschäftigen wir uns zum einen mit Shellcode Programmierung, sowie des praktischen Einsatzes eines Exploits in einer realen Anwendung namens WinAmp.
4 Grundlagen zum Shellcode-Programmieren
Linux bietet, im Gegensatz zu Windows, eine direkte Verbindung zum Kernel über das int 0x80
Interface. Bei Windows hingegen gibt es dieses Interface nicht. Um hier mit dem System zu kommunizieren muss die Adresse der Funktion ,die wir ausführen wollen, aus einer DLL geladen werden. Das
heißt jedoch das die Adresse unserer gesuchten Funktion von Windows Version zu Windows Version
verschieden ist. Wohingegen die int 0x80 Systemaufrufe bei Linux konstant bleiben.
Es gibt 2 Möglichkeiten wie man Funktionen in einer DLL ausführen kann.
• Statischer Ansatz: Hierbei werden die Adressen der Funktionen die man benötigt Hardcoded
in den Shellcode eingetragen.
Der Vorteil ist die geringere Größe des Shellcodes und die Einfachheit beim Programmieren.
Der Nachteil ist das diese Art Shellcode nur für ein bestimmtes Betriebssystem mit jeweiligen
Servicepack funktioniert, da man erwartet das die Funktionen auch an der Stelle liegen.
• Dynamischer Ansatz: Bei diesem werden die Adressen der Funktionen durch den Shellcode
ermittelt und dann ausgeführt.
Vorteil dabei ist natürlich das man den Shellcode für mehrere Betriebssysteme nutzen kann.
Der Nachteil ist, dass hierbei die Größe des Codes deutlich zu nimmt.
Grundpraktikum NDS - Buffer Overflows 2
3
8. Januar 2014
5 Start des Shellcodes
In diesem Versuch benutzen wir einen Dynamisch-Statischen Ansatz. Das heißt wir werden dynamisch
DLLs und ihre Funktionen laden, aber die Funktionen um dies zu tun werden statisch sein (die sei an
dieser Stelle erst mal so hinzunehmen, im weiteren Verlauf folgt ein Beispiel). Der Grund liegt an der
Komplexität des Versuchs, sollte es zu einem rein dynamischen Verhalten kommen.
5 Start des Shellcodes
Um etwas in Windows auszuführen müssen wir Funktionen in DLLs nutzen. Dazu müssen diese DLLs
als Module geladen sein. Die einzige DLL von der wir von vornherein sicher sein können das sie
geladen ist, ist Kernel32.dll . Diese liefert den größten Teil der Win32 Grund-API-Funktionen, wie
Speichermanagement oder Prozess- und Thread-Erstellung usw.[8].
Die für uns wichtigen Funktionen darin sind:
• LoadLibraryA zum laden von anderen DLLs
• GetProcAddress um die Adresse von anderen Funktionen zu finden
• ExitProcess um Prozesse sauber zu beenden und keinen Absturz herbei zu führen
• WinExec um ein Programm zu starten
Um diese Funktionen zu nutzen, benötigt man die Adressen dieser. Dafür steht ihnen das Programm
arwin zur Verfügung. Das Programm kann aus der Konsole wie folgt aufgerufen werden:
arwin DLL FUNKTION
Dabei wird für den Parameter DLL die DLL eingetragen und für FUNKTION die Funktion. Ein
Beispiel Aufruf wäre:
arwin Kernel32.dll ExitProcess
Die Rückgabe ist eine Adresse in Hex-Format zum Beispiel 0x7c80a4b2
Um nun Shellcode zu schreiben benötigen wir Assembler-Code, der Anfang unseres Assembler-Files
sollte wie folgt aussehen:
[SECTION .text]
; set the code to be 32-bit
BITS 32
global _start
_start:
nach start: kann mit der Programmierung begonnen werden.
5.1 Parameter an Funktionen übergeben
Viele Funktionen erwarten Parameter, doch wie werden diese übergeben. Wie dies Funktioniert wird
am folgenden Beispiel erläutert[2].
Grundpraktikum NDS - Buffer Overflows 2
4
8. Januar 2014
5 Start des Shellcodes
[Section .text]
BITS 32
global _start
_start:
1
xor eax,eax ;nimmt Rückgabewert auf
2
xor ebx,ebx ; speichert String-Pointer
3
xor edx,edx ;speichert NULL
4
5
jmp short Befehl
6 BefehlReturn:
7
pop ebx
8
mov [ebx + 40], dl
9
xor eax,eax
10
push eax ;push 0 auf den Stack (2. Parameter)
11
push ebx ;push the command string onto the stack (1. Parameter)
12
mov ebx,0x7c8615b5
13
call ebx ;call WinExec(path,showcode)
14
xor eax,eax
15
push eax
16
mov ebx, 0x7c81ca82
17
call ebx ;call ExitProcess(0)
18 Befehl:
19
call BefehlReturn
20
db "cmd.exe /c net user PSUser PSPasswd /ADDN"
Die Zahlen vor den Codezeilen gehören nicht zum Code. Sie geben nur die Codezeile an, zum besseren
Verständnis.
1. In den Zeilen 1-3 werden die Register gelöscht, dies geschieht über xor um Null Bytes zu verhindern.
2. In der Zeile 5 wird ein Sprung zur Zeile 18 veranlasst
3. Zeile 19 ruft die Funktion in Zeile 6 auf, daraufhin wird Zeile 20 als Rücksprungadresse auf den
Stack gespeichert. Diese Rücksprungadresse ist der Pointer auf unseren Text
4. Zeile 7 holt die eben gespeicherte Rücksprungadresse vom Stack
5. Zeile 8 hier wird das Null-Byte anstelle des N gesetzt, die Zahl 40 gibt dabei die Position an,
nach welcher das Null-Byte gesetzt werden soll. Hierbei muss man wissen das EDX 32 Bit groß
ist, DX 16 Bit und DL das Low Byte von DX ist und DH das High-Byte von DX. Deswegen
wird hier ein Null-Byte gesetzt
6. in Zeile 10 übergeben wir den 2 Parameter der Funktion WinExec hier 0, da die cmd.exe ohne
Pfadangabe gestartet werden kann.
7. Zeile 11 hier wird unser String als Parameter 1 übergeben
8. in Zeile 12 wird die Adresse übergeben an der unsere gewünschte Funktion steht
9. Zeile 13 führt die Funktion aus dabei werden die letzten beiden Stackeinträge als Parameter
Grundpraktikum NDS - Buffer Overflows 2
5
8. Januar 2014
6 Durchführung
genutzt.
10. Zeile 14 hier wird eax wieder gelöscht, da eax oft den Rückgabewert von aufgerufenen Funktionen
enthält.
11. Zeile 15 hier wird 0 als Parameter für die Funktion ExitProcess aufgerufen.
12. Zeile 16 hier wird ebx mit der Adresse der Funktion von ExitProcess belegt
13. Zeile 17 ruft die Funktion an der Stelle ebx auf, also ExitProcess(0)
Wie man erkennen kann, können Text-Pointer per call-Aufruf in den Stack geladen werden. Dies kann
beliebig fortgeführt werden, um zum Beispiel noch andere Funktionen mit Parametern zu versorgen.
Achten sie darauf das die Parameter der Funktionen in umgekehrter Reihenfolge übergeben
werden und das EAX die Rückgabewerte von Funktionen enthält.
Hinweis: Falls mal ein Parameter eine 1 statt einer 0 verlangt, weisen Sie nicht direkt eine 1 hinzu,
sondern führen ein XOR mit anschließenden INC.
6 Durchführung
Für diese Versuch stehen Ihnen die folgenden Programme zur Verfügung.
• Cygwin darin enthalten gcc, nasm, hexedit, nano, vim
• Ollydbg
• xxd-shellcode.sh
• XVI32
• arwin
• shellcodetest.c
In Cygwin finden sie in ihrem Home-Verzeichnis den Ordner shellcode, darin befindet sich das Shellskript xxd-shellcode.sh . Dieser Ordner ist wiederum aus Windows unter C:/cygwin/home/shellcode
zu finden
Um Assembler-Dateien zu schreiben können sie auch in Cygwin nano oder vim nutzen. Um eine
Assembler Datei mit nasm zu kompilieren nutzen sie den folgenden Befehl
nasm -f bin
-o AUSGABE.BIN ASSEMBLER-FILE
Daraufhin erhalten sie die kompilierte binär Datei. Damit sie aus dieser nicht den Shellcode von Hand
abschreiben müssen, können sie das Programm xxd-shellcode nutzen. Als Parameter wird hier die per
nasm erzeugte Binärdatei angegeben.
./xxd-shellcode.sh AUSGABE.BIN
Sollten sie dennoch die Lust verspüren es von Hand zu machen, können sie das Programm Hexviewer
in Windows nutzen oder sie geben den folgenden Befehl in cygwin ein
hexdump -C AUSGABE.BIN
Mit shellcodetest.c können Sie ihren Shellcode testen.
Sollten Sie fragen zu den Programmen haben, konsultieren Sie das Internet oder Notfalls den Betreuer.
Grundpraktikum NDS - Buffer Overflows 2
6
8. Januar 2014
7 Aufgabe 1
7 Aufgabe 1
7.1 Aufgabe 1.1
Ermitteln Sie die Adressen für die folgenden Funktionen und notieren Sie diese.
• LoadLibraryA
• GetProcAddress
• ExitProcess
• WinExec
• MessageBoxA befindet sich in User32.dll
7.2 Aufgabe 1.2
Schreiben Sie ihren eigenen Shellcode der calc.exe aufruft. Nutzen Sie dafür WinExec. Die Funktion
sieht wie folgt aus WinExec(Path, Showcode). Der zweite Parameter dieser Funktion soll 0 sein.
Testen Sie den Shellcode mit shellcodetest.c.
7.3 Aufgabe 1.3
Schreiben Sie ihren eigenen Shellcode der eine MessageBox mit beliebiegen Text aufruft und die Buttons OK und CANCEL besitzt. Die Funktion MessageBoxA hat folgenden Aufruf[5]
MessageBoxA(windowhandle,message,title,buttons). Als windowhandle wird NULL benutzt. Gehen Sie wie folgt vor.
1. Rufen sie per LoadLibraryA(DLL) die DLL user32.dll auf, der in EAX gespeicherte Rückgabewert
der Funktion soll für GetProcessAddress genutzt werden
2. Rufen Sie GetProcessAddress(hmodule,funktionsname) auf, wobei hmodule der Rückgabewert
von LoadLibraryA ist und der Funktionsname MessageBoxA ist
3. Der Rückgabewert von GetProcessAddress ist die Adresse der Funktion MessageBoxA, rufen Sie
diese mit den entsprechenden Parameter auf
4. Rufen Sie anschließend ExitProcess(exitcode) aus um den Eltern-Prozess nicht abstürzen zu
lassen, hierbei ist exitcode der Rückgabewert von MessageBoxA ist.
Testen Sie ihren Shellcode mit shellcodetester.c.
8 Aufgabe 2
8.1 Aufgabe 2.1
Benutzen sie nun das Fuzzer Programm
C:\BO\Aufgaben\3\test.exe
um das Programm Winamp auf die benötigte Puffergröße zu testen. Der Aufrufsyntax ist dabei wie
folgt:
C:\BO\Aufgaben\3\test.exe <PUFFERGRÖßE>
Grundpraktikum NDS - Buffer Overflows 2
7
8. Januar 2014
8 Aufgabe 2
Da Ollydbg im JIT Modus läuft, wird Ollydbg bei einem Ausnahmefehler den Programmfluss unterbrechen. Daraufhin sollten sie sich in Ollydbg die EIP Adresse anschauen. Ist diese 41414141 (AAAA),
haben sie die richtige Puffergröße getroffen. Hier ist jedoch eines zu beachten, wenn der von ihnen
gewählte Puffer zu klein ist, geschieht nichts (normaler Programmablauf). Ist der von ihnen gewählte
Puffer zu groß, wird der Ausnahmefehler abgefangen (Ollydbg reagiert nicht). Das Fenster“, welches
”
ihnen zur Verfügung steht, um den Puffer zu testen ist 7 Byte, wobei das 4. Byte ähnlich reagiert wie
als wenn der Puffer zu groß ist. Geben sie die Größe des Puffers an, um den EIP zu überschreiben.
Tipp: Die benötigte Puffergröße liegt zwischen 1015 und 1025 Byte.
8.2 Aufgabe 2.2
Das hier betroffene Modul ist in mp3.dll“, wenn sie sich die Adressierung in Ollydbg anschauen, wer”
den sie bemerken das diese keine vorangestellte 0-Folge besitzt und Adressen somit direkt anspring”
bar“ sind (sie benötigen jmp esp nicht mehr aus der ntdll.dll). Darum werden sie call esp (FFD4)“
”
aus der in mp3.dll statt dem vorherigen EIP benutzen (das Vorgehen zur Findung der Adresse ist das
Selbe wie in Aufgabe 1.3, darum wird ihnen die Adresse vorgegeben). Des Weiteren müssten 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 müssen sie den Quelltext neu
”
kompilieren und mit XVI32 betrachten). Was bemerken sie und wie können sie sich das erklären (sollten
sie das nicht erklären können, lassen sie die Erklärung weg. Schildern sie jedoch ihre Beobachtung
und warum der Jumpcode nicht funktionieren würde. Sie müssen mindestens eine Hochsprache der
Programmierung beherrschen (die Casting unterstützt) um dieses Phänomen zu beschreiben)?
Modifizieren sie
C:\BO\Aufgaben\3\exploit.c
mit Hilfe der Puffergröße und kompilieren sie den Quelltext (Hinweis: Sie müssen BUF LEN
und drei memcpy Funktionen verändern. Orientieren sie sich an den vorherigen Exploits
um die memcpy Funktionen anzugleichen). Was können sie beobachten, wenn sie das Exploit
ausführen? Tipp: Sollten sie etwas selbst nachprüfen wollen (Sprungweiten o.ä.), die Returnanweisung
der in mp3.dll, nach welcher der Ausnahmefehler eintritt, liegt bei Offset 02005CB7. Außerdem besteht
die Möglichkeit den ESP in Stack/Dump zu verfolgen (Rechtsklick mit der Maus auf das Register),
damit sollten sie in der Lage sein die Parameter auch selbst zu finden.
8.3 Aufgabe 2.3
Fügen Sie in exploit.c statt den vorgegebenen Shellcode ihren eigenen ein. Dokumentieren Sie das
Ergebnis.
8.4 Aufgabe 2.4
Modifizieren sie nun die Datei
C:\BO\Aufgaben\3\Internetseite\attack.html
Grundpraktikum NDS - Buffer Overflows 2
8
8. Januar 2014
8 Aufgabe 2
so, dass das local Exploit zu einem remote Exploit wird (Tipp: schauen sie sich den Quellcode genau
an, es ist sehr einfach.).
Beschreiben sie was sie geändert haben, und schlagen sie mind. eine Gegenmaßnahme zum Schutz
gegen diese Attacke vor.
8.5 Aufgabe 2.5
Nun wechseln sie die Betrachtungsweise. Sie arbeiten nun (erfolgreich) als Angestellter bzw. sind
selbstständig in der ITS Branche. Sie haben erfahren, dass in der Software einer ihrer Auftraggeber
eine Sicherheitslücke besteht (Winamp). Sie haben bereits getestet, unter welchen Bedingungen das
Programm abstürzt (Aufgabe 2.1).
Benutzen sie die Testplayliste (sie liegt in dem Aufgabenverzeichnis (test.pls)) um die zwei Funktionen
(dies wüssten sie unter realen Bedingungen nicht) herauszufinden, die in dem Modul in mp3.dll (auch
das müssten sie erst herausfinden) die Rücksprungadresse überschreiben (eine Funktion überschreibt
nicht den EIP selbst sondern schreibt ohne überprüfung eine beliebige Menge an Daten auf den
Stack). Das Vorgehen ist nun (eigentlich) wie folgt: sie gehen in das Modul in mp3.dll und lassen
alle ”intermodularen calls” anzeigen (Rechtsklick in den Code ! Search for !All intermodular calls),
dann setzen sie alle Aufrufe als Breakpoint und lassen das Programm ausführen (F9) (ausgenommen
sie wissen welcher Call am wahrscheinlichsten ist, dann neben sie nur diese/n Call/s). Nach jedem
Breakpoint untersuchen sie den Stack (klicken sie in das Stackfenster und drücken sie Strg+B, danach
geben sie als Suchstring 41414141 oder etwas anderes aus ihrem Puffer ein). Wird ihre Suchabfrage
gefunden, geschieht das überschreiben vor dem jetzigen Breakpoint (sie müssen das Debuggen neu
starten). Wurde der Suchwert nicht gefunden, lassen sie das Programm weiter ausführen (F9).
Bei jedem neuen Breakpoint müssen sie den Stack untersuchen. Sie sollten dabei auch die Register
beobachten (diese geben manchmal Hinweise darauf, wann etwas passiert. Man benötigt dazu aber
i.d.R. meist Erfahrung mit den API Calls von Windows). Sie können also nun zählen wie oft sie F9
drücken müssen, bis der Stack überschrieben wird. Es ist jedoch so, dass sog. Threads erstellt werden
und verursachen, dass es variiert wie oft sie weiter tracen müssen (dann können die Register wiederum
helfen).
Wenn sie herausgefunden haben, wann sie F9 nicht mehr drücken sollten, gehen sie von dort an mit F8
weiter vor. Sollten sie dabei über einen call“ kommen, müssen sie den Stack wieder durchsuchen und
”
diesen call“ als Breakpoint setzen (Hinweis: Mit Minus“ können sie einen Schritt zurück gehen.
”
”
Außerdem empfiehlt es sich die anderen Breakpoints zu deaktivieren, um das Tracen zu beschleunigen), falls der Stack überschrieben wurde. Nach einem Neustart des Debuggingprozesses, wird beim
Ausführen der neue Breakpoint ausgeführt. Nun gehen sie mit F7 in den call“ hinein und fahren mit
”
F8 fort. Dies wiederholt sich solange, bis sie (in unserem Beispiel) in eine Schleife kommen. In dieser
Schleife zeigt Ollydbg ihnen Informationen über jeden Befehl innerhalb der Schleife an, sobald beim
Tracen die Position des Befehls erreicht wird. Somit können sie die Stackpositionen leicht finden und
beobachten wie der Stack überschrieben wird.
Da dies sehr zeitaufwändig ist, bekommen sie einige Breakpoints und API Calls (intermodular calls)
vorgegeben: Die erste Routine wird leichter gefunden, wenn sie nur Breakpoints auf
CreateFileA
setzen. Sie sollten dadurch auf die Adresse 02009836 stoßen (probieren sie trotzdem einmal das Tracen
aus und geben sie an, wie oft sie F9 drücken mussten). Wenn sie nun den Stack durchsuchen, sollte
dieser schon überschrieben worden sein (ein Mal). Daher scrollen sie etwas nach oben, dort finden sie
einen Funktionsprolog (s. Unterprozesse, die (hier) zur Verwaltung gestartet werden)
Wenn sie dort alle Sprungreferenzen anzeigen lassen (Find References To), sollten sie neun calls finden.
Grundpraktikum NDS - Buffer Overflows 2
9
8. Januar 2014
8 Aufgabe 2
Starten sie den Debugprozess neu und setzen sie alle Calls der Form 02019xxx als Breakpoints. Sollten
sie feststellen, dass auch bei diesen Breakpoints der Stack überschrieben wurde, nehmen sie den ersten
call VOR ihrem Breakpoint und testen sie dies erneut. Wiederholen sie dies, bis sie einen Breakpoint
gefunden haben andem folgendes gilt: vor dem call ist der Stack ok, danach ist er überschrieben.
Tracen sie in diesen call und suchen sie dort genauso weiter. So sollten sie die erste Funktion schnell
finden.
Wenn sie die erste Funktion gefunden haben, lassen sie das Programm bis zum nächsten Return
ausführen und kehren sie zum Aufrufer zurück. Danach lassen sie das Programm wieder bis zum
Return ausführen und sollen so nahe der zweiten Funktion sein (sie können dies immer bis zu einem
Return wiederholen und den Stack überprüfen, diese Methode ist ähnlich der mit den Calls). Nun
tracen sie weiter und beobachten wieder das Programm (nach jedem Call den Stack untersuchen,
denn er wird zweimal überschrieben). Sie sollten nun die zweite Funktion schnell finden können.
Tipp: öffnen sie vor der Untersuchung einmal Winamp und laden sie die Testplayliste. Danach schließen sie Winamp wieder. Damit müssen sie die Playliste nicht immer neu laden, wenn sie die Untersuchung neu beginnen müssen.
Tipp: Wenn sie eine Funktion gefunden haben, bei der sie vermuten das diese den Stack überscheibt,
benutzen sie die Option Lock Stack“ um den Stack an der jetzigen Position im Auge zu behalten
”
(Rechtsklick mit der Maus auf das Stackfenster. Es ist dabei immernoch möglich sich andere Teile
des Stacks anzuschauen (Scrollen)). Geben sie die beiden Offsets an, die sie herausgefunden haben.
Beschreiben sie den von ihnen eingeschlagenen Weg unter der Benutzung von F7/F8/F9 und den von
ihnen verwendeten Breakpoints. Damit können sie ihrem Auftraggeber eine detailierte Auflistung der
von ihnen gefundenen Ergebnisse liefern (Hinweis: Dieser Fehler wurde ab Version 5.13 in Winamp
behoben.).
Sollten sie diese Aufgabe erfolgreich bewältigt haben, haben sie eine gute Grundlage im Umgang mit
Dateianalysen erworben. Interessierte Teilnehmer seien darauf hingewiesen, dass die letzte Aufgabe
zum sog. Reverse Engineering gehört. Zu diesem Themenkomplex existieren sehr viele, sehr interessante Anwendungen.
Grundpraktikum NDS - Buffer Overflows 2
10
8. Januar 2014
9 Fragen
9 Fragen
1. Was versteht man unter Shellcode?
2. Wie funktioniert ein statischer Funktionsaufruf im Shellcode?
3. Wie funktioniert ein dynamischer Funktionsaufruf?
4. Worauf muss geachtet werden, damit Shellcode funktioniert?
5. Wie kann ich Text in meinem Shellcode nutzen?
6. Wie füge ich ein NULL-Byte ans Ende eines String an?
7. In welcher Reihenfolge werden Parameter an Funktionen im Shellcode übergeben und wie wird
dies gemacht?
Grundpraktikum NDS - Buffer Overflows 2
11
8. Januar 2014
Literatur
Literatur
[1] Jack Koziol et. al. The Shellcoders Handbook, 2004.
[2] Steve Hanna. Shellcoding for Linux and Windows Tutorial, 2004. http://www.vividmachines.
com/shellcode/shellcode.html.
[3] R. Hyde.
The art of assembly language programming.
baut/ArtOfAssembly/artofasm.html.
http://cs.smith.edu/ thie-
[4] Iczelion. Win32 assembly tutorials. http://win32assembly.programminghorizon.com/tutorials.html.
[5] Windows MSDN. Messagebox function. http://msdn.microsoft.com/en-us/library/windows/
desktop/ms645505%28v=vs.85%29.aspx.
[6] T. Werthmann. Survey on buffer overflow attacks and countermeasures, June 2006.
[7] Wikipedia. Shellcode. http://en.wikipedia.org/wiki/Shellcode.
[8] Wikipedia. Microsoft Windows library files, 2005. http://en.wikipedia.org/wiki/Microsoft_
Windows_library_files.
Grundpraktikum NDS - Buffer Overflows 2
12
8. Januar 2014