mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/binary-exploitation/libc-heap/use-after-free/first-fit.
This commit is contained in:
parent
d890db308a
commit
3176af5b6a
@ -12,10 +12,10 @@ Wenn Sie einen Speicherblock freigeben, der kein schneller Block ist, gelangt er
|
||||
|
||||
Beispiel:
|
||||
|
||||
- Sie reservieren 300 Bytes (`a`), dann 250 Bytes (`b`), geben `a` frei und fordern erneut 250 Bytes (`c`) an.
|
||||
- Sie reservieren 300 Bytes (`a`), dann 250 Bytes (`b`), dann geben Sie `a` frei und fordern erneut 250 Bytes (`c`) an.
|
||||
- Wenn Sie `a` freigeben, gelangt es in den unsortierten Bin.
|
||||
- Wenn Sie dann erneut 250 Bytes anfordern, findet der Zuweiser `a` am Schwanz und teilt es auf, wobei der Teil zurückgegeben wird, der Ihrer Anfrage entspricht, und der Rest im Bin bleibt.
|
||||
- `c` wird auf das vorherige `a` zeigen und mit den `a's` gefüllt sein.
|
||||
- Wenn Sie dann erneut 250 Bytes anfordern, findet der Zuweiser `a` am Schwanz und teilt es auf, wobei der Teil, der Ihrer Anfrage entspricht, zurückgegeben wird und der Rest im Bin bleibt.
|
||||
- `c` wird auf das vorherige `a` zeigen und mit den Inhalten von `a` gefüllt sein.
|
||||
```c
|
||||
char *a = malloc(300);
|
||||
char *b = malloc(250);
|
||||
@ -24,13 +24,9 @@ char *c = malloc(250);
|
||||
```
|
||||
### Fastbins
|
||||
|
||||
Fastbins werden für kleine Speicherblöcke verwendet. Im Gegensatz zu unsortierten Bins fügen Fastbins neue Blöcke am Kopf hinzu, was ein Last-in-First-out (LIFO) Verhalten erzeugt. Wenn Sie einen kleinen Speicherblock anfordern, zieht der Allocator vom Kopf des Fastbins.
|
||||
Fastbins werden für kleine Speicherblöcke verwendet. Im Gegensatz zu unsortierten Bins fügen Fastbins neue Blöcke am Kopf hinzu, was ein Last-In-First-Out (LIFO) Verhalten erzeugt. Wenn Sie einen kleinen Speicherblock anfordern, zieht der Allocator vom Kopf des Fastbins.
|
||||
|
||||
Beispiel:
|
||||
|
||||
- Sie allokieren vier Blöcke von jeweils 20 Bytes (`a`, `b`, `c`, `d`).
|
||||
- Wenn Sie sie in beliebiger Reihenfolge freigeben, werden die freigegebenen Blöcke am Kopf des Fastbins hinzugefügt.
|
||||
- Wenn Sie dann einen 20-Byte Block anfordern, gibt der Allocator den zuletzt freigegebenen Block vom Kopf des Fastbins zurück.
|
||||
```c
|
||||
char *a = malloc(20);
|
||||
char *b = malloc(20);
|
||||
@ -45,21 +41,89 @@ b = malloc(20); // c
|
||||
c = malloc(20); // b
|
||||
d = malloc(20); // a
|
||||
```
|
||||
---
|
||||
### 🔥 Moderne glibc Überlegungen (tcache ≥ 2.26)
|
||||
|
||||
Seit glibc 2.26 behält jeder Thread sein eigenes **tcache**, das *vor* dem unsortierten Bin abgefragt wird. Daher wird ein First-Fit-Szenario **nur erreicht, wenn**:
|
||||
|
||||
1. Die angeforderte Größe **größer als `tcache_max`** ist (standardmäßig 0x420 auf 64-Bit), *oder*
|
||||
2. Der entsprechende tcache-Bin **bereits voll oder manuell geleert** ist (indem 7 Elemente zugewiesen und in Gebrauch gehalten werden).
|
||||
|
||||
In echten Exploits fügen Sie normalerweise eine Hilfsroutine hinzu, wie:
|
||||
```c
|
||||
// Drain the tcache for a given size
|
||||
for(int i = 0; i < 7; i++) pool[i] = malloc(0x100);
|
||||
for(int i = 0; i < 7; i++) free(pool[i]);
|
||||
```
|
||||
Sobald der tcache erschöpft ist, gehen nachfolgende Freigaben in den unsortierten Bin, und das klassische First-Fit-Verhalten (Schwanzsuche, Kopf-Einfügung) kann erneut ausgelöst werden.
|
||||
|
||||
---
|
||||
### 🚩 Erstellen eines überlappenden Chunk UAF mit First-Fit
|
||||
|
||||
Der folgende Fragment (getestet auf glibc 2.38) zeigt, wie der Splitter im unsortierten Bin missbraucht werden kann, um 2 **überlappende Zeiger** zu erstellen – ein leistungsstarkes Primitive, das eine einzelne Freigabe in ein Write-After-Free umwandelt.
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(){
|
||||
setbuf(stdout, NULL);
|
||||
|
||||
/* 1. prepare 2 adjacent chunks and free the first one */
|
||||
char *A = malloc(0x420); // big enough to bypass tcache
|
||||
char *B = malloc(0x420);
|
||||
strcpy(A, "AAAA\n");
|
||||
free(A); // A → unsorted
|
||||
|
||||
/* 2. request a *smaller* size to force a split of A */
|
||||
char *C = malloc(0x400); // returns lower half of former A
|
||||
|
||||
/* 3. The remainder of A is still in the unsorted bin.
|
||||
Another 0x400-byte malloc will now return the *same*
|
||||
region pointed to by B – creating a UAF/overlap. */
|
||||
char *C2 = malloc(0x400);
|
||||
|
||||
printf("B = %p\nC2 = %p (overlaps B)\n", B, C2);
|
||||
|
||||
// Arbitrary write in B is immediately visible via C2
|
||||
memset(B, 'X', 0x10);
|
||||
fwrite(C2, 1, 0x10, stdout); // prints Xs
|
||||
}
|
||||
```
|
||||
Exploitation Rezept (häufig in aktuellen CTFs):
|
||||
|
||||
1. **Entleere** den tcache für die Zielgröße.
|
||||
2. **Gib** einen Chunk frei, sodass er im unsortierten Bin landet.
|
||||
3. **Allociere** eine etwas kleinere Größe – der Allocator teilt den unsortierten Chunk.
|
||||
4. **Allociere** erneut – der verbleibende Teil überlappt mit einem bereits verwendeten Chunk → UAF.
|
||||
5. Überschreibe sensible Felder (Funktionszeiger, FILE vtable usw.)
|
||||
|
||||
Eine praktische Anwendung findet sich in der 2024 HITCON Quals *Setjmp* Herausforderung, wo dieses genaue Primitive verwendet wird, um von einem UAF zu vollständiger Kontrolle über `__free_hook` zu pivotieren.{{#ref}}
|
||||
../../../../references/2024_setjmp_firstfit.md
|
||||
{{#endref}}
|
||||
|
||||
---
|
||||
### 🛡️ Milderungen & Härtung
|
||||
|
||||
* **Safe-linking (glibc ≥ 2.32)** schützt nur die einfach verketteten *tcache*/**fastbin** Listen. Die unsortierten/kleinen/großen Bins speichern weiterhin rohe Zeiger, sodass First-Fit basierte Überlappungen weiterhin möglich sind, wenn du einen Heap-Leak erhalten kannst.
|
||||
* **Heap-Zeiger-Verschlüsselung & MTE** (ARM64) betreffen x86-64 glibc noch nicht, aber Distro-Härtungsflags wie `GLIBC_TUNABLES=glibc.malloc.check=3` werden bei inkonsistenten Metadaten abbrechen und naive PoCs brechen.
|
||||
* **Füllen des tcache beim Freigeben** (vorgeschlagen für 2024 für glibc 2.41) würde die Nutzung des unsortierten Bins weiter reduzieren; beobachte zukünftige Releases bei der Entwicklung generischer Exploits.
|
||||
|
||||
---
|
||||
## Weitere Referenzen & Beispiele
|
||||
|
||||
- [**https://heap-exploitation.dhavalkapil.com/attacks/first_fit**](https://heap-exploitation.dhavalkapil.com/attacks/first_fit)
|
||||
- [**https://8ksec.io/arm64-reversing-and-exploitation-part-2-use-after-free/**](https://8ksec.io/arm64-reversing-and-exploitation-part-2-use-after-free/)
|
||||
- ARM64. Use after free: Erzeuge ein Benutzerobjekt, gib es frei, erzeuge ein Objekt, das den freigegebenen Chunk erhält und schreibe darauf, **überschreibe die Position von user->password** des vorherigen. Wiederverwende den Benutzer, um **die Passwortüberprüfung zu umgehen**
|
||||
- ARM64. Use after free: Erzeuge ein Benutzerobjekt, gib es frei, erzeuge ein Objekt, das den freigegebenen Chunk erhält und schreibe darauf, **überschreibe die Position von user->password** vom vorherigen. Wiederverwende den Benutzer, um **die Passwortüberprüfung zu umgehen**.
|
||||
- [**https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/use_after_free/#example**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/use_after_free/#example)
|
||||
- Das Programm erlaubt das Erstellen von Notizen. Eine Notiz hat die Notizinformationen in einem malloc(8) (mit einem Zeiger auf eine Funktion, die aufgerufen werden könnte) und einen Zeiger auf ein anderes malloc(\<size>) mit dem Inhalt der Notiz.
|
||||
- Der Angriff besteht darin, 2 Notizen (note0 und note1) mit größeren malloc-Inhalten als der Größe der Notizinformationen zu erstellen und sie dann freizugeben, damit sie in den Fast Bin (oder tcache) gelangen.
|
||||
- Erstelle dann eine weitere Notiz (note2) mit einer Inhaltsgröße von 8. Der Inhalt wird in note1 sein, da der Chunk wiederverwendet wird, wo wir den Funktionszeiger ändern könnten, um auf die Gewinnfunktion zu zeigen und dann Use-After-Free auf note1 anzuwenden, um den neuen Funktionszeiger aufzurufen.
|
||||
- Das Programm erlaubt das Erstellen von Notizen. Eine Notiz hat die Notizinformationen in einem malloc(8) (mit einem Zeiger auf eine Funktion, die aufgerufen werden könnte) und einen Zeiger auf ein anderes malloc(<size>) mit dem Inhalt der Notiz.
|
||||
- Der Angriff würde darin bestehen, 2 Notizen (note0 und note1) mit größeren malloc-Inhalten als der Größe der Notizinformationen zu erstellen und sie dann freizugeben, sodass sie in den Fast Bin (oder tcache) gelangen.
|
||||
- Dann, erstelle eine weitere Notiz (note2) mit einer Inhaltsgröße von 8. Der Inhalt wird in note1 sein, da der Chunk wiederverwendet wird, wo wir den Funktionszeiger ändern könnten, um auf die Gewinnfunktion zu zeigen und dann Use-After-Free die note1 zu verwenden, um den neuen Funktionszeiger aufzurufen.
|
||||
- [**https://guyinatuxedo.github.io/26-heap_grooming/pico_areyouroot/index.html**](https://guyinatuxedo.github.io/26-heap_grooming/pico_areyouroot/index.html)
|
||||
- Es ist möglich, etwas Speicher zu allocieren, den gewünschten Wert zu schreiben, ihn freizugeben, ihn erneut zu allocieren und da die vorherigen Daten noch vorhanden sind, wird er gemäß der neuen erwarteten Struktur im Chunk behandelt, was es ermöglicht, den Wert zu setzen, um das Flag zu erhalten.
|
||||
- [**https://guyinatuxedo.github.io/26-heap_grooming/swamp19_heapgolf/index.html**](https://guyinatuxedo.github.io/26-heap_grooming/swamp19_heapgolf/index.html)
|
||||
- In diesem Fall ist es notwendig, 4 in einen bestimmten Chunk zu schreiben, der der erste ist, der allociert wird (auch nachdem alle zwangsweise freigegeben wurden). Bei jedem neu allocierten Chunk wird seine Nummer im Array-Index gespeichert. Dann, allociere 4 Chunks (+ den ursprünglich allocierten), der letzte wird 4 enthalten, gib sie frei und zwinge die Reallokation des ersten, der den letzten freigegebenen Chunk verwenden wird, der den 4 enthält.
|
||||
|
||||
|
||||
|
||||
- In diesem Fall ist es notwendig, 4 in einen bestimmten Chunk zu schreiben, der der erste ist, der allociert wird (auch nachdem alle von ihnen zwangsweise freigegeben wurden). Bei jedem neu allocierten Chunk wird seine Nummer im Array-Index gespeichert. Dann, allociere 4 Chunks (+ den ursprünglich allocierten), der letzte wird 4 enthalten, gib sie frei und zwinge die Reallokation des ersten, der den letzten freigegebenen Chunk verwenden wird, der den 4 enthält.
|
||||
- 2024 HITCON Quals Setjmp Write-up (Quarkslab) – praktischer First-Fit / unsorted-split Überlappungsangriff: <https://ctftime.org/writeup/39355>
|
||||
- Angstrom CTF 2024 *heapify* Write-up – Missbrauch der unsortierten Bin-Splittung, um libc zu leaken und Überlappung zu gewinnen: <https://hackmd.io/@aneii11/H1S2snV40>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user