From 08b1dd2fc1aeb6361013796070bd8b6e9149f904 Mon Sep 17 00:00:00 2001 From: Translator Date: Wed, 30 Jul 2025 06:14:24 +0000 Subject: [PATCH] Translated ['src/binary-exploitation/libc-heap/heap-overflow.md', 'src/b --- .../libc-heap/heap-overflow.md | 46 ++++++++++++++++--- .../stack-overflow/README.md | 44 ++++++++++++++---- 2 files changed, 75 insertions(+), 15 deletions(-) diff --git a/src/binary-exploitation/libc-heap/heap-overflow.md b/src/binary-exploitation/libc-heap/heap-overflow.md index 5175b5f23..9e7616d6c 100644 --- a/src/binary-exploitation/libc-heap/heap-overflow.md +++ b/src/binary-exploitation/libc-heap/heap-overflow.md @@ -6,28 +6,28 @@ Ein Heap Overflow ist wie ein [**Stack Overflow**](../stack-overflow/index.html), aber im Heap. Grundsätzlich bedeutet es, dass ein gewisser Speicher im Heap reserviert wurde, um einige Daten zu speichern, und **die gespeicherten Daten größer waren als der reservierte Speicher.** -Bei Stack Overflows wissen wir, dass einige Register wie der Befehlszeiger oder der Stack-Frame aus dem Stack wiederhergestellt werden und es möglich sein könnte, dies auszunutzen. Im Falle von Heap Overflows **wird standardmäßig keine sensiblen Informationen** im Heap-Chunk gespeichert, der überlaufen werden kann. Es könnte jedoch sensible Informationen oder Zeiger geben, sodass die **Kritikalität** dieser Schwachstelle **abhängt** von **den Daten, die überschrieben werden könnten**, und wie ein Angreifer dies ausnutzen könnte. +Bei Stack Overflows wissen wir, dass einige Register wie der Befehlszeiger oder der Stack-Frame aus dem Stack wiederhergestellt werden und es möglich sein könnte, dies auszunutzen. Im Fall von Heap Overflows **wird standardmäßig keine sensiblen Informationen** im Heap-Chunk gespeichert, das überlaufen werden kann. Es könnte jedoch sensible Informationen oder Zeiger geben, sodass die **Kritikalität** dieser Schwachstelle **abhängig** davon ist, **welche Daten überschrieben werden könnten** und wie ein Angreifer dies ausnutzen könnte. > [!TIP] > Um Überlauf-Offsets zu finden, können Sie die gleichen Muster wie bei [**Stack Overflows**](../stack-overflow/index.html#finding-stack-overflows-offsets) verwenden. ### Stack Overflows vs Heap Overflows -Bei Stack Overflows ist die Anordnung und die Daten, die zum Zeitpunkt des Auslösens der Schwachstelle im Stack vorhanden sind, ziemlich zuverlässig. Dies liegt daran, dass der Stack linear ist, immer in kollidierendem Speicher zunimmt, an **bestimmten Stellen des Programmlaufs der Stack-Speicher normalerweise ähnliche Arten von Daten speichert** und eine spezifische Struktur mit einigen Zeigern am Ende des von jeder Funktion verwendeten Stack-Teils hat. +Bei Stack Overflows ist die Anordnung und die Daten, die zum Zeitpunkt des Auslösens der Schwachstelle im Stack vorhanden sind, ziemlich zuverlässig. Das liegt daran, dass der Stack linear ist, immer in kollidierendem Speicher zunimmt, an **bestimmten Stellen des Programmlaufs der Stack-Speicher normalerweise ähnliche Arten von Daten speichert** und eine spezifische Struktur mit einigen Zeigern am Ende des von jeder Funktion verwendeten Stack-Teils hat. -Im Falle eines Heap Overflows ist der verwendete Speicher jedoch nicht linear, sondern **zugewiesene Chunks befinden sich normalerweise an getrennten Speicherpositionen** (nicht nebeneinander), aufgrund von **Bins und Zonen**, die Zuweisungen nach Größe trennen, und weil **zuvor freigegebener Speicher verwendet wird**, bevor neue Chunks zugewiesen werden. Es ist **kompliziert zu wissen, welches Objekt mit dem anfälligen** für einen Heap Overflow kollidieren wird. Daher ist es notwendig, einen **zuverlässigen Weg zu finden, um das gewünschte Objekt im Speicher** neben dem überlaufbaren zu platzieren. +Im Fall eines Heap Overflows ist der verwendete Speicher jedoch nicht linear, sondern **zugewiesene Chunks befinden sich normalerweise an getrennten Speicherpositionen** (nicht nebeneinander), aufgrund von **Bins und Zonen**, die Zuweisungen nach Größe trennen, und weil **zuvor freigegebener Speicher verwendet wird**, bevor neue Chunks zugewiesen werden. Es ist **kompliziert zu wissen, welches Objekt mit dem anfälligen** für einen Heap Overflow kollidieren wird. Daher ist es notwendig, einen **zuverlässigen Weg zu finden, um das gewünschte Objekt im Speicher** neben dem überlaufbaren zu platzieren. -Eine der Techniken, die dafür verwendet wird, ist **Heap Grooming**, die beispielsweise [**in diesem Beitrag**](https://azeria-labs.com/grooming-the-ios-kernel-heap/) verwendet wird. In dem Beitrag wird erklärt, wie im iOS-Kernel, wenn eine Zone keinen Speicher mehr hat, um Chunks zu speichern, sie um eine Kernel-Seite erweitert wird, und diese Seite in Chunks der erwarteten Größen aufgeteilt wird, die in der Reihenfolge verwendet werden (bis zur iOS-Version 9.2, dann werden diese Chunks auf eine randomisierte Weise verwendet, um die Ausnutzung dieser Angriffe zu erschweren). +Eine der Techniken, die dafür verwendet wird, ist **Heap Grooming**, die beispielsweise [**in diesem Beitrag**](https://azeria-labs.com/grooming-the-ios-kernel-heap/) verwendet wird. In dem Beitrag wird erklärt, wie im iOS-Kernel, wenn eine Zone keinen Speicher mehr hat, um Chunks zu speichern, sie um eine Kernel-Seite erweitert wird, und diese Seite in Chunks der erwarteten Größen aufgeteilt wird, die in der Reihenfolge verwendet werden (bis zur iOS-Version 9.2, danach werden diese Chunks auf eine randomisierte Weise verwendet, um die Ausnutzung dieser Angriffe zu erschweren). Daher wird in dem vorherigen Beitrag, in dem ein Heap Overflow auftritt, um das überlaufene Objekt dazu zu bringen, mit einem Opferobjekt zu kollidieren, mehrere **`kallocs` von mehreren Threads erzwungen, um sicherzustellen, dass alle freien Chunks gefüllt sind und dass eine neue Seite erstellt wird**. -Um dieses Füllen mit Objekten einer bestimmten Größe zu erzwingen, ist die **out-of-line Zuweisung, die mit einem iOS mach port verbunden ist**, ein idealer Kandidat. Durch das Anpassen der Größe der Nachricht ist es möglich, die Größe der `kalloc`-Zuweisung genau anzugeben, und wenn der entsprechende mach port zerstört wird, wird die entsprechende Zuweisung sofort wieder an `kfree` freigegeben. +Um dieses Füllen mit Objekten einer bestimmten Größe zu erzwingen, ist die **out-of-line Zuweisung, die mit einem iOS Mach-Port verbunden ist**, ein idealer Kandidat. Durch das Anpassen der Größe der Nachricht ist es möglich, die Größe der `kalloc`-Zuweisung genau anzugeben, und wenn der entsprechende Mach-Port zerstört wird, wird die entsprechende Zuweisung sofort wieder an `kfree` freigegeben. Dann können einige dieser Platzhalter **freigegeben** werden. Die **`kalloc.4096`-Freiliste gibt Elemente in einer Last-In-First-Out-Reihenfolge frei**, was im Grunde bedeutet, dass, wenn einige Platzhalter freigegeben werden und der Exploit versucht, mehrere Opferobjekte zuzuweisen, während er versucht, das anfällige Objekt für den Overflow zuzuweisen, es wahrscheinlich ist, dass dieses Objekt von einem Opferobjekt gefolgt wird. ### Beispiel libc -[**Auf dieser Seite**](https://guyinatuxedo.github.io/27-edit_free_chunk/heap_consolidation_explanation/index.html) ist es möglich, eine grundlegende Heap Overflow-Emulation zu finden, die zeigt, wie das Überschreiben des prev in use-Bits des nächsten Chunks und der Position der prev size es ermöglicht, einen **verwendeten Chunk zu konsolidieren** (indem er denkt, dass er ungenutzt ist) und **dann erneut zuzuweisen**, wobei es möglich ist, Daten zu überschreiben, die in einem anderen Zeiger verwendet werden. +[**Auf dieser Seite**](https://guyinatuxedo.github.io/27-edit_free_chunk/heap_consolidation_explanation/index.html) ist es möglich, eine grundlegende Heap Overflow-Emulation zu finden, die zeigt, wie das Überschreiben des prev in use-Bits des nächsten Chunks und der Position der prev-Größe es ermöglicht, einen **verwendeten Chunk zu konsolidieren** (indem er denkt, er sei ungenutzt) und **dann erneut zuzuweisen**, wodurch es möglich ist, Daten zu überschreiben, die in einem anderen Zeiger verwendet werden. Ein weiteres Beispiel aus [**protostar heap 0**](https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap0/index.html) zeigt ein sehr einfaches Beispiel eines CTF, bei dem ein **Heap Overflow** ausgenutzt werden kann, um die Gewinnerfunktion aufzurufen, um **die Flagge zu erhalten**. @@ -43,6 +43,38 @@ python3 -c 'print("/"*0x400+"/bin/ls\x00")' > hax.txt - [**Auth-or-out. Hack The Box**](https://7rocky.github.io/en/ctf/htb-challenges/pwn/auth-or-out/) - Wir nutzen eine Integer Overflow-Sicherheitsanfälligkeit, um einen Heap Overflow zu erzeugen. -- Wir korrumpieren Zeiger auf eine Funktion innerhalb eines `struct` des überlaufenen Chunks, um eine Funktion wie `system` festzulegen und Codeausführung zu erhalten. +- Wir korrumpieren Zeiger auf eine Funktion innerhalb einer `struct` des überlaufenen Chunks, um eine Funktion wie `system` festzulegen und Codeausführung zu erhalten. + +### Beispiel aus der Praxis: CVE-2025-40597 – Missbrauch von `__sprintf_chk` + +Im SonicWall SMA100 Firmware 10.2.1.15 allokiert das Reverse-Proxy-Modul `mod_httprp.so` einen **0x80-Byte** Heap-Chunks und fügt dann mehrere Strings mit `__sprintf_chk` zusammen: +```c +char *buf = calloc(0x80, 1); +/* … */ +__sprintf_chk(buf, /* destination (0x80-byte chunk) */ +-1, /* <-- size argument !!! */ +0, /* flags */ +"%s%s%s%s", /* format */ +"/", "https://", path, host); +``` +`__sprintf_chk` ist Teil von **_FORTIFY_SOURCE**. Wenn es einen **positiven** `size`-Parameter erhält, überprüft es, ob der resultierende String in den Zielpuffer passt. Durch das Übergeben von **`-1` (0xFFFFFFFFFFFFFFFF)** haben die Entwickler effektiv die **Grenzprüfung deaktiviert** und den gesicherten Aufruf wieder in ein klassisches, unsicheres `sprintf` umgewandelt. + +Das Bereitstellen eines übermäßig langen **`Host:`**-Headers ermöglicht es einem Angreifer daher, **den 0x80-Byte-Chunck zu überlaufen und die Metadaten des folgenden Heap-Chunks zu überschreiben** (tcache / fast-bin / small-bin, je nach Allokator). Ein Absturz kann reproduziert werden mit: +```python +import requests, warnings +warnings.filterwarnings('ignore') +requests.get( +'https://TARGET/__api__/', +headers={'Host': 'A'*750}, +verify=False +) +``` +Praktische Ausnutzung würde **Heap Grooming** erfordern, um ein kontrollierbares Objekt direkt nach dem verwundbaren Chunk zu platzieren, aber die Hauptursache hebt zwei wichtige Erkenntnisse hervor: + +1. **_FORTIFY_SOURCE ist kein Allheilmittel** – Missbrauch kann den Schutz zunichte machen. +2. Übergeben Sie immer die **korrekte Puffergröße** an die `_chk`-Familie (oder, noch besser, verwenden Sie `snprintf`). + +## References +* [watchTowr Labs – Stack Overflows, Heap Overflows and Existential Dread (SonicWall SMA100)](https://labs.watchtowr.com/stack-overflows-heap-overflows-and-existential-dread-sonicwall-sma100-cve-2025-40596-cve-2025-40597-and-cve-2025-40598/) {{#include ../../banners/hacktricks-training.md}} diff --git a/src/binary-exploitation/stack-overflow/README.md b/src/binary-exploitation/stack-overflow/README.md index 2e00c8d74..c3dc509b5 100644 --- a/src/binary-exploitation/stack-overflow/README.md +++ b/src/binary-exploitation/stack-overflow/README.md @@ -4,7 +4,7 @@ ## Was ist ein Stack Overflow -Ein **Stack Overflow** ist eine Schwachstelle, die auftritt, wenn ein Programm mehr Daten auf den Stack schreibt, als ihm zugewiesen sind. Diese überschüssigen Daten werden **benachbarte Speicherbereiche überschreiben**, was zu einer Korruption gültiger Daten, einer Störung des Kontrollflusses und potenziell zur Ausführung von schädlichem Code führen kann. Dieses Problem tritt häufig aufgrund der Verwendung unsicherer Funktionen auf, die keine Grenzkontrollen für Eingaben durchführen. +Ein **Stack Overflow** ist eine Schwachstelle, die auftritt, wenn ein Programm mehr Daten auf den Stack schreibt, als ihm zugewiesen sind. Diese überschüssigen Daten werden **benachbarte Speicherbereiche überschreiben**, was zur Korruption gültiger Daten, zur Störung des Kontrollflusses und möglicherweise zur Ausführung von schädlichem Code führt. Dieses Problem tritt häufig aufgrund der Verwendung unsicherer Funktionen auf, die keine Grenzkontrollen für Eingaben durchführen. Das Hauptproblem bei diesem Überschreiben ist, dass der **gespeicherte Befehlszeiger (EIP/RIP)** und der **gespeicherte Basiszeiger (EBP/RBP)**, um zur vorherigen Funktion zurückzukehren, **auf dem Stack gespeichert sind**. Daher wird ein Angreifer in der Lage sein, diese zu überschreiben und **den Ausführungsfluss des Programms zu steuern**. @@ -25,9 +25,9 @@ printf("You entered: %s\n", buffer); Die häufigste Methode, um Stack Overflows zu finden, besteht darin, eine sehr große Eingabe von `A`s zu geben (z. B. `python3 -c 'print("A"*1000)'`) und einen `Segmentation Fault` zu erwarten, der anzeigt, dass die **Adresse `0x41414141` versucht wurde zuzugreifen**. -Darüber hinaus, sobald Sie festgestellt haben, dass es eine Stack Overflow-Sicherheitsanfälligkeit gibt, müssen Sie den Offset finden, bis es möglich ist, die **Rücksprungadresse zu überschreiben**. Dazu wird normalerweise eine **De Bruijn-Sequenz** verwendet. Diese ist für ein gegebenes Alphabet der Größe _k_ und Teilsequenzen der Länge _n_ eine **zyklische Sequenz, in der jede mögliche Teilsequenz der Länge _n_ genau einmal** als zusammenhängende Teilsequenz erscheint. +Darüber hinaus, sobald Sie festgestellt haben, dass eine Stack Overflow-Sicherheitsanfälligkeit vorliegt, müssen Sie den Offset finden, bis es möglich ist, die **Rücksprungadresse zu überschreiben**. Dazu wird normalerweise eine **De Bruijn-Sequenz** verwendet. Diese ist für ein gegebenes Alphabet der Größe _k_ und Teilsequenzen der Länge _n_ eine **zyklische Sequenz, in der jede mögliche Teilsequenz der Länge _n_ genau einmal** als zusammenhängende Teilsequenz erscheint. -Auf diese Weise ist es anstelle von Hand erforderlich, herauszufinden, welcher Offset benötigt wird, um die EIP zu steuern, möglich, als Padding eine dieser Sequenzen zu verwenden und dann den Offset der Bytes zu finden, die das Überschreiben beendet haben. +Auf diese Weise ist es anstelle von Hand erforderlich, herauszufinden, welcher Offset benötigt wird, um das EIP zu steuern, möglich, als Padding eine dieser Sequenzen zu verwenden und dann den Offset der Bytes zu finden, die es überschrieben haben. Es ist möglich, **pwntools** dafür zu verwenden: ```python @@ -50,14 +50,14 @@ pattern search $rsp #Search the offset given the content of $rsp ``` ## Ausnutzen von Stack-Überläufen -Während eines Überlaufs (vorausgesetzt, die Überlaufgröße ist groß genug) wirst du in der Lage sein, **Werte von lokalen Variablen im Stack zu überschreiben**, bis du das gespeicherte **EBP/RBP und EIP/RIP (oder sogar mehr)** erreichst.\ +Während eines Überlaufs (vorausgesetzt, die Überlaufgröße ist groß genug) werden Sie in der Lage sein, **Werte von lokalen Variablen im Stack zu überschreiben**, bis Sie das gespeicherte **EBP/RBP und EIP/RIP (oder sogar mehr)** erreichen.\ Die häufigste Methode, diese Art von Schwachstelle auszunutzen, besteht darin, die **Rücksprungadresse zu modifizieren**, sodass, wenn die Funktion endet, der **Kontrollfluss dorthin umgeleitet wird, wo der Benutzer in diesem Zeiger angegeben hat**. In anderen Szenarien könnte es jedoch ausreichen, einfach **einige Variablenwerte im Stack zu überschreiben**, um die Ausnutzung zu erreichen (wie bei einfachen CTF-Herausforderungen). ### Ret2win -In dieser Art von CTF-Herausforderungen gibt es eine **Funktion**, die **im** Binärprogramm **nie aufgerufen wird** und die **du aufrufen musst, um zu gewinnen**. Für diese Herausforderungen musst du nur den **Offset finden, um die Rücksprungadresse zu überschreiben**, und **die Adresse der Funktion finden**, die aufgerufen werden soll (normalerweise wäre [**ASLR**](../common-binary-protections-and-bypasses/aslr/index.html) deaktiviert), sodass, wenn die verwundbare Funktion zurückkehrt, die versteckte Funktion aufgerufen wird: +In dieser Art von CTF-Herausforderungen gibt es eine **Funktion**, die **im** Binärprogramm **nie aufgerufen wird** und die **Sie aufrufen müssen, um zu gewinnen**. Für diese Herausforderungen müssen Sie nur den **Offset finden, um die Rücksprungadresse zu überschreiben**, und **die Adresse der Funktion finden**, die aufgerufen werden soll (in der Regel wäre [**ASLR**](../common-binary-protections-and-bypasses/aslr/index.html) deaktiviert), sodass, wenn die verwundbare Funktion zurückkehrt, die versteckte Funktion aufgerufen wird: {{#ref}} ret2win/ @@ -73,7 +73,7 @@ stack-shellcode/ ### ROP & Ret2... Techniken -Diese Technik ist das grundlegende Framework, um den Hauptschutz der vorherigen Technik zu umgehen: **Kein ausführbarer Stack (NX)**. Und sie ermöglicht die Durchführung mehrerer anderer Techniken (ret2lib, ret2syscall...), die dazu führen, dass beliebige Befehle ausgeführt werden, indem vorhandene Anweisungen im Binärprogramm missbraucht werden: +Diese Technik ist das grundlegende Framework, um den Hauptschutz der vorherigen Technik zu umgehen: **Kein ausführbarer Stack (NX)**. Und sie ermöglicht die Durchführung mehrerer anderer Techniken (ret2lib, ret2syscall...), die dazu führen, dass beliebige Befehle ausgeführt werden, indem vorhandene Anweisungen im Binärprogramm ausgenutzt werden: {{#ref}} ../rop-return-oriented-programing/ @@ -81,7 +81,7 @@ Diese Technik ist das grundlegende Framework, um den Hauptschutz der vorherigen ## Heap-Überläufe -Ein Überlauf muss nicht immer im Stack sein, er könnte auch im **Heap** sein, zum Beispiel: +Ein Überlauf wird nicht immer im Stack auftreten, er könnte auch im **Heap** auftreten, zum Beispiel: {{#ref}} ../libc-heap/heap-overflow.md @@ -89,10 +89,38 @@ Ein Überlauf muss nicht immer im Stack sein, er könnte auch im **Heap** sein, ## Arten von Schutzmaßnahmen -Es gibt mehrere Schutzmaßnahmen, die versuchen, die Ausnutzung von Schwachstellen zu verhindern, überprüfe sie in: +Es gibt mehrere Schutzmaßnahmen, die versuchen, die Ausnutzung von Schwachstellen zu verhindern, überprüfen Sie diese in: {{#ref}} ../common-binary-protections-and-bypasses/ {{#endref}} +### Beispiel aus der Praxis: CVE-2025-40596 (SonicWall SMA100) + +Eine gute Demonstration, warum **`sscanf` niemals für das Parsen von nicht vertrauenswürdigen Eingaben vertraut werden sollte**, erschien 2025 im SSL-VPN-Gerät SMA100 von SonicWall. Die verwundbare Routine innerhalb von `/usr/src/EasyAccess/bin/httpd` versucht, die Version und den Endpunkt aus jeder URI zu extrahieren, die mit `/__api__/` beginnt: +```c +char version[3]; +char endpoint[0x800] = {0}; +/* simplified proto-type */ +sscanf(uri, "%*[^/]/%2s/%s", version, endpoint); +``` +1. Die erste Umwandlung (`%2s`) speichert sicher **zwei** Bytes in `version` (z.B. `"v1"`). +2. Die zweite Umwandlung (`%s`) **hat keinen Längenbezeichner**, daher wird `sscanf` **bis zum ersten NUL-Byte** weiter kopieren. +3. Da `endpoint` sich im **Stack** befindet und **0x800 Bytes lang** ist, führt das Bereitstellen eines Pfades, der länger als 0x800 Bytes ist, zu einer Beschädigung von allem, was sich nach dem Puffer befindet ‑ einschließlich des **Stack-Canyons** und der **gespeicherten Rücksprungadresse**. + +Ein einzeiliger Proof-of-Concept reicht aus, um den Absturz **vor der Authentifizierung** auszulösen: +```python +import requests, warnings +warnings.filterwarnings('ignore') +url = "https://TARGET/__api__/v1/" + "A"*3000 +requests.get(url, verify=False) +``` +Obwohl Stack-Canaries den Prozess abbrechen, erhält ein Angreifer dennoch ein **Denial-of-Service**-Primitive (und möglicherweise mit zusätzlichen Informationslecks eine Codeausführung). Die Lektion ist einfach: + +* Geben Sie immer eine **maximale Feldbreite** an (z.B. `%511s`). +* Bevorzugen Sie sicherere Alternativen wie `snprintf`/`strncpy_s`. + +## References +* [watchTowr Labs – Stack Overflows, Heap Overflows and Existential Dread (SonicWall SMA100)](https://labs.watchtowr.com/stack-overflows-heap-overflows-and-existential-dread-sonicwall-sma100-cve-2025-40596-cve-2025-40597-and-cve-2025-40598/) + {{#include ../../banners/hacktricks-training.md}}