Ausnutzung von CVE-2018-5093 in Firefox 56 und 57 – TEIL 1: Steuerung des Befehlszeigers - DEEP
Ausnutzung von CVE-2018-5093 in Firefox 56 und 57 – TEIL 1: Steuerung des Befehlszeigers
04 Juli 2022
Kontext
Ziel dieses Projekts ist es, während der Red-Team-Übung einen ersten Zugang zu erhalten, indem durch die Ausnutzung einer Sicherheitslücke eine Codeausführung erreicht wird.
Dieser erste Artikel beschreibt die ersten Schritte der Entwicklung des Exploits bezüglich der Schwachstelle CVE-2018-5093 und erklärt, wie man die Integer-Unterlauf-Schwachstelle von Firefox 56 und 57 ausnutzt, um den Befehlszeiger beim Öffnen einer speziell gestalteten Webseite zu steuern.
Die Entwicklung des Proof of Concept erfolgte unter Windows 10 in der Versionsumgebung 21H2 und mit Hilfe eines WINDBG-Debuggers.
Bisher wurde noch kein einziger Artikel mit einem funktionierenden Exploit veröffentlicht. Aus diesem Grund wurde zur Entwicklung dieses Exploits das Write-up von ExodusIntel genutzt.
Um diesen Artikel zu verstehen, müssen Sie über einige Kenntnisse in Bezug auf Assembler mit der Verwendung des Stacks und des Heaps sowie einige bekannte Techniken bei Browser Exploits wie Heap Spraying verfügen.
Analyse der Schwachstelle
Die Schwachstelle wurde im WebAssembly-Code in der xul.dll-Bibliothek gefunden und 2018 an Mozilla gemeldet. Seit 2020 ist diese Sicherheitslücke in Firefox 58 und 59 behoben.
In Abbildung 1 sehen Sie als Proof of Concept, wie Sie die Schwachstelle einfach auslösen können.
Figure 1 : Proof of concept
Diese Schwachstelle wird ausgelöst, wenn die get()-Funktion des Table-Objekts aufgerufen wird. Wenn die get()-Funktion aufgerufen wird, wird ein Aufruf der Funktion getImpl() ausgeführt. Allerdings beinhaltet die Funktion getImpl() eine Überprüfung des Index, der im Argument der Funktion get() eingegeben wurde. Die Funktion ToNonWrappingUint32() prüft, ob der Index zwischen 0 und table.length() – 1 liegt, wie in Abbildung 2. dargestellt.
Figure 2 : Unterlauf-Schwachstelle
Auslösen des Fehlers
Wie im obigen Screenshot dargestellt, lässt sich bei der Erstellung des Table-Objekts eine Tabellengröße von 0 mit der Anfangskomponente in Abbildung 1 angeben, sodass table.length() gleich 0 sein kann. Wenn table.length() gleich 0 ist, liegt der Wert table.length() – 1 bei -1, aber die Funktion ToNonWrappingUint32() hat den Argument-Typ „unsigned int 32“, also wird der Wert -1 zum Maximalwert von unsigned int 32. Dies ist ein Unterlauf, daher kann die Funktion den Wert des Index nicht überprüfen, und alle in 32 Bit kodierten Zahlen können als Index verwendet werden.
Ein signierter Integer mit 8 Bits, der gleich -1 ist, wird wie folgt binär dargestellt: 1111 1110.
Das Programm interpretiert dies also als den unsignierten Integer 254, was dem auf 8 Bit – 1 kodierten Maximalwert entspricht.
Umkehrung der betroffenen Komponente
Nach der Analyse mit GHIDRA ist der Assembler-Code, mit dem die Schwachstelle ausgenutzt werden kann, in Abbildung 3 zu sehen, da es sich um die Zeile handelt, die es erlaubt, das Objekt am Positionsindex abzurufen.
Figure 3 : Anfälliger Assembler-Code
Nach dieser Zeile können wir also einige Register kontrollieren und uns bewegen, wohin wir wollen. Aus diesem Grund sollten wir in der Lage sein, das EIP/RIP-Register zu kontrollieren, wenn wir einen Assembler-Befehl ausführen können, der einen Aufruf an ein von uns gesteuertes Register vornimmt.
Einige Funktionen verfügen über eine Anweisung, die es ermöglicht, ein Register aufzurufen. Nach einer tiefgreifenden Analyse haben wir herausgefunden, dass sich dieser Befehl in Funktion FUN_107bc8d6 befindet (siehe Abbildung 4).
Figure 4 : Zielfunktion
Über die Kontrolle einiger Register muss eine Kette von Aufrufen zum Auslösen der Funktion gefunden werden. Wir haben einen Weg gefunden, andere Funktionen zu verketten, wie hier dargestellt:
Figure 5 : Aufruf der Zielfunktion – unsere Kette
Steuerung des Befehlszeigers
Bei der Ausführung des JavaScript-Codes, der in Abbildung 1 als Proof of Concept dargestellt ist, sehen wir, dass das Programm versucht, ein Objekt an der Position 0x2000000 des Table-Objekts abzurufen. Mittels WINDBG können wir sehen, was passiert (siehe Abbildung 6).
Figure 6 : Zugriffsverletzung
In dieser Abbildung möchte das Programm ein Objekt an der Adresse 0x169a40b0 abrufen, das jedoch nicht existiert, weil die Position größer ist als die zugewiesene Tabellengröße.
Präzises Heap Spraying
Nun können wir durch einen präzisen Heap Spray eine gültige Adresse, die wir kontrollieren können, an die Stelle setzen, auf die zugegriffen wird, damit wir unser gefälschtes Objekt verwenden und einige nützliche Register steuern können.
Die präzise Heap-Spray-Payload wird auf der Grundlage des Artikels von Corelan[4] erstellt, in dem diese Technik demonstriert und gezeigt wird, wie man durch präzises Heap Spraying die unten dargestellte Payload erreicht.
Figure 7 : Präzise Heap-Spray-Payload
Mit dieser Technik werden wir den Heap mit der Adresse 0x10101010 sprayen. Wenn das Programm dann die Adresse des Objekts übernimmt, erhält es den Wert 0x10101010 (siehe Abbildung 8).
Figure 8 : Beschädigte Adresse
Mit dem präzisen Heap Spray enthält die Adresse 0x10101010 nur Nullbytes bis zur Adresse 0x10101090, wie in Abbildung 9 beabsichtigt und in Abbildung 10 dargestellt.
Figure 9 : Präziser Heap Spray mit Nullbytes an der Adresse 0x10101008 bis zur Adresse 0x101010A0
Figure 10 : Inhalt im Heap
Verkettung von Funktionsaufrufen
Nun wollen wir das Assembler-Programm bis zum Aufruf der Funktion FUN_1234294b ausführen.
Zu diesem Zweck müssen wir einige Adressen im präzisen Heap Spray modifizieren, um alle Kontrollen zu umgehen, die prüfen, ob das abgerufene Objekt ein gutes Format aufweist, d. h. ob das Objekt den in der Funktion getImpl() (siehe Abbildung 2) angeforderten Objekttyp hat, bevor der Aufruf der Zielfunktion erfolgt.
Um jedoch den Inhalt und den Ort der Daten zu identifizieren, werden wir Schritt für Schritt die Daten im Heap Spray mit WINDBG verändern, bis der Ausführungsfluss die Zielfunktion erreicht.
Wenn das Programm mit dem Debugger ausgeführt wird, kommt es zu einer Zugriffsverletzung (Abbildung 11), weil das Programm auf 0x00000008 zugreifen will, diese Adresse aber nicht existiert.
Figure 11 : Zugriffsverletzung
Das Programm versucht, auf diese Adresse zuzugreifen, weil an 0x10101018 0x00000000 vorhanden ist.
Figure 12 : ESI-Wert betroffen
Aus diesem Grund ändern wir den Heap Spray wie in Abbildung 13 dargestellt, um eine gute Adresse bei 0x10101018 zu haben, die wir kontrollieren können. Hier können wir die Adresse 0x10101040 wählen.
Figure 13 : Präziser Heap Spray mit einer Änderung
Anhand dieser Vorgehensweise nehmen wir weitere Änderungen am Heap Spray vor, um den Assembler-Code auszuführen, bis die Funktion FUN_1234294b aufgerufen wird.
So sieht unsere Heap-Spray-Payload jetzt aus:
Figure 14 : Präziser Heap Spray mit einigen Änderungen zur Umgehung aller Kontrollen
Nun haben wir Zugriff auf die Funktion FUN_1234294b und wollen die Funktion FUN_104e3000 aufrufen:
Figure 15 : Aufruf von FUN_104e3000
Leider springt das Programm, wie in Abbildung 17 zu sehen ist, beim schrittweisen Debuggen mit WINDBG zu 0x7a682a35, weil ESI gleich 0x00000000 ist. Springt das Programm aber zu dieser Adresse, führt es eine POP RET-Anweisung aus (Abbildung 16), wohingegen wir die Anweisungen in LAB_123429b2 in derselben Funktion ausführen wollen, d. h. wir wollen diesen Sprung vermeiden.
Figure 16 : LAB_123429b2-Funktion mit POP RET-Anweisungen
Figure 17 : Sprung in LAB_12342A35
Daher ändern wir den Wert an der Adresse 0x10101044, damit sich das ESI-Register von 0x00000000 unterscheidet, sodass verhindert wird, dass der Ausführungsfluss ungewollt springt.
Wie in Abbildung 18 zu sehen, möchte das Programm auf die Adresse 0x101ffff0 zugreifen, also müssen wir den Heap Spray wie in Abbildung 19 anpassen, um dies zu ermöglichen und den Wert 0x10101010 an 0x101ffff0 zu haben.
Figure 18 : Zugriff auf die Adresse 0x101ffff0
Figure 19 : Heap-Spray-Anpassung zur Kontrolle der 0x101ffff0-Adresse
Wenn wir nun den Heap mit unserem bevorzugten Debugger inspizieren, erhalten wir die im folgenden Screenshot dargestellten Daten, mit denen wir überprüfen können, ob unser Heap Spray korrekt repariert ist, da 101010101111111111 am Ende der Payload des präzisen Heap Sprays hinzugefügt wurde.
Figure 20 : Inhalt des Heap
Wir haben Zugriff auf die Funktion FUN_104e3000 und dann wird die Funktion FUN_104e33c0 aufgerufen – unsere Kette funktioniert nun!
Schließlich wird die Zielfunktion FUN_107bc8d6 aufgerufen und eine Zugriffsverletzung ausgelöst
Figure 21 : Zugriffsverletzung
Die Ursache für die obige Zugriffsverletzung wird dadurch ausgelöst, dass das Programm versucht, eine Funktion an der Adresse 0x00000010 aufzurufen.
Umsetzung der Steuerung des Befehlszeigers
Zum Abschluss muss diese Adresse durch eine andere ersetzt werden, die wir durch Anpassung der Payload kontrollieren können.
Für diese letzte Änderung (wirklich die letzte!) müssen wir den Adresswert 0x10101068 anpassen, da das EAX-Register an dieser Adresse enthält, was wir brauchen.
In Abbildung 22 ändern wir diesen Wert um 0x10101080, da wir wissen, dass 0x10101080 + 0x10 = 0x10101090 (EAX+0x10 Aufruf) ist, und haben 0x41414141 an dieser Adresse hinzugefügt, um den Wert 0x41414141 in unserem Befehlszeiger-Register zu erhalten.
Figure 22 : Endgültige präzise Heap-Spray-Payload
Abbildung 23 zeigt, dass der Befehlszeiger jetzt 0x41414141 entspricht, wir haben also erfolgreich die EIP mit unserem Wert 0x41414141 überschrieben.
Figure 23 : Steuerung des Befehlszeigers
Aus technischer Sicht können wir nun ausführen, was wir wollen, indem wir den Ausführungsfluss kontrollieren. Da es sich jedoch um eine reale Anwendung handelt, implementiert das Programm einige Schutzmechanismen wie ASLR, DEP/NX-Schutz usw.
Im zweiten Teil dieses Artikels wird erklärt, wie diese Anweisungen umgangen werden können, um eine Codeausführung zu erreichen.
Erstellt von
Cybersecurity Offensive Security TeamKontakt
Sie haben Fragen zu einem der Artikel? Sie brauchen Beratung, um die richtige Lösung für Ihre ICT-Probleme zu finden?
Einen Experten kontaktierenUnsere Experten beantworten Ihre Fragen
Sie haben Fragen zu einem der Artikel? Sie brauchen Beratung, um die richtige Lösung für Ihre ICT-Probleme zu finden?
Weitere Artikel aus der Kategorie Sicherheit
DDoS-Angriffe in Luxemburg im Jahr 2024
Erfahren Sie mehr über die Statistiken zu DDoS-Angriffen, die POST Cyberforce im Jahr 2024 in Luxemburg entdeckt hat.
Verfasser
Paul FelixVeröffentlicht am
31 März 2024
DDoS-Angriffe in Luxemburg im Jahr 2023
Erfahren Sie mehr über die Statistiken zu DDoS-Angriffen, die POST Cyberforce im Jahr 2023 in Luxemburg entdeckt hat.
Verfasser
Paul FelixVeröffentlicht am
15 Februar 2023
DDoS-Angriffe in Luxemburg im Jahr 2022
Erfahren Sie mehr über die Statistiken zu DDoS-Angriffen, die POST Cyberforce im Jahr 2022 in Luxemburg entdeckt hat.
Verfasser
Paul FelixVeröffentlicht am
11 Oktober 2022