Studienarbeit Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista Fachbereich Informationstechnik Studiengang Softwaretechnik und Medieninformatik Semester: SWT6 Name: Johannes Hohenbichler Datum: 20.08.2008 Version: 1.03 Betreuer: Dominik Schoop
60
Embed
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Hierbei handelt es sich um eine Studienarbeit, deren Thema Stack- und Heap-Overflows unter Windows XP und Windows Vista ist. Zur Einführung ist ein umfangreiches Grundlagenkapitel enthalten, dass die generelle Funktionsweise von Overflows und Code-Injection unter Windows beschreibt. Eine Besonderheit sind hierbei die ausführlich auf Kompatibilität getesteten Demo-Programme mit Quellcode. Um Experimentierfreudigen einen möglichst leichten Einstieg zu geben, wird in den Quellcode-Beschreibungen auf Sicherheitsoptimierungen unterschiedlicher Compilerversionen eingegangen.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Studienarbeit
Stack- und Heap-Overflow-Schutz
bei
Windows XP und Windows Vista
Fachbereich Informationstechnik
Studiengang Softwaretechnik und Medieninformatik
Semester: SWT6
Name: Johannes Hohenbichler
Datum: 20.08.2008
Version: 1.03
Betreuer: Dominik Schoop
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Seite - 2 -
I Inhaltsverzeichnis
I Inhaltsverzeichnis ......................................................................................................................... 1-2
II Abbildungsverzeichnis .................................................................................................................. 1-4
III Abkürzungsverzeichnis ................................................................................................................. 1-5
IV Toolsverzeichnis ........................................................................................................................... 1-6
V Besondere Darstellungsformen .................................................................................................... 1-7
Hinweis: die Funktion dump() ist in der Include-Datei hacking.h definiert. Sie gibt von einer, per
ersten Parameter übergebenen Speicheradresse ausgehend, eine mit dem zweiten Parameter
definierte, Menge an Speicherinhalten, aus.
Das Programm übernimmt den ersten Parameter, den das Hauptprogramm übergeben bekommt und
kopiert ihn in der Funktion check_authentication() in einen Buffer, der als Zwischenspeicher
dient.
Stimmt das Passwort mit einem der gespeicherten Passwörter überein, so wird die Variable
auth_flag auf 1 gesetzt, was "wahr" entspricht.
Das Hauptprogramm nimmt den Rückgabewert der Funktion check_authentication() um
Zugang zu einem geschützten Bereich zu gewähren oder zu verweigern.
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Seite - 20 -
Dabei gibt es in dem Programmfluss keinen Else-Zweig, der im Falle, keiner Übereinstimmung, die die
Variable auth_flag auf 0 setzen würde. Der Programmierer hat diesen Fall durch das Initaialisieren
mit 0 abgedeckt.
Gegen dieses Vorgehen ist prinzipiell nichts einzuwenden. Das Problem mit dem obigen Code ist
jedoch, dass die Funktion strcpy() unabhängig von der Größe des Zielbuffers password_buffer
alle Zeichen bis zum ersten '\0' kopiert.
Diese Frage lässt sich mit Hilfe der Programmausgabe beantworten:
~~~ vorher ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dump: password_buffer
0012FF54: 46 46 46 46 46 46 46 46 | FFFFFFFF
dump: auth_flag
0012FF5C: 00 00 00 00 | ....
... gekürzt
Wie hier zu sehen ist liegt die Variable auth_flag unmittelbar nach dem Buffer password_buffer
im Speicher.
Das bedeutet, sollte es dem Benutzer möglich sein, dem Programm als ersten Parameter mehr als
acht Zeichen zu übergeben, so findet durch strcpy()ein Buffer Overflow in den Speicherbereich
der Variable auth_flag statt.
Startet man das Programm beispielsweise folgendermaßen:
auth_overflow.exe 12345678A
So erhält man folgende Ausgabe:
~~~ vorher ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dump: password_buffer
0012FF54: 46 46 46 46 46 46 46 46 | FFFFFFFF
dump: auth_flag);
0012FF5C: 00 00 00 00 | ....
~~~ nachher ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dump: password_buffer
0012FF54: 31 32 33 34 35 36 37 38 | 12345678
dump: auth_flag);
0012FF5C: 41 00 00 00 | A...
-=-=-=-=-=-=-=-=-=-=-=-=-=-
Access Granted.
-=-=-=-=-=-=-=-=-=-=-=-=-=-
Wie zu sehen ist, hat der Benutzer mittels "12345678" acht Zeichen übergeben und noch ein
zusätzliches 'A' angehängt.
Wie in der Abbildung 3-2 zu sehen ist, wird das 'A' an die Speicheradresse 0x0012FF5C geschrieben.
Der Rückgabewert der Funktion check_authentication() ist als int deklariert und wird durch
das Programm als wahr oder falsch interpretiert. Da in der Programmiersprache c alle Werte ungleich
0 dem Wert "Wahr" entsprechen, wird im Falle eines Overflows der Zugang zum geschützten Bereich
gewährt.
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Seite - 21 -
F F 0 00FF 0
password_buffer auth_flag
0x0012FF54 0x0012FF5C
F FFF
1 4 0 0A32 05 876
Overflowrichtung
1. Vorher
3. Nachher
2. strcyp()
Abbildung 3-2: Buffer Overflow von password_buffer in auth_flag
Dieses Beispiel zeigt eindrucksvoll, wie bereits ein einziges Zeichen an der richtigen Stelle genügen
kann, um den Ablauf eines Programms wesentlich zu beeinflussen.
Hinweis: Werden in diesem Programm mehr wie zwölf Zeichen übergeben, so stürzt das Programm
ab, da Informationen auf dem Stack überschrieben werden, die für den weiteren Programmablauf
benötigt werden. Abgesehen von Programmabstürzen, bietet diese Möglichkeit der Manipulation
von Werten, einen interessanten Ansatzpunkt für weitere Angriffsmöglichkeiten, auf die in den
folgenden Abschnitten eingegangen wird.
Bei dem zuletzt vorgestellten Overflow, ist außerdem zu bedenken, dass nicht nur Zahlenwerte und
Strings auf diese Weise manipuliert werden können. Es ist ebenso möglich Funktionspointer zu
überschreiben. Auf diese Weise kann wahlfrei, vorhandener, oder auch eingeschleuster
Programmcode ausgeführt werden.
Damit kommt dieses Grundagekapitel zu den "nützlicheren" Angriffsmöglichkeiten mittels Buffer
Overflows: Dem Ausführen von beliebigem Code.
3.1.3 Ausführen von beliebigem Code
Um auf einem Zielsystem beliebigen Code auszuführen sind prinzipiell immer zwei Schritte nötig
1. Den auszuführenden Code in den Arbeitsspeicher des Zielsystems einschleusen
2. Eine Möglichkeit finden den eingeschleusten Code ausführen zu lassen
Der erste Punkt lässt sich, ähnlich wie im Beispiel des letzten Abschnitts, mittels Programmparameter
erreichen.
Der zweite Punkt wird meistens durch das Manipulieren eins Funktionspointers erreicht. Dazu
können vom Programmierer selbst angelegte Funktionspointer verwendet werden, oder aber auch
auf dem Stack liegende Rücksprungadressen. [ 5 ]
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Seite - 22 -
Da die wirkliche Herausforderung mehr beim Ausführen, als beim Einschleusen liegt, werden in den
restlichen Abschnitten dieses Kapitels einige Möglichkeiten vorgestellt, um den Code zur Ausführung
zu bringen.
3.1.4 Klassische Stack-basierende Angriffe
Stack-basierende Angriffe verfahren normaler weise streng nach dem bereits vorgestellten Schema:
1. Den auszuführenden Code in Arbeitsspeicher des Zielsystems einschleusen
2. Eine Möglichkeit finden den gespeicherten Code ausführen zu lassen
Eine Möglichkeit den Code einzuschleusen haben wir bereits kennen gelernt: Die strcpy()-Funktion.
Kommen wir also zu Punkt zwei: Dem Starten des eingeschleusten Codes.
Bei klassischen Stack-basierenden Angriffen erfolgt das Starten des Codes durch das Manipulieren,
der auf dem Stack gespeicherten Rücksprung-Adresse(RET). Betrachtet man die in Abbildung 3-3
dargestellte Speicherbelegung, so stellt man fest, dass RET an einer höheren Adresse im Speicher
liegt als die lokalen Variablen.
Beispielhaftes
Stackframe
Wa
ch
stu
msrich
tun
g
Gespeicherte Register der
aufgerufenen Funktion
Lokale Variablen
Stack Frame Pointer (SFP)
Return Adresse (RET)
Parameter
0000000h
(Kleine Adressen)
FFFFFFFFh
(Große Adressen)
Ove
rflo
wrich
tun
g
Abbildung 3-3: Beispielhaftes Stackframe unter Windows allgemein
Da lokal angelegte String-Arrays (Buffer) nichts weiter sind als die in Abbildung 3-3 dargestellten
lokalen Variablen, ist es möglich, mit einer ausreichend großen Eingabe die Return-Adresse zu
überschreiben.
Damit der nächste Schritt, das Bestimmen der gewünschten Rücksprungadresse, einfacher ist, wird
als Füllmenge (um RET zu erreichen) ein spezieller Assembler-Befehl verwendet: ein NOP. NOP steht
für No OPeration und hat als einzige Aufgabe einen Maschinenzyklus zu verbrauchen. Danach führt
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Seite - 23 -
die CPU die Befehlsverarbeitung mit dem darauf folgenden Befehl fort. Typischer Weise werden an
dieser Stelle einige NOPs aufeinander folgen und bilden so einen NOP-Sled2.
Um nun den eingeschleusten Code ausführen zu lassen, muss RET auf den ersten eingeschleusten
Befehl zeigen. Wenn ein NOP-Sled verwendet wird, reicht es an dieser Stelle aus, einen beliebigen
Punkt auf dem NOP-Sled zu treffen. Das ist besonders hilfreich, weil der Compiler mit dem das
verwundbare Programm übersetzt wird möglicher Weise einige Optimierungen durchführt, die die
exakte Positionsbestimmung des ersten Befehls erschweren können. Aus demselben Grund ist es
üblich die gewünschte Return-Adresse mehrfach zu wiederholen.
Besondere Aufmerksamkeit muss man der Ausrichtung der eingeschleusten Return-Adresse widmen.
Das bedeutet man muss darauf achten, dass das erste Byte der selbst geschriebenen Return-Adresse
auch wirklich über das erste Byte der alten Return-Adresse geschrieben wird. Ohne Verwendung
eines Debuggers, lässt sich die korrekte Ausrichtung am einfachsten durch Probieren finden. Dabei
sollten maximal vier Versuche nötig sein, da eine Adresse bei 32-Bit-Systemen nur 4 Byte groß ist und
es somit nur vier Möglichkeiten gibt.
Die absolute Adresse des Puffers wird meist mittels eines Debuggers ermittelt und auf x86-Systemen
in Little-Endian-Anordnung eingebgeben. Interessant hierbei ist auch, dass der Stack eines Prozesses
immer an derselben Adresse beginnt, was bedeutet, dass auch hier Probieren zum Ziel führen kann.
Alternativ können zur Positionsbestimmung von Buffern auch Formatstring-Verwundbarkeit
verwendet werden [ 5 ] . Auf Formatstrings wird in dieser Arbeit jedoch nicht eingegangen, weil sie
nicht Teil des Themas "Buffer-Overflows" sind.
Insgesamt wird dem auszunutzenden Programm die in Abbildung 3-4 dargestellte Kombination
übergeben. Diese Kombination aus NOP-Sled, Payload3 und widerholter Return-Adresse, wird häufig
als Angriffsvektor bezeichnet.
NOP-sledRET
(mehrfach wiederholt)Payload
Abbildung 3-4: Angriffsvektor
Bleibt noch zu erwähnen, dass die Speichermenge die für den Payload zur Verfügung steht, durch die
Position der Return-Adresse begrenzt ist. Dieses Problem lässt sich aber durch einen relativen
Sprung, nach den Speicherbereich mit der Return-Adresse umgehen. [ 10 ]
2 NOP-Sled/NOP-Sledge: Übersetzt: NOP-Schlitten. Das bedeutet, eine Folge von NOPs führen direkt, ohne jede weitere
Funktion, zu dem nächsten „richtigen“ Maschinenbefehl. Beispielsweise dem ersten Befehl des Sehellcodes.
3 Der Payload/Shellcode besteht aus Maschinencode. Er ist der Teil des einzuschleusenden Codes, der die eigentliche
Funktionalität beinhaltet. Häufig werden die Begriffe Payload und Shellcode als Synonym verwendet. Details zu Shellcode werden in dem Kapitel 3.2 behandelt
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Seite - 24 -
Beispiel: stack-overflow.c im Quellcode-Ordner "Kapitel-3-1-4_stack-overflow"
Eine Variante des Programms auth_overflow.c ist unter dem Namen stack-overflow.c Quellcode-
Archiv zu finden. Dieses Programm bekommt seine Eingabe dabei nicht als Parameter, sondern liest
von einer Datei. Außerdem wird nicht die Funktion strcpy() verwendet, sondern die Funktion
memcpy(). Für diese Modifikationen gibt es zwei Gründe:
1. Mit der Windows-Eingabeaufforderung ist es nicht ohne weiteres möglich einem Programm,
per Parameter Zeichen zu übergeben, die nicht "druckbar" sind. Da das auf die meisten
Maschinenbefehle zutrifft, ist ein einfaches Einschleusen von Code über die Kommandozeile
nicht möglich. Abhilfe würde an dieser Stelle das Programm cat4 schaffen mit dem man die
Eingabe an das Programm umleiten kann. Cat ist aber nicht Bestandteil von Windows. Zudem
besteht das Problem der Parameterübergabe mit nichtdruckbaren Zeichen auch in den
meisten Debuggern. Aus diesem Grund liest das Demo-Programm aus einer Datei.
2. Wie in dem Abschnitt 2.1 beschrieben, liegt der für das Programm selbst zur Verfügung
stehende Speicher im niederen Adressbereich. Deshalb ist die Wahrscheinlichkeit sehr hoch,
dass der Buffer in dem der eingeschleuste Code liegt in einem Adressbereich liegt, der mit
zwei führenden Nullen (0x00AABBCC) beginnt. Das bedeutet, dass strcpy() die
Speicheradresse nicht mehr kopiert. Es gibt eine Reihe von Möglichkeiten den
eingeschleusten Code trotz dieses strcpy()-Problems zur Ausführung zu bringen
(beispielsweise "return to libc"). Um das Beispiel einfach zu halten wird dieses Problem an
dieser Stelle durch die Verwendung von memcpy() umgangen.
Trotz dieser zwei Vereinfachungen, bleibt das demonstrierte Prinzip in allen Fällen gleich: Den
Angriffsvektor einschleusen und den Maschinencode zur Ausführung bringen.
Ein funktionierender Angriffsvektor zu dem Programm stack-overflow.c ist ebenfalls im Quellcode-
Archiv zu finden. Dabei wird der Angriffsvektor mittels eines Perl-Skripts generiert. Der hierbei
verwendete Payload startet hierbei nichts weiter als den Windows-Taschenrechner clac.exe. Details
zur Erstellung von Payload folgt in dem Abschnitt 3.2.
4 cat ist ein Kommandozeilen-Tool aus der UNIX-Welt, mit dem sich unter anderem sehr einfach Eingaben aus einer Datei
lesen lassen. Das Tool gibt es auch für Windows
Tools-Hinweis
Die felxibelste Möglichkeit einen Angriffsvektor zu erstellen ist mit der Programmiersprach Perl.
Perl gibt es auch für Windows: Toolsverzeichnis IV
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Zu einem Buffer-Underrun kann es beispielsweise durch fehlerhafte Pointerarithmetik kommen
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Seite - 44 -
Überblick
Hinter dem Compilerswitch /GS verbirgt sich eine Funktion namens Buffer Security Check. Das
Haupt-Ziel dieser Funktion ist es, ein Überschreiben der Return-Adresse zu erkennen und das
Programm gegebenenfalls abzubrechen. Unter Linux gibt es mit StackGuard und ProPolice Lösungen,
die diesem Prinzip ebenfalls folgen.
Verfügbar ist diese Option seit Visual C++ 2002 und standardmäßig aktiviert ist die Option seit VS
2005[ 35 ] . Dabei gilt es allerdings zu beachten, dass sich die Implementierungsdetails und damit der
effektive Schutz, seit der ersten Version stark verändert haben. Im Folgenden wird nur auf die
Implementierung von VS 2005 eingegangen.
Seit Windows XP SP2 bzw. Windows Server 2003 ist die Option auch in den meisten Windows-
Binaries Standard. [ 32 ]
Funktionsweise
Programme, die mit der /GS Option kompiliert wurden, initialisieren nach dem Programmstart 4Byte
großes Master-Cookie, mit nicht vorhersagbarem Inhalt. Wird anschließend im Programmverlauf eine
geschützte Funktion aufgerufen, so wird innerhalb des Funktionsprologs eine Kopie des Master-
Cookies, wie auf Abbildung 4-3 zu sehen, auf dem Stack platziert. Wichtig ist hierbei vor allem die
Position des Cookies auf dem Stack: es liegt nach den potentiell verbundbaren lokalen Variablen und
vor der Return-Adresse. Hat die Funktion ihre Arbeit erledigt, so wird innerhalb des Funktionsepilogs
der momentane Wert, des auf dem Stack liegenden Cookies, mit dem Master-Cookie verglichen.
Sollte innerhalb der Funktion ein Buffer-Overflow vorgekommen sein, der bis zu dem Cookie reicht,
so wird das an dieser Stelle erkannt. Gegebenenfalls wird anschließend eine Ausnahme geworfen
und falls diese nicht entsprechend behandelt wird, wird das Programm wird mit einer Fehlermeldung
abgebrochen. [ 32 ]
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Seite - 45 -
Beispielhaftes
Stackframe
Wa
ch
stu
msrich
tun
g
0000000h
(Kleine Adressen)
FFFFFFFFh
(Große Adressen)
Ove
rflo
wrich
tun
g
Gespeicherte Register der
aufgerufenen Funktion
Sichere Parameter
Lokale Variablen
Exception Handler
Cookie
Stack Frame Pointer (SFP)
Return Adresse (RET)
Verwundbare Parameter
Abbildung 4-3: Beispielhaftes Stacklayout unter Verwendung von /GS bei VS 2005 [ 32 ]
Ebenfalls auf Abbildung 4-3 zu sehen, ist ein Feld "Sichere Parameter". Diese Neuerung gibt es seit
Visual Studio 2005 und soll verhindern, dass durch verwundbare Funktionsparameter nachfolgende
Speicherbereiche überschrieben werden können. Aktiviert wird diese Funktionalität ebenfalls mit der
/GS Option. Dabei stellen die sicheren Parameter nichts weiter dar, wie eine Kopie der Original-
Parameter. Während des Funktionsablaufs wird ausschließlich mit der Kopie (den sicheren
Parametern) gearbeitet. Aufgrund ihrer Position auf dem Stack, kann durch das weiter unten
liegende Cookie, ein von dem Parametern ausgehende Buffer-Overflow ebenfalls erkannt werden. [
32 ]
Schwachstellen
Die offensichtlichste und auch von Microsoft offiziell dokumentierte Schwachstelle, ist die Tatsache,
dass das Cookie nur unter bestimmten Umständen angelegt wird. Begründet wird dieses Verhalten
vor allem durch den Overhead, der durch das zusätzliche Verwalten und Prüfen der Cookies entsteht.
Das bedeute praktisch, dass ein Prüfung mittels Cookie, unter folgenden Umständen trotz aktivierter
/GS Option nicht erfolgt: [ 33 ] [ 32 ]
Bei Funktionen, die keinen Puffer enthalten
Wenn die /O Optionen (Code optimieren) nicht aktiviert werden
Bei Funktionen mit variabler Argumentliste (...)
Bei Funktionen, die mit naked (C++) markiert sind
Bei Funktionen, die Inlineassemblycode in der ersten Anweisung enthalten
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Seite - 46 -
Wenn ein Parameter nur auf eine Art und Weise verwendet wird, die im Falle eines
Pufferüberlaufs höchstwahrscheinlich nicht ausgenutzt werden kann
Passend zu dem letzten Punkt, wurde erst kürzlich herausgefunden, dass Puffer von einer Größe
kleiner wie 5 Byte offenbar als nicht gefährlich eingestuft werden und somit keinen Schutz durch
Cookies besitzen. [ 32 ]
Die meisten der obigen Fälle kann der Entwickler glücklicher weise eliminieren, indem er das Pragma
strict_gs_check(on) verwendet [ 4 ] . Allerdings sollte bei diesem Vorgehen der zusätzliche
Overhead und die damit einhergehenden Performanceeinbußen nicht außer Acht gelassen werden.
Falls der Angreifer die Möglichkeit hat, einen wahlfreien Schreibzugriff der Größe 4-Byte
auszuführen, bevor der Cookie-Check durchgeführt wird, kann versucht werden das Master-Cookie
mit einem bekannten Wert zu überschreiben. Da es in der aktuellen Implementierung nur 256
mögliche Positionen für das Cookie gibt und der Speicherbereich beschreibbar ist, bieten sich hier
Brute-Force-Angriffe an. [ 32 ] [ 36 ]
Die gefährlichste Schwachstelle bei der Verwendung von /GS ist die Tatsache, dass man wie in der
Abbildung 4-3 zu sehen ist, von einem verwundbaren Puffer ausgehend ohne weiteres den Exception
Handler überschreiben kann. Wie in dem Abschnitt 3.1.5 kann dabei der Exception Handler anstelle
der Return-Adresse überschrieben werden. Diese Methode funktioniert deshalb, weil die Funktion
zum Prüfen des Cookies erst am Ende der Funktion aufgerufen wird. Bis dies geschieht kann ein
Angreifer eine Exception auslösen und somit die Ausführung des manipulierten Exception Handler
veranlassen[ 36 ] . Dieser Angriffsmöglichkeit begegnet VS mit der Einführung von SafeSEH auf das
später noch eingegangen wird.
Effektiver Schutz
/GS für sich allein bringt kaum einen Mehrwert, da durch das Manipulieren des Exception Handlers
weiterhin alle Möglichkeiten offen stehen (Windows XP SP1, Windows Server 2003 SP0, Vista).
In Verbindung mit SafeSEH (siehe nächster Abschnitt) jedoch, ist Microsoft hier ein sehr effektiver
Schutzmechanismus gelungen, der den Stack für Angreifer zunehmend uninteressanter werden lässt.
Wie eine aktuelle Studie von Symantec [ 32 ] zu dem Thema zeit, werden jedoch bei weitem nicht
alle ausführbaren Windows-Dateien von Windows XP und Vista mit der /GS Option kompiliert. Dabei
existiert bereits eine Liste mit Dateien, die ohne /GS Kompiliert wurden und somit nicht geschützt
sind. Außerdem wurde von Symantec, zur Erstellung der besagten Liste, ein Programm entwickelt,
dass in der Lage ist zu erkennen, ob ein Binary mit /GS kompiliert wurde. Mit diesen Hilfsmitteln sind
Angriffe auf ungeschützte Dateien bereits vorprogrammiert.
Dateien die mit /GS kompiliert wurden und zusätzlich zu dem eigentlichen Buffer-Overflow die
Möglichkeit eines wahlfreien 4-Byte-Schreibzugriffs bieten, sind aus den oben beschriebenen Grund
anfällig für Brute-Force-Angriffe. [ 32 ] [ 36 ]
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Seite - 47 -
Nicht vergessen werden darf bei diesem Mechanismus der Schadensbegrenzung jedoch, dass hier
keinerlei Schutz vor Denial of Service Angriffen (DoS)13 geboten wird.
Abschließend sein noch darauf hingewiesen, dass die meisten Programme von Microsoft heutzutage
mit /GS und /SafeSEH kompiliert werden.
4.6.4 Sichere Ausnahmebehandlung (SafeSEH)
Option Beschreibung [ 37 ] Standard Windows
Binaries [ 4 ]
/SAFESEH[:NO]
(Linker)
Abbild verfügt über sichere Ausnahmehandler ? teilweise bei
Windows XP SP2,
Windows Server
2003 SP1,
Windows Vista
Überblick
Die aktuelle Version der Linker-Option /SafeSEH wurde mit Windows XP SP2 / Server 2003 SP1
eingeführt und ist nur für x86-Architekturen verfügbar[ 37 ] [ 4 ] . Ihr Ziel ist es, der im vorherigen
Abschnitt angesprochene Möglichkeit, zum Umgehen der Cookie-Prüfung zu begegnen.
Hinweis: Die genaue Geschichte des SAFESEH-Option ist etwas unklar: Eine Funktion zum validieren
gab es scheinbar bereits mit Server 2003 SP0, unklar ist allerdings welche Funktionalität wann und
mit welchem Umfang eingeführt wurde.
Funktionsweise
Ein mit der /SafeSEH Option kompiliertes Programm, hat in dem Header der ausführbaren Datei
(PE-Header) eine Liste "Sicherer Exception Handler". Wenn im Verlauf des Programms eine
Ausnahme ausgelöst wird, so prüft die Laufzeitumgebung, ob der auf dem Stack liegende, zur
Ausführung vorgesehene, Exception Handler in der besagten Liste steht. Sollte im Programmverlauf
der Exception Handler manipuliert worden sein, so wird dies von Windows erkannt und das
Programm wird abgebrochen. [ 4 ]
13
Ziel von Denial of Service Angriffen ist es, einen Service oder Dienst für den Nutzer unverfügbar zu machen.
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Seite - 48 -
Schwachstellen
Windows kann einen Exception Handler nur auf seine Richtigkeit überprüfen, wenn das Programm
mit der /SafeSEH Option kompiliert wurde. Dementsprechend sind alle DLLs und Programme von
Drittherstellern, die diese Option nicht verwenden weiterhin verwundbar. [ 14 ]
Effektiver Schutz
Zum Zeitpunkt der Analyse von Ben Nagy [ 14 ] im September 2006, waren keinerlei Möglichkeiten
bekannt, bei Binaries die mit /GS und /SafeSEH kompiliert wurden, die Return-Adresse oder den
Exception Handler als zuverlässigen Einstiegspunkt zu nutzen, um beliebigen Code zur Ausführung zu
bringen. [ 14 ]
Die Ansätze zum Angriff, auf die im letzten Abschnitt vorgestellten Cookies, bleiben jedoch weiterhin
bestehen und bieten einen Ansatzpunkt für weitergehende Analysen.
Auch bei diesem Mechanismus der Schadensbegrenzung darf nicht vergessen werden, dass hier
keinerlei Schutz vor Denial of Service Angriffen geboten wird.
4.6.5 Data Execution Prevention (DEP)
Option Beschreibung [ 37 ] Standard [ 37 ] Windows Binaries
/NXCOMPAT[:NO]
(Linker)
Gibt an, dass eine ausführbare Datei mit dem
Windows-Feature
Datenausführungsverhinderung kompatibel ist.
wenn die
Komponente
Vista erfordert
teilweise bei
Windows XP SP2,
Windows Server
2003 SP1,
Windows Vista
Überblick
Das Ziel von Hardware-DEP (Hardware-enforced DEP) ist es, Angreifern die Möglichkeit zu nehmen,
eingeschleusten Code von beliebigen Speichersegmenten ausgehend, ausführen zu können. Dabei ist
es bisher historisch bedingt gewesen, dass auf dem Stack und dem Heap liegende Daten ausgeführt
werden können, obwohl dies bei entsprechender Programmierung eigentlich nicht nötig ist.
Sollte bei Verwendung von Hardware-DEP dennoch versucht werden Code von einem als nicht
ausführbar markierten Bereich auszuführen, so wird eine Exception geworfen und falls diese nicht
abgefangen wird, wird das Programm beendet. [ 38 ]
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Seite - 49 -
Außer dem Hardware-DEP gibt es auch ein Software-DEP (Software-enforced DEP). Die
Namensgebung ist dabei nicht unbedingt logisch. Software-DEP wird nämlich bereits unter dem
Schlagwort SafeSEH geführt und hat es lediglich zum Ziel, Exception Handler auf Manipulationen hin
zu prüfen und das Programm gegebenenfalls abzubrechen (siehe Abschnitt 4.6.4). Software-DEP
kann in diesem Zusammenhang als eine Art Erweiterung zu Hardware-DEP gesehen werden. Für
Software-DEP ist keine spezielle Hardware-Unterstützung notwendig. [ 38 ] [ 39 ]
DEP ist seit Windows XP SP2 und Windows Server 2003 SP1 standardmäßig aktiviert. Hierbei sind
sowohl Software-DEP, als auch Hardware-DEP inbegriffen. [ 38 ]
Funktionsweise
Damit Hardware-DEP funktioniert wird ein Prozessor mit entsprechender Funktionalität benötigt. Bei
AMD heißt die entsprechende Funktion "no-execute" (NX), bei Intel "Execute Disable" (XD). [ 39 ]
Außerdem muss in der Datei Boot.ini bei 32-Bit-Systemen die Physical Address Extension (PAE)
aktiviert sein. Bei 64-Bit-Windows-Versionen ist PAE nicht nötig, weil die entsprechende
Funktionalität bereits nativ implementiert ist.
Software- und Hardware-DEP werden global mit dem Eintrag /noexecute=policy_level in der
Boot.ini konfiguriert. Dabei gibt es für policy_level folgende vier Einstellungsmöglichkeiten: [ 39 ]
1. OptIn: Ist unter Windows XP SP2 die Standardkonfiguration. Mit dieser Option gilt die
Datenausführungsverhinderung standardmäßig nur für Windows-Systembinärdateien. [ 39 ]
2. OptOut: Ist unter Windows 2003 Server SP1 [ 40 ] die Standardkonfiguration.
Datenausführungsverhinderung standardmäßig für alle Prozesse aktivieren. Es kann über
Registryeinträge, eine Liste mit Ausnahmen erstellt werden. [ 39 ]
3. AlwaysOn: Datenausführungsverhinderung gilt für das gesamte System. [ 39 ]
4. AlwaysOff: Für das gesamte System deaktivieren. [ 39 ]
Außer über die globalen Einstellungen, lässt sich DEP für DLLs auch mittels eins "Incompatible-Flags"
deaktivieren. [ 40 ]
Eine dauerhafte Aktivierung von DEP lässt sich mit der oben angegebenen Compiler-Option
/NXCOMPAT:YES erreichen [ 31 ] .
Im Betrieb wird bei Hardware-DEP für jede virtuelle Speicherseite ein Bit gesetzt, dass den
Speicherbereich entweder als ausführbar oder nicht ausführbar markiert. Wird im Betrieb von einem
als "nicht ausführbar" markierten Speicherbereich Code ausgeführt, so wird eine Exception geworfen
und falls sie nicht behandelt wird, wird der Prozess beendet.
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Seite - 50 -
Schwachstellen
Im Wesentlichen haben alle Schwachstellen, die mit DEP in Zusammenhang gebracht werden, mit
dem Tradeoff zwischen Sicherheit und Kompatibilität zu tun, den Microsoft bei der Implementierung
von Hardware-DEP gegangen ist.
So werden in der Regel weder der Internet Explorer 7, noch Java unter Windows Vista SP1 / XP SP2
mit Hardware-DEP betrieben. Dadurch gelang es Shane Macauly und Alexander Sotrov im Rahmen
des Wettbewerbs "Pwn to Own" im April 2008 mittels Flash und Java, Hardware-DEP zu umgehen
und beliebigen eingeschleusten Code auszuführen. Diese, in Flash begründete Einstiegsmöglichkeit,
wurde bereits 6 Tage nach dem Bekanntwerden von Adobe behoben. [ 41 ] [ 42 ]
Eine weitere Schwachstelle von Hardware-DEP wurde bereits im Jahr 2005 gefunden [ 40 ] . Bei
dieser Methode nutzt der Angreifer die Möglichkeit, das Kompatibility-Flag vom User-Mode aus
nachträglich ändern zu können. Dabei muss es dem Angreifer allerdings bereits möglich sein, im Stil
von return2libc eigenen Code ausführen zu können. Außerdem benötigt er die Adressen mehrerer
Speicherregionen, die gezielt manipuliert werden müssen. Aufgrund der letzen Anforderung sind
Angriffe dieser Art unter Windows Vista nicht mehr zuverlässig möglich, da dort ASLR zur Verfügung
steht. Microsoft hat auf die Veröffentlichung des Angriffs von Alexander Anisimov mit der Aussage
reagiert, man glaube nicht, dies sei eine Schachstelle, weil der Angreifer bereits Code zur Ausführung
bringen können muss. Abgesehen davon sei DEP auch primär zum Schutz vor Remote-Angriffen
entwickelt worden. [ 43 ] [ 44 ]
Effektiver Schutz
Die Implementierung von DEP scheint, in Hinsicht auf Remote-Angriffe, bisher keine Schwachstellen
zu haben. Wünschenswert wäre es dennoch, die oben angesprochenen Unzulänglichkeiten
schnellstmöglich zu korrigieren, um so potentiellen neuen Angriffen so schwer wie möglich zu
machen.
Eine wirkliche Gefahr stellt die Abwärtskompatibilität von DEP dar. Hier sind die Dritthersteller
gefragt: Sie sollten schnellstmöglich sicherstellen, dass alle Ihre Produkte mit aktivierten Hardware-
DEP uneingeschränkt lauffähig sind.
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Seite - 51 -
4.6.6 Address Space Layout Randomization (ASLR)
Option Beschreibung [ 37 ] Standard[ 4 ] Windows
Binaries [ 31 ]
/DYNAMICBASE[:NO]
(Linker)
Address Space Layout Randomization verfügbar und
Standard seit
VS 2005 SP1
Windows Vista
seit Beta2
Überblick
ASLR ist eine Funktionalität, die ausschließlich unter Windows Vista zur Verfügung steht und seit
Visual Studio 2005 SP1 auch für Eigenentwicklungen verfügbar ist. Das Ziel von ASLR ist es, Remote-
Angriffe, die es zum Ziel haben eigenen Code zur Ausführung zu bringen, so unzuverlässig wie
möglich zu machen. Ausschließen lässt sich diese Art von Angriff mit ASLR nicht, da das System
grundliegend auf einen begrenzten Grad an Wahrscheinlichkeit zurückgreift. [ 30 ]
Funktionsweise
Wird bei VS 2005 SP1 /DYNAMICBASE als Option beim Linken angegeben, so wird im PE-Header der
ausführbaren Datei ein Flag gesetzt, dass der Laufzeitumgebung mitteilt, dass ASLR verwendet
werden soll. [ 30 ]
Beim Bootvorgang von Windows Vista wird ein globales Image-Offset gewählt, von dem ausgehend
alle DLLs geladen werden. Dadurch ist es weiterhin effizient möglich, innerhalb aller Prozesse auf
eine gemeinsame Funktionalität einer DLL zuzugreifen. Außer dem globalen Image-Offset werden die
Basisadressen von der TXT-, DATA- und BSS-Segmente sowie der der DLLs, bei jedem Reboot neu
gewählt. Im Unterschied dazu, werden die Basisadressen des Stacks und der angelegten Heaps, bei
jedem Programmstart neu gewählt und sind für jeden Thread verschieden. Zusätzlich zu der
Basisadresse des Stacks, wird der Initial-Stack-Pointer dynamisch gewählt. [ 30 ]
Die Bestimmung der dynamischen Adressen erfolgt dabei durch Pseudo-Zufallszahlen. Die Menge der
möglichen Basisadressen ist dabei sehr unterschiedlich. So ist beispielsweise die Menge der
möglichen Adressen für den Initial Stack-Pointer auf einem 32-Bit-System 16.384, für die
Basisadresse des globalen Image-Offsets jedoch, existieren lediglich 256 Möglichkeiten. [ 30 ]
Nichts direkt mit dem eigentlichen ASLR der Linker-Option /DYNAMICBASE, hat die in Abschnitt 4.4
beschriebene dynamische Wahl des PEB zu tun. Dabei wird ebenfalls, bei jedem Programmstart, die
Adresse des PEB zufällig gewählt.
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Seite - 52 -
Schwachstellen
Die offensichtlichste Schwachstelle von ASLR existiert bei lokalen Angriffen. Dabei muss ein Angreifer
lediglich einen eigenen Prozess starten und mittels eines Debuggers die globale Basisadresse
ermitteln. Hierbei sollte allerdings berücksichtigt werden, dass ALSR primär zum Schutz vor Remote-
Angriffen entwickelt wurde und somit ist es in der Regel nicht möglich, einen eigenen Prozess zu
starten, von dem diese Information abgeleitet werden kann. [ 30 ]
Eine wirkliche Schwachstelle hingegen ist die Tatsache, dass ähnlich wie bei GS und SafeSEH, noch
nicht alle Windows Binaries mit der entsprechenden Option kompiliert wurden. Nach [ 4 ] sind bei
Windows Vista Ultimate 1676 von 1767 Dateien mit ASLR kompiliert.
Einer Analyse von Symantec zufolge[ 30 ] , bestehen in der Implementierung von ASLR noch einige
Verbesserungsmöglichkeiten. Im Wesentlichen wird dabei die Häufigkeitsverteilung der
Basisadressen als verbesserungswürdig eingestuft. Die größte Schwachstelle in diesem
Zusammenhang betrifft die Basisadresse des PEB, die in 25% aller Fälle identisch ist. Außerdem zeigt
sich bei der Verwendung von HeapAlloc() eine sehr deutliche Häufigkeitsverteilung. Ausgehend
von diesen Implementierungsschwächen bieten sich Brute-Force-Angriffe geradezu an. [ 30 ]
Effektiver Schutz
Wie bereits erwähnt ist der Schutz vor lokalen Angriffen durch ASLR nahezu null.
Die Möglichkeit zuverlässige Remote-Exploits zu schreiben, wurde durch ASLR signifikant verringert.
Dabei bleibt jedoch die Möglichkeit der Brute-Force Angriffe bestehen. Dies könnte vor allem durch
die oben erwähnten Schwächen in der Häufigkeitsverteilung interessant werden. Da sich Microsoft
dieser Problematik jedoch bewusst ist und dieses Problem selbst auf eine
Implementierungsschwäche zurückführt, kann auf eine baldige Beseitigung dieser Unzulänglichkeit
gehofft werden. [ 30 ]
Auch bei diesem Mechanismus der Schadensbegrenzung darf nicht vergessen werden, dass hier
keinerlei Schutz vor Denial of Service Angriffen geboten wird.
4.7 Abschließender Vergleich: XP gegenüber Vista
Wie sich der folgenden Tabelle entnehmen lässt, sind viele Neuerungen der jüngeren Vergangenheit
auch in Windows XP enthalten. Diese Neuerungen für sich haben die Schwierigkeit zuverlässige
Exploits zu schreiben, die auf Buffer-Overflows basieren, stark erhöht. Laut CVE-Statistik [ 1 ] gab es
für Windows XP im Jahr 2007 noch 28 veröffentliche Schwachstellen, die direkt auf Buffer-Overflows
zurückzuführen waren. Im Jahr 2008 ist es, bis zum Druckzeitpunkt dieser Arbeit im Juni 2008, noch
keine einzige solche Schwachstelle. [ 1 ]
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Seite - 53 -
Tabelle 1: Sicherheitsmechanismen in XP und Vista
Windows XP Windows Vista
UAC und Service Hardening Nein Ja
Patchguard Ja,
nur bei 64Bit
Ja,
nur bei 64Bit
PEB Randomization Seit SP2 Ja
SAL Ja,
bei entsprechender
Entwicklungsumgebung
Ja,
bei entsprechender
Entwicklungsumgebung
Stackoptimierungen(O2) Ja,
muss beim Kompilieren
aktiviert werden
Ja,
muss beim Kompilieren
aktiviert werden
SafeSEH Seit SP2,
muss beim Linken aktiviert
werden
Ja,
muss beim Linken aktiviert
werden
DEP Seit SP2,
muss beim Linken aktiviert
werden
Ja,
muss beim Linken aktiviert
werden
ASLR Nein Ja,
muss beim Linken aktiviert
werden
Weitere Neuerungen wie UAC und ASLR, die nur Windows Vista und seinen Folgeversionen zugänglich sind, haben den Sicherheitsstandard noch weiter erhöht, so dass Buffer-Overflows als Einfallstor zunehmend unwahrscheinlicher werden. Außerdem schränken sie den Spielraum des eingeschleusten Codes stark ein, was ebenfalls einen sicherheitstechnischen Mehrwert darstellt. Im Fazit folgt nun eine kurze Zusammenfassung und eine Bewertung der Gesamtmenge an Maßnahmen, die in Windows XP und Windows Vista zum Einsatz kommen.
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Seite - 54 -
5 Fazit
In den beiden ersten Kapiteln wurden einige traditionelle und einige neuere Angriffstechniken
vorgestellt, die auf Buffer-Overflows basieren und mit denen ein modernes Betriebssystem
heutzutage zurechtkommen muss. In dem letzten Kapitel wurden die Mechanismen vorgestellt, die
Windows Vista und frühere Versionen mitbringen, um sich gegen diese Gefahren zu wappnen. Dabei
ist es offensichtlich, dass Microsoft einen beachtlichen Entwicklungsaufwand investiert hat um den
Ruf des unsicheren "Blue-Screen-Windows" endgültig abzulegen.
Dabei sind neue Programmierpraktiken wie SAL entstanden, die den Entwicklern helfen Buffer-
Overflows erst gar nicht entstehen zu lassen und somit den wohl effektivsten Schutz gegen Buffer-
Overflows bietet. Sollten sich im Code von Drittherstellern, oder im Betriebssystem selbst dennoch
Buffer-Overflows finden, so wird der praktische Nutzen, durch die meisten in diesem Dokument
vorgestellten Mechanismen, auf Denial of Service Angriffe reduziert. Dies gilt allerdings nur, wenn die
gesamte Breite, an zur Verfügung stehenden Schutzmechanismen, verwendet wird. Das einfachste
Negativbeispiel ist ein Programm, das zwar mit /GS, aber nicht mit /SafeSEH kompiliert wurde. Hier
verwendet der Angreifer einfach den Exception Handler und nicht die Rücksprungadresse als
Einstiegspunkt.
Kritik und Lob zugleich verdient Windows Vista für seine Abwärtskompatibilität. So freut es
Dritthersteller, dass sie ihre Programme nicht aufwändig umschreiben müssen, um mit den neuen
Sicherheitsmechanismen kompatibel zu sein, denn sie bleiben einfach inkompatibel. Was den
Programmierer der Software freut, ist schlecht für die Gesamtsicherheit des Systems. Als
bekanntestes Negativbeispiel sei hier nochmals der Internet Explorer 7 genannt, der selbst heute
noch mit deaktivierten DEP das Tor zur Welt öffnet.
Sollte es einem Anwender gelingen, nur Programme zu betreiben, die alle zur Verfügung stehenden
Mechanismen verwenden, so betreibt er das mit Abstand sicherste Windows-System das es bisher
gab.
Dennoch ist "das sicherste" nicht gleichzusetzen mit "sicher". Dieser Tatsache ist sich auch Stephen
Toulouse (Senior Product Manager bei Microsoft Security Technology) bewusst, der sagt:
"Keins der Features aus Windows Vista, weder allein, noch zusammen, ist
kugelsicher. Dennoch erhöht sich der Schutz gegenüber Windows XP
signifikant" (Frei übersetzt nach [ 29 ] ).
Aus dieser richtigen, aber auch sehr unverfänglichen Aussage, lässt sich ablesen, wie schwer es ist,
den effektiven Schutz eines Betriebssystems zu beurteilen.
Um die gesamte Sicherheit von Windows Vista zu bewerten darf man nicht nur veröffentliche
Sicherheitslücken bewerten, sondern man muss auch Dienstleister, mit moralisch fragwürdiger
Motivation in seine Bewertung mit einbeziehen, die versprechen gegen Bezahlung funktionierende
Exploits zu liefern. Ebenso dürfen Hacker mit unterschiedlichen Idealen nicht vergessen werden, die
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Seite - 55 -
teilweise kein Interesse daran haben ihre "private Exploits" zu veröffentlichen, da Sie dadurch ihren
"Freiraum" verkleinern würden.
Auch wenn sich abschließend nicht sagen lässt "Windows Vista ist sicher", der Mehrwert den
Neuerungen wie UAC und ASLR gegenüber Windows XP bringen, ist unbestritten. Wer also vor der
Wahl steht XP oder Vista, dem sollte vom sicherheitstechnischen Standpunkt aus, auf jeden Fall zu
Vista geraten werden.
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Seite - 56 -
A Literaturverzeichnis
1. Statistics. [Online] National Vulnerability Database, 15. 7 2008. http://nvd.nist.gov/.
2. Mark E. Russinovich, David A. Solomon. Windows Internals. Redmond : Microsoft Corporation,
2005. ISBN 3-86063-977-3.
3. James C. Foster, Vitaly Osipov, Nish Bhalla, Niels Heinen. Buffer Overflow Attacks: Detect, Exploit,
Prevent. Rockland : Syngress Publishing, Inc., 2005. ISBN 1-932266-67-4.
4. Joel Scambray, Stuart McClure. Hacking Exposed Windows: Windows Security Secrets & Solutions,
Third Edition. s.l. : McGraw-Hill, 2008. ISBN 978-0-07-149426-7.
5. Ericson, Jon. HACKING: THE ART OF EXPLOITATION, 2ND EDITION. San Francisco : NO STARCH