mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-25 06:00:40 +00:00
Translated ['binary-exploitation/heap/README.md', 'binary-exploitation/h
This commit is contained in:
parent
f765ed8b16
commit
fe0fcd0746
8 changed files with 673 additions and 125 deletions
|
@ -721,7 +721,11 @@
|
|||
* [Format Strings - Arbitrary Read Example](binary-exploitation/format-strings/format-strings-arbitrary-read-example.md)
|
||||
* [Format Strings Template](binary-exploitation/format-strings/format-strings-template.md)
|
||||
* [Heap](binary-exploitation/heap/README.md)
|
||||
* [Use After Free](binary-exploitation/heap/use-after-free.md)
|
||||
* [Bins & Memory Allocations](binary-exploitation/heap/bins-and-memory-allocations.md)
|
||||
* [Heap Functions Security Checks](binary-exploitation/heap/heap-functions-security-checks.md)
|
||||
* [Use After Free](binary-exploitation/heap/use-after-free/README.md)
|
||||
* [First Fit](binary-exploitation/heap/use-after-free/first-fit.md)
|
||||
* [Double Free](binary-exploitation/heap/double-free.md)
|
||||
* [Heap Overflow](binary-exploitation/heap/heap-overflow.md)
|
||||
* [Common Binary Exploitation Protections & Bypasses](binary-exploitation/common-binary-protections-and-bypasses/README.md)
|
||||
* [ASLR](binary-exploitation/common-binary-protections-and-bypasses/aslr/README.md)
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
|
||||
L'heap è essenzialmente il luogo in cui un programma sarà in grado di memorizzare dati quando richiede dati chiamando funzioni come **`malloc`**, `calloc`... Inoltre, quando questa memoria non è più necessaria, viene resa disponibile chiamando la funzione **`free`**.
|
||||
|
||||
Come mostrato, si trova subito dopo dove il binario viene caricato in memoria (controlla la sezione `[heap]`):
|
||||
Come mostrato, si trova subito dopo il caricamento del binario in memoria (controlla la sezione `[heap]`):
|
||||
|
||||
<figure><img src="../../.gitbook/assets/image (1241).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Allocazione di Chunk di Base
|
||||
|
||||
Quando viene richiesto di memorizzare alcuni dati nell'heap, viene allocato uno spazio nell'heap. Questo spazio apparterrà a un bin e solo i dati richiesti + lo spazio degli header del bin + l'offset della dimensione minima del bin verranno riservati per il chunk. L'obiettivo è riservare solo la memoria minima possibile senza rendere complicato trovare dove si trova ciascun chunk. Per questo, le informazioni sui metadati del chunk vengono utilizzate per sapere dove si trova ciascun chunk utilizzato/libero.
|
||||
Quando viene richiesto di memorizzare alcuni dati nell'heap, viene allocato uno spazio nell'heap. Questo spazio apparterrà a un bin e solo i dati richiesti + lo spazio degli header del bin + l'offset della dimensione minima del bin verranno riservati per il chunk. L'obiettivo è riservare la memoria minima possibile senza rendere complicato trovare dove si trova ciascun chunk. Per questo, le informazioni sui metadati del chunk vengono utilizzate per sapere dove si trova ciascun chunk utilizzato/libero.
|
||||
|
||||
Ci sono diversi modi per riservare lo spazio principalmente a seconda del bin utilizzato, ma una metodologia generale è la seguente:
|
||||
|
||||
|
@ -27,7 +27,7 @@ Nota che se la memoria richiesta supera una soglia, verrà utilizzato **`mmap`**
|
|||
|
||||
Nelle applicazioni **multithread**, il gestore dell'heap deve prevenire le **condizioni di gara** che potrebbero portare a crash. Inizialmente, ciò veniva fatto utilizzando un **mutex globale** per garantire che solo un thread potesse accedere all'heap alla volta, ma ciò causava **problemi di prestazioni** a causa del collo di bottiglia indotto dal mutex.
|
||||
|
||||
Per affrontare questo problema, l'allocatore di heap ptmalloc2 ha introdotto "arene", dove **ogni arena** funge da **heap separato** con le sue **proprie** strutture **dati** e **mutex**, consentendo a più thread di eseguire operazioni sull'heap senza interferire l'uno con l'altro, purché utilizzino arene diverse.
|
||||
Per affrontare questo problema, l'allocatore dell'heap ptmalloc2 ha introdotto "arene", dove **ogni arena** funge da un **heap separato** con le sue **proprie** strutture **dati** e **mutex**, consentendo a più thread di eseguire operazioni sull'heap senza interferire l'uno con l'altro, purché utilizzino arene diverse.
|
||||
|
||||
L'arena "principale" predefinita gestisce le operazioni sull'heap per le applicazioni single-threaded. Quando vengono aggiunti **nuovi thread**, il gestore dell'heap assegna loro **arene secondarie** per ridurre la contesa. Prima tenta di collegare ciascun nuovo thread a un'arena inutilizzata, creandone di nuove se necessario, fino a un limite di 2 volte i core della CPU per i sistemi a 32 bit e 8 volte per i sistemi a 64 bit. Una volta raggiunto il limite, i **thread devono condividere le arene**, portando a una potenziale contesa.
|
||||
|
||||
|
@ -41,16 +41,82 @@ I subheap fungono da riserve di memoria per le arene secondarie nelle applicazio
|
|||
* L'heap iniziale si trova direttamente dopo il binario del programma in memoria e si espande utilizzando la chiamata di sistema `sbrk`.
|
||||
* I subheap, utilizzati dalle arene secondarie, vengono creati tramite `mmap`, una chiamata di sistema che mappa una regione di memoria specificata.
|
||||
2. **Riserva di Memoria con `mmap`**:
|
||||
* Quando il gestore dell'heap crea un subheap, riserva un grande blocco di memoria tramite `mmap`. Questa riserva non alloca immediatamente memoria; designa semplicemente una regione che altri processi di sistema o allocazioni non dovrebbero utilizzare.
|
||||
* Per impostazione predefinita, la dimensione riservata per un subheap è di 1 MB per i processi a 32 bit e di 64 MB per i processi a 64 bit.
|
||||
* Quando il gestore dell'heap crea un subheap, riserva un grande blocco di memoria tramite `mmap`. Questa riserva non alloca immediatamente memoria; semplicemente designa una regione che altri processi di sistema o allocazioni non dovrebbero utilizzare.
|
||||
* Per impostazione predefinita, la dimensione riservata per un subheap è di 1 MB per i processi a 32 bit e 64 MB per i processi a 64 bit.
|
||||
3. **Espansione Graduale con `mprotect`**:
|
||||
* La regione di memoria riservata è inizialmente contrassegnata come `PROT_NONE`, indicando che il kernel non ha bisogno di allocare memoria fisica per questo spazio ancora.
|
||||
* Per "far crescere" il subheap, il gestore dell'heap utilizza `mprotect` per cambiare le autorizzazioni delle pagine da `PROT_NONE` a `PROT_READ | PROT_WRITE`, spingendo il kernel ad allocare memoria fisica agli indirizzi precedentemente riservati. Questo approccio passo dopo passo consente al subheap di espandersi secondo necessità.
|
||||
* La regione di memoria riservata è inizialmente contrassegnata come `PROT_NONE`, indicando che il kernel non deve ancora allocare memoria fisica a questo spazio.
|
||||
* Per "far crescere" il subheap, il gestore dell'heap utilizza `mprotect` per cambiare le autorizzazioni della pagina da `PROT_NONE` a `PROT_READ | PROT_WRITE`, spingendo il kernel ad allocare memoria fisica agli indirizzi precedentemente riservati. Questo approccio step-by-step consente al subheap di espandersi secondo necessità.
|
||||
* Una volta esaurito l'intero subheap, il gestore dell'heap crea un nuovo subheap per continuare l'allocazione.
|
||||
|
||||
### Metadati
|
||||
### malloc\_state
|
||||
|
||||
Come già commentato, questi chunk hanno anche alcuni metadati, molto ben rappresentati in questa immagine:
|
||||
**Ogni heap** (arena principale o arene di altri thread) ha una **struttura `malloc_state`.**\
|
||||
È importante notare che la struttura **`malloc_state`** dell'arena principale è una **variabile globale nella libc** (quindi situata nello spazio di memoria della libc).\
|
||||
Nel caso delle **strutture `malloc_state`** degli heap dei thread, sono situate **all'interno del "heap" del thread** stesso.
|
||||
|
||||
Ci sono alcune cose interessanti da notare da questa struttura (vedi codice C di seguito):
|
||||
|
||||
* Il `mchunkptr bins[NBINS * 2 - 2];` contiene **puntatori** ai **primi e ultimi chunk** dei **bins** piccoli, grandi e non ordinati (il -2 è perché l'indice 0 non viene utilizzato)
|
||||
* Pertanto, il **primo chunk** di questi bin avrà un **puntatore all'indietro a questa struttura** e l'**ultimo chunk** di questi bin avrà un **puntatore in avanti** a questa struttura. Ciò significa fondamentalmente che se è possibile **rilevare** questi indirizzi nell'arena principale, si avrà un puntatore alla struttura nella **libc**.
|
||||
* Le strutture `struct malloc_state *next;` e `struct malloc_state *next_free;` sono liste collegate di arene
|
||||
* Il chunk `top` è l'ultimo "chunk", che è fondamentalmente **tutto lo spazio rimanente dell'heap**. Una volta che il chunk top è "vuoto", l'heap è completamente utilizzato e ha bisogno di richiedere più spazio.
|
||||
* L'ultimo chunk di **rimanenza** proviene dai casi in cui non è disponibile un chunk di dimensioni esatte e quindi viene diviso un chunk più grande, una parte rimanente del puntatore viene posizionata qui.
|
||||
```c
|
||||
// From https://heap-exploitation.dhavalkapil.com/diving_into_glibc_heap/malloc_state
|
||||
struct malloc_state
|
||||
{
|
||||
/* Serialize access. */
|
||||
__libc_lock_define (, mutex);
|
||||
/* Flags (formerly in max_fast). */
|
||||
int flags;
|
||||
|
||||
/* Fastbins */
|
||||
mfastbinptr fastbinsY[NFASTBINS];
|
||||
/* Base of the topmost chunk -- not otherwise kept in a bin */
|
||||
mchunkptr top;
|
||||
/* The remainder from the most recent split of a small request */
|
||||
mchunkptr last_remainder;
|
||||
/* Normal bins packed as described above */
|
||||
mchunkptr bins[NBINS * 2 - 2];
|
||||
|
||||
/* Bitmap of bins */
|
||||
unsigned int binmap[BINMAPSIZE];
|
||||
|
||||
/* Linked list */
|
||||
struct malloc_state *next;
|
||||
/* Linked list for free arenas. Access to this field is serialized
|
||||
by free_list_lock in arena.c. */
|
||||
struct malloc_state *next_free;
|
||||
/* Number of threads attached to this arena. 0 if the arena is on
|
||||
the free list. Access to this field is serialized by
|
||||
free_list_lock in arena.c. */
|
||||
|
||||
INTERNAL_SIZE_T attached_threads;
|
||||
/* Memory allocated from the system in this arena. */
|
||||
INTERNAL_SIZE_T system_mem;
|
||||
INTERNAL_SIZE_T max_system_mem;
|
||||
};
|
||||
|
||||
typedef struct malloc_state *mstate;
|
||||
```
|
||||
### malloc\_chunk
|
||||
|
||||
Questa struttura rappresenta un particolare blocco di memoria. I vari campi hanno significati diversi per i blocchi allocati e non allocati.
|
||||
```c
|
||||
// From https://heap-exploitation.dhavalkapil.com/diving_into_glibc_heap/malloc_chunk
|
||||
struct malloc_chunk {
|
||||
INTERNAL_SIZE_T mchunk_prev_size; /* Size of previous chunk, if it is free. */
|
||||
INTERNAL_SIZE_T mchunk_size; /* Size in bytes, including overhead. */
|
||||
struct malloc_chunk* fd; /* double links -- used only if this chunk is free. */
|
||||
struct malloc_chunk* bk;
|
||||
/* Only used for large blocks: pointer to next larger size. */
|
||||
struct malloc_chunk* fd_nextsize; /* double links -- used only if this chunk is free. */
|
||||
struct malloc_chunk* bk_nextsize;
|
||||
};
|
||||
|
||||
typedef struct malloc_chunk* mchunkptr;
|
||||
```
|
||||
Come già commentato in precedenza, questi chunk hanno anche alcuni metadati, molto ben rappresentati in questa immagine:
|
||||
|
||||
<figure><img src="../../.gitbook/assets/image (1242).png" alt=""><figcaption><p><a href="https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png">https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png</a></p></figcaption></figure>
|
||||
|
||||
|
@ -60,126 +126,26 @@ Di solito i metadati sono 0x08B, indicando la dimensione corrente del chunk util
|
|||
* `M`: Se è 1, questo chunk fa parte di uno spazio allocato con mmap e non fa parte di un heap
|
||||
* `P`: Se è 1, il chunk precedente è in uso
|
||||
|
||||
Quindi, lo spazio per i dati dell'utente, e infine 0x08B per indicare la dimensione del chunk precedente quando il chunk è disponibile (o per memorizzare i dati dell'utente quando viene allocato).
|
||||
Successivamente, lo spazio per i dati dell'utente, e infine 0x08B per indicare la dimensione del chunk precedente quando il chunk è disponibile (o per memorizzare i dati dell'utente quando è allocato).
|
||||
|
||||
Inoltre, quando disponibile, i dati dell'utente vengono utilizzati per contenere anche alcuni dati:
|
||||
Inoltre, quando disponibili, i dati dell'utente vengono utilizzati anche per contenere alcune informazioni:
|
||||
|
||||
* Puntatore al chunk successivo
|
||||
* Puntatore al chunk precedente
|
||||
* Dimensione del chunk successivo nella lista
|
||||
* Dimensione del prossimo chunk nella lista
|
||||
* Dimensione del chunk precedente nella lista
|
||||
|
||||
|
||||
|
||||
<figure><img src="../../.gitbook/assets/image (1243).png" alt=""><figcaption><p><a href="https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png">https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png</a></p></figcaption></figure>
|
||||
|
||||
{% hint style="info" %}
|
||||
Nota come organizzare la lista in questo modo evita la necessità di avere un array in cui ogni singolo chunk viene registrato.
|
||||
|
||||
## Protezioni di Free
|
||||
|
||||
Per proteggersi dall'abuso accidentale o intenzionale della funzione free, prima di eseguire le sue azioni vengono effettuati alcuni controlli:
|
||||
|
||||
* Controlla che l'indirizzo [sia allineato](https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l4182) su un limite di 8 byte o 16 byte su un limite di 64 bit (`(indirizzo % 16) == 0`), poiché _malloc_ garantisce che tutte le allocazioni siano allineate.
|
||||
* Controlla che il campo di dimensione del chunk non sia impossibile - sia perché è [troppo piccolo](https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l4318), troppo grande, non di dimensioni allineate, o [sovrapporrebbe la fine dello spazio degli indirizzi del processo](https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l4175).
|
||||
* Controlla che il chunk si trovi [all'interno dei limiti dell'arena](https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l4318).
|
||||
* Controlla che il chunk non sia [già contrassegnato come libero](https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l4182) controllando il bit "P" corrispondente che si trova nei metadati all'inizio del chunk successivo.
|
||||
## Bins
|
||||
|
||||
Per migliorare l'efficienza di come vengono memorizzati i chunk, ogni chunk non è solo in una lista concatenata, ma ci sono diversi tipi. Questi sono i bins e ci sono 5 tipi di bins: [62](https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l1407) small bins, 63 large bins, 1 unsorted bin, 10 fast bins e 64 tcache bins per thread.
|
||||
|
||||
L'indirizzo iniziale di ogni bin non ordinato, small e large è all'interno dello stesso array. L'indice 0 non è utilizzato, 1 è l'unsorted bin, i bins da 2 a 64 sono small bins e i bins da 65 a 127 sono large bins.
|
||||
|
||||
### Small Bins
|
||||
|
||||
I small bins sono più veloci dei large bins ma più lenti dei fast bins.
|
||||
|
||||
Ogni bin dei 62 avrà **chunk della stessa dimensione**: 16, 24, ... (con una dimensione massima di 504 byte in 32 bit e 1024 in 64 bit). Questo aiuta nella velocità nel trovare il bin in cui dovrebbe essere allocato uno spazio e nell'inserimento e rimozione delle voci in queste liste.
|
||||
|
||||
### Large Bins
|
||||
|
||||
A differenza dei small bins, che gestiscono chunk di dimensioni fisse, ogni **large bin gestisce un intervallo di dimensioni di chunk**. Questo è più flessibile, permettendo al sistema di ospitare **varie dimensioni** senza necessità di un bin separato per ogni dimensione.
|
||||
|
||||
In un allocatore di memoria, i large bins iniziano dove finiscono i small bins. Gli intervalli per i large bins crescono progressivamente, il che significa che il primo bin potrebbe coprire chunk da 512 a 576 byte, mentre il successivo copre da 576 a 640 byte. Questo modello continua, con il bin più grande che contiene tutti i chunk sopra 1MB.
|
||||
|
||||
I large bins sono più lenti da gestire rispetto ai small bins perché devono **ordinare e cercare in una lista di dimensioni di chunk variabili per trovare la migliore corrispondenza** per un'allocazione. Quando un chunk viene inserito in un large bin, deve essere ordinato e quando viene allocata memoria, il sistema deve trovare il chunk giusto. Questo lavoro aggiuntivo li rende **più lenti**, ma poiché le allocazioni di grandi dimensioni sono meno comuni di quelle piccole, è un compromesso accettabile.
|
||||
|
||||
Ci sono:
|
||||
|
||||
* 32 bins di intervallo 64B
|
||||
* 16 bins di intervallo 512B
|
||||
* 8 bins di intervallo 4096B
|
||||
* 4 bins di intervallo 32768B
|
||||
* 2 bins di intervallo 262144B
|
||||
* 1 bin per dimensioni rimanenti
|
||||
|
||||
### Unsorted bin
|
||||
|
||||
L'unsorted bin è una **cache veloce** utilizzata dal gestore dell'heap per rendere più veloce l'allocazione di memoria. Ecco come funziona: quando un programma libera memoria, il gestore dell'heap non la mette immediatamente in un bin specifico. Invece, cerca prima di **fonderla con eventuali chunk liberi adiacenti** per creare un blocco più grande di memoria libera. Quindi, inserisce questo nuovo chunk in un bin generale chiamato "unsorted bin".
|
||||
|
||||
Quando un programma **richiede memoria**, il gestore dell'heap **controlla prima l'unsorted bin** per vedere se c'è un chunk della dimensione corretta. Se ne trova uno, lo usa immediatamente, il che è più veloce rispetto alla ricerca in altri bins. Se non trova un chunk adatto, sposta i chunk liberati nei rispettivi bins corretti, piccoli o grandi, in base alla loro dimensione.
|
||||
|
||||
Quindi, l'unsorted bin è un modo per velocizzare l'allocazione di memoria riutilizzando rapidamente la memoria liberata di recente e riducendo la necessità di ricerche e fusioni dispendiose di tempo.
|
||||
|
||||
{% hint style="danger" %}
|
||||
Nota che anche se i chunk sono di categorie diverse, di tanto in tanto, se un chunk disponibile entra in collisione con un altro chunk disponibile (anche se sono di categorie diverse), verranno fusi.
|
||||
{% endhint %}
|
||||
|
||||
### Fast bins
|
||||
### Esempio Veloce di Heap
|
||||
|
||||
I fast bins sono progettati per **accelerare l'allocazione di memoria per chunk piccoli** mantenendo i chunk liberati di recente in una struttura di accesso rapido. Questi bins utilizzano un approccio Last-In, First-Out (LIFO), il che significa che il **chunk liberato più di recente è il primo** ad essere riutilizzato quando c'è una nuova richiesta di allocazione. Questo comportamento è vantaggioso per la velocità, poiché è più veloce inserire e rimuovere dalla cima di uno stack (LIFO) rispetto a una coda (FIFO).
|
||||
|
||||
Inoltre, **i fast bins utilizzano liste collegate singolarmente**, non doppie, il che migliora ulteriormente la velocità. Poiché i chunk nei fast bins non vengono fusi con i vicini, non c'è bisogno di una struttura complessa che permetta la rimozione dal mezzo. Una lista collegata singolarmente è più semplice e veloce per queste operazioni.
|
||||
|
||||
Fondamentalmente, ciò che accade qui è che l'intestazione (il puntatore al primo chunk da controllare) punta sempre all'ultimo chunk liberato di quella dimensione. Quindi:
|
||||
|
||||
* Quando viene allocato un nuovo chunk di quella dimensione, l'intestazione punta a un chunk libero da utilizzare. Poiché questo chunk libero punta al successivo da utilizzare, questo indirizzo viene memorizzato nell'intestazione in modo che la prossima allocazione sappia dove ottenere un chunk disponibile
|
||||
* Quando un chunk viene liberato, il chunk libero salverà l'indirizzo al chunk disponibile corrente e l'indirizzo a questo nuovo chunk liberato verrà messo nell'intestazione
|
||||
|
||||
{% hint style="danger" %}
|
||||
I chunk nei fast bins non vengono automaticamente impostati come disponibili, quindi rimangono come chunk fast bin per un po' di tempo invece di poter essere fusi con altri chunk.
|
||||
{% endhint %}
|
||||
|
||||
### Tcache (Per-Thread Cache) Bins
|
||||
|
||||
Anche se i thread cercano di avere il proprio heap (vedi [Arenas](./#arenas) e [Subheaps](./#subheaps)), c'è la possibilità che un processo con molti thread (come un server web) **finisca per condividere l'heap con altri thread**. In questo caso, la soluzione principale è l'uso di **lock**, che potrebbero **sopprimere significativamente i thread**.
|
||||
|
||||
Pertanto, una tcache è simile a un fast bin per thread nel senso che è una **lista collegata singolarmente** che non fonde i chunk. Ogni thread ha **64 tcache bins collegati singolarmente**. Ogni bin può avere un massimo di [7 chunk della stessa dimensione](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l323) che vanno da [24 a 1032B nei sistemi a 64 bit e da 12 a 516B nei sistemi a 32 bit](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l315).
|
||||
|
||||
Quando un **thread libera** un chunk, **se non è troppo grande** per essere allocato nella tcache e il rispettivo bin tcache **non è pieno** (già 7 chunk), **verrà allocato lì**. Se non può andare nella tcache, dovrà attendere il lock dell'heap per poter eseguire l'operazione di liberazione globalmente.
|
||||
|
||||
Quando viene **allocato un chunk**, se c'è un chunk libero della dimensione necessaria nella **tcache lo utilizzerà**, altrimenti dovrà attendere il lock dell'heap per poterne trovare uno nei bin globali o crearne uno nuovo.\
|
||||
C'è anche un'ottimizzazione, in questo caso, mentre si ha il lock dell'heap, il thread **riempirà la sua tcache con chunk dell'heap (7) della dimensione richiesta**, quindi nel caso ne abbia bisogno di più, li troverà nella tcache.
|
||||
### Ordine dei Bins
|
||||
|
||||
#### Per l'allocazione:
|
||||
|
||||
1. Se è disponibile un chunk nel Tcache di quella dimensione, utilizzalo
|
||||
2. Se è molto grande, utilizza mmap
|
||||
3. Ottieni il lock dell'heap dell'arena e:
|
||||
1. Se c'è abbastanza spazio di dimensioni ridotte, utilizza un chunk fast bin disponibile della dimensione richiesta, utilizzalo e riempi il tcache dal fast bin
|
||||
2. Controlla ogni voce nella lista non ordinata cercando un chunk sufficientemente grande e riempi il tcache se possibile
|
||||
3. Controlla i bin di dimensioni ridotte o grandi (in base alla dimensione richiesta) e riempi il tcache se possibile
|
||||
4. Crea un nuovo chunk dalla memoria disponibile
|
||||
1. Se non c'è memoria disponibile, ottienine di più usando `sbrk`
|
||||
2. Se la memoria principale dell'heap non può crescere ulteriormente, crea uno nuovo spazio utilizzando mmap
|
||||
5. Se niente ha funzionato, restituisci null
|
||||
|
||||
**Per la liberazione:**
|
||||
|
||||
1. Se il puntatore è Null, termina
|
||||
2. Esegui controlli di coerenza `free` nel chunk per cercare di verificarne la legittimità
|
||||
1. Se è abbastanza piccolo e il tcache non è pieno, mettilo lì
|
||||
2. Se il bit M è impostato (non nell'heap), utilizza `munmap`
|
||||
3. Ottieni il lock dell'heap dell'arena:
|
||||
1. Se si adatta a un fastbin, mettilo lì
|
||||
2. Se il chunk è > 64KB, consolidare immediatamente i fastbins e mettere i chunk uniti risultanti nel bin non ordinato.
|
||||
3. Unisci il chunk all'indietro e in avanti con i chunk liberati vicini nei bin di dimensioni ridotte, grandi e non ordinati se presenti.
|
||||
4. Se è in cima alla testa, uniscilo alla memoria non utilizzata
|
||||
5. Se non è tra quelli precedenti, memorizzalo nella lista non ordinata
|
||||
|
||||
|
||||
|
||||
\
|
||||
|
||||
Esempio rapido di heap da [https://guyinatuxedo.github.io/25-heap/index.html](https://guyinatuxedo.github.io/25-heap/index.html) ma in arm64:
|
||||
Esempio veloce di heap da [https://guyinatuxedo.github.io/25-heap/index.html](https://guyinatuxedo.github.io/25-heap/index.html) ma in arm64:
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -204,7 +170,21 @@ Gli spazi extra riservati (0x21-0x10=0x11) provengono dagli **header aggiunti**
|
|||
0x2: Is MMAPPED - Specifies that the chunk was obtained with mmap()
|
||||
0x4: Non Main Arena - Specifies that the chunk was obtained from outside of the main arena
|
||||
```
|
||||
##
|
||||
## Bins e Assegnazioni/Liberazioni di Memoria
|
||||
|
||||
Verifica quali sono i bins e come sono organizzati e come la memoria viene assegnata e liberata in:
|
||||
|
||||
{% content-ref url="bins-and-memory-allocations.md" %}
|
||||
[bins-and-memory-allocations.md](bins-and-memory-allocations.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
## Controlli di Sicurezza delle Funzioni di Heap
|
||||
|
||||
Le funzioni coinvolte nell'heap eseguiranno determinati controlli prima di eseguire le loro azioni per cercare di assicurarsi che l'heap non sia stato corrotto:
|
||||
|
||||
{% content-ref url="heap-functions-security-checks.md" %}
|
||||
[heap-functions-security-checks.md](heap-functions-security-checks.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
## Riferimenti
|
||||
|
||||
|
|
210
binary-exploitation/heap/bins-and-memory-allocations.md
Normal file
210
binary-exploitation/heap/bins-and-memory-allocations.md
Normal file
|
@ -0,0 +1,210 @@
|
|||
# Bins & Assegnazioni di Memoria
|
||||
|
||||
<details>
|
||||
|
||||
<summary><strong>Impara l'hacking di AWS da zero a eroe con</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (Esperto Red Team AWS di HackTricks)</strong></a><strong>!</strong></summary>
|
||||
|
||||
Altri modi per supportare HackTricks:
|
||||
|
||||
* Se desideri vedere la tua **azienda pubblicizzata in HackTricks** o **scaricare HackTricks in PDF** Controlla i [**PIANI DI ABBONAMENTO**](https://github.com/sponsors/carlospolop)!
|
||||
* Ottieni il [**merchandising ufficiale di PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
* Scopri [**La Famiglia PEASS**](https://opensea.io/collection/the-peass-family), la nostra collezione di [**NFT esclusivi**](https://opensea.io/collection/the-peass-family)
|
||||
* **Unisciti al** 💬 [**gruppo Discord**](https://discord.gg/hRep4RUj7f) o al [**gruppo telegram**](https://t.me/peass) o **seguici** su **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Condividi i tuoi trucchi di hacking inviando PR a** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos di github.
|
||||
|
||||
</details>
|
||||
|
||||
## Informazioni di Base
|
||||
|
||||
Per migliorare l'efficienza su come i chunk sono memorizzati, ogni chunk non è solo in una lista concatenata, ma ci sono diversi tipi. Questi sono i bins e ci sono 5 tipi di bins: [62](https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l1407) small bins, 63 large bins, 1 unsorted bin, 10 fast bins e 64 tcache bins per thread.
|
||||
|
||||
L'indirizzo iniziale per ogni bin non ordinato, small e large è all'interno dello stesso array. L'indice 0 non è utilizzato, 1 è l'unsorted bin, i bins 2-64 sono small bins e i bins 65-127 sono large bins.
|
||||
|
||||
### Small Bins
|
||||
|
||||
I small bins sono più veloci dei large bins ma più lenti dei fast bins.
|
||||
|
||||
Ogni bin dei 62 avrà **chunk della stessa dimensione**: 16, 24, ... (con una dimensione massima di 504 byte in 32 bit e 1024 in 64 bit). Questo aiuta nella velocità nel trovare il bin in cui dovrebbe essere allocato uno spazio e nell'inserimento e rimozione delle voci in queste liste.
|
||||
|
||||
### Large Bins
|
||||
|
||||
A differenza dei small bins, che gestiscono chunk di dimensioni fisse, ogni **large bin gestisce un intervallo di dimensioni di chunk**. Questo è più flessibile, consentendo al sistema di ospitare **varie dimensioni** senza la necessità di un bin separato per ogni dimensione.
|
||||
|
||||
In un allocatore di memoria, i large bins iniziano dove finiscono i small bins. Gli intervalli per i large bins crescono progressivamente, il che significa che il primo bin potrebbe coprire chunk da 512 a 576 byte, mentre il successivo copre da 576 a 640 byte. Questo modello continua, con il bin più grande che contiene tutti i chunk sopra 1MB.
|
||||
|
||||
I large bins sono più lenti da gestire rispetto ai small bins perché devono **ordinare e cercare in una lista di dimensioni di chunk variabili per trovare la migliore corrispondenza** per un'allocazione. Quando un chunk viene inserito in un large bin, deve essere ordinato e quando viene allocata memoria, il sistema deve trovare il chunk giusto. Questo lavoro aggiuntivo li rende **più lenti**, ma poiché le allocazioni di grandi dimensioni sono meno comuni di quelle piccole, è un compromesso accettabile.
|
||||
|
||||
Ci sono:
|
||||
|
||||
* 32 bins di intervallo 64B
|
||||
* 16 bins di intervallo 512B
|
||||
* 8 bins di intervallo 4096B
|
||||
* 4 bins di intervallo 32768B
|
||||
* 2 bins di intervallo 262144B
|
||||
* 1 bin per dimensioni rimanenti
|
||||
|
||||
### Unsorted Bin
|
||||
|
||||
L'unsorted bin è una **cache veloce** utilizzata dal gestore dell'heap per rendere più veloce l'allocazione di memoria. Ecco come funziona: quando un programma libera memoria, il gestore dell'heap non la mette immediatamente in un bin specifico. Invece, cerca prima di **unirla con eventuali chunk liberi adiacenti** per creare un blocco più grande di memoria libera. Quindi, inserisce questo nuovo chunk in un bin generale chiamato "unsorted bin".
|
||||
|
||||
Quando un programma **richiede memoria**, il gestore dell'heap **controlla l'unsorted bin** per vedere se c'è un chunk di dimensioni adeguate. Se ne trova uno, lo utilizza immediatamente. Se non trova un chunk adatto, sposta i chunk liberati nei rispettivi bins, sia small che large, in base alla loro dimensione.
|
||||
|
||||
Quindi, l'unsorted bin è un modo per velocizzare l'allocazione di memoria riutilizzando rapidamente la memoria liberata di recente e riducendo la necessità di ricerche e fusioni che richiedono tempo.
|
||||
|
||||
{% hint style="danger" %}
|
||||
Nota che anche se i chunk sono di categorie diverse, se un chunk disponibile entra in collisione con un altro chunk disponibile (anche se sono di categorie diverse), verranno uniti.
|
||||
{% endhint %}
|
||||
|
||||
### Fast Bins
|
||||
|
||||
I fast bins sono progettati per **accelerare l'allocazione di memoria per chunk piccoli** mantenendo i chunk liberati di recente in una struttura di accesso rapido. Questi bins utilizzano un approccio Last-In, First-Out (LIFO), il che significa che il **chunk liberato più di recente è il primo** ad essere riutilizzato quando c'è una nuova richiesta di allocazione. Questo comportamento è vantaggioso per la velocità, poiché è più veloce inserire e rimuovere dalla cima di uno stack (LIFO) rispetto a una coda (FIFO).
|
||||
|
||||
Inoltre, **i fast bins utilizzano liste collegate singolarmente**, non doppie, il che migliora ulteriormente la velocità. Poiché i chunk nei fast bins non vengono uniti con i vicini, non c'è bisogno di una struttura complessa che consenta la rimozione dal mezzo. Una lista collegata singolarmente è più semplice e veloce per queste operazioni.
|
||||
|
||||
Fondamentalmente, ciò che accade qui è che l'intestazione (il puntatore al primo chunk da controllare) punta sempre all'ultimo chunk liberato di quella dimensione. Quindi:
|
||||
|
||||
* Quando viene allocato un nuovo chunk di quella dimensione, l'intestazione punta a un chunk libero da utilizzare. Poiché questo chunk libero punta al successivo da utilizzare, questo indirizzo viene memorizzato nell'intestazione in modo che la prossima allocazione sappia dove ottenere un chunk disponibile
|
||||
* Quando un chunk viene liberato, il chunk libero salverà l'indirizzo al chunk disponibile corrente e l'indirizzo a questo nuovo chunk liberato verrà messo nell'intestazione
|
||||
|
||||
{% hint style="danger" %}
|
||||
I chunk nei fast bins non vengono automaticamente impostati come disponibili, quindi rimangono come chunk fast bin per un po' di tempo invece di poter essere uniti con altri chunk.
|
||||
{% endhint %}
|
||||
|
||||
### Tcache (Cache Per-Thread)
|
||||
|
||||
Anche se i thread cercano di avere il proprio heap (vedi [Arenas](bins-and-memory-allocations.md#arenas) e [Subheaps](bins-and-memory-allocations.md#subheaps)), c'è la possibilità che un processo con molti thread (come un server web) **finirà per condividere l'heap con altri thread**. In questo caso, la soluzione principale è l'uso di **lock**, che potrebbero **sopprimere significativamente i thread**.
|
||||
|
||||
Pertanto, una tcache è simile a un fast bin per thread nel senso che è una **lista collegata singolarmente** che non unisce i chunk. Ogni thread ha **64 tcache bins collegati singolarmente**. Ogni bin può avere un massimo di [7 chunk della stessa dimensione](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l323) che vanno da [24 a 1032B nei sistemi a 64 bit e da 12 a 516B nei sistemi a 32 bit](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l315).
|
||||
|
||||
**Quando un thread libera** un chunk, **se non è troppo grande** da essere allocato nella tcache e il rispettivo bin tcache **non è pieno** (già 7 chunk), **verrà allocato lì**. Se non può andare nella tcache, dovrà attendere il lock dell'heap per poter eseguire l'operazione di liberazione globalmente.
|
||||
|
||||
Quando viene **allocato un chunk**, se c'è un chunk libero della dimensione necessaria nella **tcache lo utilizzerà**, altrimenti dovrà attendere il lock dell'heap per poterne trovare uno nei bin globali o crearne uno nuovo.\
|
||||
C'è anche un'ottimizzazione, in questo caso, mentre ha il lock dell'heap, il thread **riempirà la sua tcache con chunk dell'heap (7) della dimensione richiesta**, quindi nel caso ne abbia bisogno di più, li troverà nella tcache.
|
||||
## Flusso di Allocazione
|
||||
|
||||
{% hint style="success" %}
|
||||
(Questa spiegazione attuale proviene da [https://heap-exploitation.dhavalkapil.com/diving\_into\_glibc\_heap/core\_functions](https://heap-exploitation.dhavalkapil.com/diving\_into\_glibc\_heap/core\_functions). TODO: Controllare l'ultima versione e aggiornarla)
|
||||
{% endhint %}
|
||||
|
||||
Le allocazioni vengono infine eseguite con la funzione: `void * _int_malloc (mstate av, size_t bytes)` e seguono questo ordine:
|
||||
|
||||
1. Aggiorna `bytes` per gestire **allineamenti**, ecc.
|
||||
2. Controlla se `av` è **NULL** o meno.
|
||||
3. Nel caso di assenza di **arena utilizzabile** (quando `av` è NULL), chiama `sysmalloc` per ottenere un chunk usando mmap. Se ha successo, chiama `alloc_perturb`. Restituisce il puntatore.
|
||||
4. A seconda della dimensione:
|
||||
* \[Aggiunta all'originale] Usa tcache prima di controllare il prossimo fastbin.
|
||||
* \[Aggiunta all'originale] Se non c'è tcache ma viene utilizzato un bin diverso (vedi passaggio successivo), cerca di riempire la tcache da quel bin.
|
||||
* Se la dimensione rientra nell'intervallo del **fastbin**:
|
||||
1. Ottieni l'indice nell'array fastbin per accedere a un bin appropriato in base alla dimensione richiesta.
|
||||
2. Rimuove il primo chunk in quel bin e fa puntare `victim` ad esso.
|
||||
3. Se `victim` è NULL, passa al caso successivo (smallbin).
|
||||
4. Se `victim` non è NULL, controlla la dimensione del chunk per assicurarti che appartenga a quel particolare bin. Altrimenti viene generato un errore ("malloc(): memory corruption (fast)").
|
||||
5. Chiama `alloc_perturb` e quindi restituisce il puntatore.
|
||||
* Se la dimensione rientra nell'intervallo dello **smallbin**:
|
||||
1. Ottieni l'indice nell'array smallbin per accedere a un bin appropriato in base alla dimensione richiesta.
|
||||
2. Se non ci sono chunk in questo bin, passa al caso successivo. Questo viene verificato confrontando i puntatori `bin` e `bin->bk`.
|
||||
3. `victim` viene reso uguale a `bin->bk` (l'ultimo chunk nel bin). Se è NULL (avviene durante l'`inizializzazione`), chiama `malloc_consolidate` e salta questo passaggio completo di controllo in bin diversi.
|
||||
4. Altrimenti, quando `victim` non è NULL, controlla se `victim->bk->fd` e `victim` sono uguali o meno. Se non sono uguali, viene generato un errore (`malloc(): smallbin double linked list corrupted`).
|
||||
5. Imposta il bit PREV\_INSUSE per il prossimo chunk (in memoria, non nella lista doppiamente concatenata) per `victim`.
|
||||
6. Rimuovi questo chunk dall'elenco del bin.
|
||||
7. Imposta il bit di arena appropriato per questo chunk in base a `av`.
|
||||
8. Chiama `alloc_perturb` e quindi restituisce il puntatore.
|
||||
* Se la dimensione non rientra nell'intervallo dello smallbin:
|
||||
1. Ottieni l'indice nell'array largebin per accedere a un bin appropriato in base alla dimensione richiesta.
|
||||
2. Verifica se `av` ha fastchunks o meno. Questo viene fatto controllando il `FASTCHUNKS_BIT` in `av->flags`. In tal caso, chiama `malloc_consolidate` su `av`.
|
||||
5. Se non è ancora stato restituito alcun puntatore, ciò indica uno o più dei seguenti casi:
|
||||
1. La dimensione rientra nell'intervallo 'fastbin' ma non è disponibile alcun fastchunk.
|
||||
2. La dimensione rientra nell'intervallo 'smallbin' ma non è disponibile alcun smallchunk (chiama `malloc_consolidate` durante l'inizializzazione).
|
||||
3. La dimensione rientra nell'intervallo 'largbin'.
|
||||
6. Successivamente, vengono controllati gli **unsorted chunks** e i chunk attraversati vengono inseriti nei bin. Questo è l'unico punto in cui i chunk vengono inseriti nei bin. Itera il bin non ordinato dalla 'TAIL'.
|
||||
1. `victim` punta al chunk attuale in considerazione.
|
||||
2. Controlla se la dimensione del chunk di `victim` è compresa nell'intervallo minimo (`2*SIZE_SZ`) e massimo (`av->system_mem`). Altrimenti viene generato un errore (`malloc(): memory corruption`).
|
||||
3. Se (la dimensione del chunk richiesta rientra nell'intervallo dello smallbin) e (`victim` è l'ultimo chunk rimanente) e (è l'unico chunk nel bin non ordinato) e (la dimensione dei chunk >= quella richiesta): **Dividi il chunk in 2 chunk**:
|
||||
* Il primo chunk corrisponde alla dimensione richiesta e viene restituito.
|
||||
* Il chunk residuo diventa il nuovo ultimo chunk rimanente. Viene reinserito nel bin non ordinato.
|
||||
1. Imposta correttamente i campi `chunk_size` e `chunk_prev_size` per entrambi i chunk.
|
||||
2. Il primo chunk viene restituito dopo aver chiamato `alloc_perturb`.
|
||||
3. Se la condizione precedente è falsa, il controllo arriva qui. Rimuovi `victim` dal bin non ordinato. Se la dimensione di `victim` corrisponde esattamente alla dimensione richiesta, restituisci questo chunk dopo aver chiamato `alloc_perturb`.
|
||||
4. Se la dimensione di `victim` rientra nell'intervallo dello smallbin, aggiungi il chunk nell'appropriato smallbin alla `HEAD`.
|
||||
5. Altrimenti inserisci nell'appropriato largebin mantenendo l'ordine ordinato:
|
||||
6. Controlla prima l'ultimo chunk (il più piccolo). Se `victim` è più piccolo dell'ultimo chunk, inseriscilo alla fine.
|
||||
7. Altrimenti, fai un loop per trovare un chunk con dimensione >= dimensione di `victim`. Se le dimensioni sono esattamente le stesse, inserisci sempre nella seconda posizione.
|
||||
8. Ripeti questo intero passaggio un massimo di `MAX_ITERS` (10000) volte o fino a quando tutti i chunk nel bin non ordinato vengono esauriti.
|
||||
7. Dopo aver controllato i chunk non ordinati, verifica se la dimensione richiesta non rientra nell'intervallo dello smallbin, in tal caso controlla i **largebins**.
|
||||
1. Ottieni l'indice nell'array largebin per accedere a un bin appropriato in base alla dimensione richiesta.
|
||||
2. Se la dimensione del chunk più grande (il primo chunk nel bin) è maggiore della dimensione richiesta:
|
||||
1. Itera dalla 'TAIL' per trovare un chunk (`victim`) con la dimensione più piccola >= la dimensione richiesta.
|
||||
2. Chiama `unlink` per rimuovere il chunk `victim` dal bin.
|
||||
3. Calcola `remainder_size` per il chunk di `victim` (questo sarà la dimensione del chunk di `victim` - dimensione richiesta).
|
||||
4. Se questo `remainder_size` >= `MINSIZE` (la dimensione minima del chunk inclusi gli header), dividi il chunk in due chunk. Altrimenti, l'intero chunk di `victim` verrà restituito. Inserisci il chunk residuo nel bin non ordinato (alla fine di 'TAIL'). Viene effettuato un controllo nel bin non ordinato se `unsorted_chunks(av)->fd->bk == unsorted_chunks(av)`. Altrimenti viene generato un errore ("malloc(): corrupted unsorted chunks").
|
||||
5. Restituisci il chunk `victim` dopo aver chiamato `alloc_perturb`.
|
||||
8. Fino a questo momento, abbiamo controllato il bin non ordinato e anche il rispettivo fast, small o large bin. Nota che un singolo bin (fast o small) è stato controllato utilizzando la dimensione **esatta** del chunk richiesto. Ripeti i seguenti passaggi fino a quando tutti i bin vengono esauriti:
|
||||
1. L'indice nell'array bin viene incrementato per controllare il bin successivo.
|
||||
2. Usa la mappa `av->binmap` per saltare i bin vuoti.
|
||||
3. `victim` punta alla 'TAIL' del bin corrente.
|
||||
4. Utilizzando la binmap si assicura che se un bin viene saltato (nel passaggio 2 precedente), è sicuramente vuoto. Tuttavia, non garantisce che tutti i bin vuoti verranno saltati. Controlla se il victim è vuoto o meno. Se è vuoto, salta nuovamente il bin e ripeti il processo sopra (o 'continua' questo loop) fino a quando non si arriva a un bin non vuoto.
|
||||
5. Dividi il chunk (`victim` punta all'ultimo chunk di un bin non vuoto) in due chunk. Inserisci il chunk residuo nel bin non ordinato (alla fine di 'TAIL'). Viene effettuato un controllo nel bin non ordinato se `unsorted_chunks(av)->fd->bk == unsorted_chunks(av)`. Altrimenti viene generato un errore ("malloc(): corrupted unsorted chunks 2").
|
||||
6. Restituisci il chunk `victim` dopo aver chiamato `alloc_perturb`.
|
||||
9. Se ancora non viene trovato alcun bin vuoto, il chunk 'top' verrà utilizzato per soddisfare la richiesta:
|
||||
1. `victim` punta a `av->top`.
|
||||
2. Se la dimensione del chunk 'top' >= 'dimensione richiesta' + `MINSIZE`, dividilo in due chunk. In questo caso, il chunk residuo diventa il nuovo chunk 'top' e l'altro chunk viene restituito all'utente dopo aver chiamato `alloc_perturb`.
|
||||
3. Verifica se `av` ha fastchunks o meno. Questo viene fatto controllando il `FASTCHUNKS_BIT` in `av->flags`. In tal caso, chiama `malloc_consolidate` su `av`. Torna al passaggio 6 (dove controlliamo il bin non ordinato).
|
||||
4. Se `av` non ha fastchunks, chiama `sysmalloc` e restituisci il puntatore ottenuto dopo aver chiamato `alloc_perturb`.
|
||||
## Flusso Gratuito
|
||||
|
||||
{% hint style="success" %}
|
||||
(Questa spiegazione attuale proviene da [https://heap-exploitation.dhavalkapil.com/diving\_into\_glibc\_heap/core\_functions](https://heap-exploitation.dhavalkapil.com/diving\_into\_glibc\_heap/core\_functions). TODO: Controllare l'ultima versione e aggiornarla)
|
||||
{% endhint %}
|
||||
|
||||
La funzione finale che libera i chunk di memoria è `_int_free (mstate av, mchunkptr p, int have_lock)` :
|
||||
|
||||
1. Controlla se `p` si trova prima di `p + chunksize(p)` in memoria (per evitare il wrapping). Altrimenti viene generato un errore (`free(): invalid pointer`).
|
||||
2. Controlla se il chunk è di almeno dimensione `MINSIZE` o un multiplo di `MALLOC_ALIGNMENT`. Altrimenti viene generato un errore (`free(): invalid size`).
|
||||
3. Se la dimensione del chunk rientra nella lista fastbin:
|
||||
1. Controlla se la dimensione del chunk successivo è compresa tra la dimensione minima e massima (`av->system_mem`), altrimenti genera un errore (`free(): invalid next size (fast)`).
|
||||
2. Chiama `free_perturb` sul chunk.
|
||||
3. Imposta `FASTCHUNKS_BIT` per `av`.
|
||||
4. Ottiene l'indice nell'array fastbin in base alla dimensione del chunk.
|
||||
5. Controlla se la cima del bin non è il chunk che stiamo per aggiungere. Altrimenti, genera un errore (`double free or corruption (fasttop)`).
|
||||
6. Controlla se la dimensione del chunk fastbin in cima è la stessa del chunk che stiamo aggiungendo. Altrimenti, genera un errore (`invalid fastbin entry (free)`).
|
||||
7. Inserisce il chunk in cima alla lista fastbin e restituisce.
|
||||
4. Se il chunk non è mappato:
|
||||
1. Controlla se il chunk è il chunk in cima o meno. Se sì, viene generato un errore (`double free or corruption (top)`).
|
||||
2. Controlla se il chunk successivo (per memoria) rientra nei limiti dell'arena. Se non lo fa, viene generato un errore (`double free or corruption (out)`).
|
||||
3. Controlla se il bit precedente in uso del chunk successivo (per memoria) è contrassegnato o meno. Se non lo è, viene generato un errore (`double free or corruption (!prev)`).
|
||||
4. Controlla se la dimensione del chunk successivo è compresa tra la dimensione minima e massima (`av->system_mem`). Se non lo è, viene generato un errore (`free(): invalid next size (normal)`).
|
||||
5. Chiama `free_perturb` sul chunk.
|
||||
6. Se il chunk precedente (per memoria) non è in uso, chiama `unlink` sul chunk precedente.
|
||||
7. Se il chunk successivo (per memoria) non è il chunk in cima:
|
||||
1. Se il chunk successivo non è in uso, chiama `unlink` sul chunk successivo.
|
||||
2. Unisce il chunk con il precedente, il successivo (per memoria), se presente, è libero e lo aggiunge all'inizio del bin non ordinato. Prima di inserire, controlla se `unsorted_chunks(av)->fd->bk == unsorted_chunks(av)` o no. Se no, viene generato un errore ("free(): corrupted unsorted chunks").
|
||||
8. Se il chunk successivo (per memoria) era un chunk in cima, unisce i chunk in modo appropriato in un unico chunk in cima.
|
||||
5. Se il chunk era mappato, chiama `munmap_chunk`.
|
||||
|
||||
## Controlli di Sicurezza delle Funzioni di Heap
|
||||
|
||||
Controlla i controlli di sicurezza eseguiti dalle funzioni ampiamente utilizzate nell'heap in:
|
||||
|
||||
{% content-ref url="heap-functions-security-checks.md" %}
|
||||
[heap-functions-security-checks.md](heap-functions-security-checks.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
## Riferimenti
|
||||
|
||||
* [https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/](https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/)
|
||||
* [https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/](https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/)
|
||||
* [https://heap-exploitation.dhavalkapil.com/diving\_into\_glibc\_heap/core\_functions](https://heap-exploitation.dhavalkapil.com/diving\_into\_glibc\_heap/core\_functions)
|
||||
|
||||
<details>
|
||||
|
||||
<summary><strong>Impara l'hacking di AWS da zero a eroe con</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
||||
|
||||
Altri modi per supportare HackTricks:
|
||||
|
||||
* Se desideri vedere la tua **azienda pubblicizzata in HackTricks** o **scaricare HackTricks in PDF** Controlla i [**PIANI DI ABBONAMENTO**](https://github.com/sponsors/carlospolop)!
|
||||
* Ottieni il [**merchandising ufficiale PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
* Scopri [**The PEASS Family**](https://opensea.io/collection/the-peass-family), la nostra collezione di [**NFT esclusivi**](https://opensea.io/collection/the-peass-family)
|
||||
* **Unisciti al** 💬 [**gruppo Discord**](https://discord.gg/hRep4RUj7f) o al [**gruppo telegram**](https://t.me/peass) o **seguici** su **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Condividi i tuoi trucchi di hacking inviando PR a** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
|
||||
</details>
|
138
binary-exploitation/heap/double-free.md
Normal file
138
binary-exploitation/heap/double-free.md
Normal file
|
@ -0,0 +1,138 @@
|
|||
# Doppia Liberazione
|
||||
|
||||
<details>
|
||||
|
||||
<summary><strong>Impara l'hacking su AWS da zero a eroe con</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (Esperto Red Team AWS di HackTricks)</strong></a><strong>!</strong></summary>
|
||||
|
||||
Altri modi per supportare HackTricks:
|
||||
|
||||
* Se desideri vedere la tua **azienda pubblicizzata su HackTricks** o **scaricare HackTricks in PDF** Controlla i [**PIANI DI ABBONAMENTO**](https://github.com/sponsors/carlospolop)!
|
||||
* Ottieni il [**merchandising ufficiale di PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
* Scopri [**La Famiglia PEASS**](https://opensea.io/collection/the-peass-family), la nostra collezione di [**NFT esclusivi**](https://opensea.io/collection/the-peass-family)
|
||||
* **Unisciti al** 💬 [**gruppo Discord**](https://discord.gg/hRep4RUj7f) o al [**gruppo telegram**](https://t.me/peass) o **seguici** su **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Condividi i tuoi trucchi di hacking inviando PR a** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos di github.
|
||||
|
||||
</details>
|
||||
|
||||
## Informazioni di Base
|
||||
|
||||
Se liberi un blocco di memoria più di una volta, può compromettere i dati dell'allocatore e aprire la porta agli attacchi. Ecco come avviene: quando liberi un blocco di memoria, ritorna in una lista di chunk liberi (ad esempio il "fastbin"). Se liberi lo stesso blocco due volte di seguito, l'allocatore rileva questo e genera un errore. Ma se **liberi un altro chunk nel mezzo, il controllo di doppia liberazione viene eluso**, causando corruzione.
|
||||
|
||||
Ora, quando richiedi nuova memoria (usando `malloc`), l'allocatore potrebbe darti un **blocco che è stato liberato due volte**. Ciò può portare a due puntatori diversi che puntano alla stessa posizione di memoria. Se un attaccante controlla uno di quei puntatori, può modificare il contenuto di quella memoria, il che può causare problemi di sicurezza o addirittura consentire l'esecuzione di codice.
|
||||
|
||||
Esempio:
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main() {
|
||||
// Allocate memory for three chunks
|
||||
char *a = (char *)malloc(10);
|
||||
char *b = (char *)malloc(10);
|
||||
char *c = (char *)malloc(10);
|
||||
char *d = (char *)malloc(10);
|
||||
char *e = (char *)malloc(10);
|
||||
char *f = (char *)malloc(10);
|
||||
char *g = (char *)malloc(10);
|
||||
char *h = (char *)malloc(10);
|
||||
char *i = (char *)malloc(10);
|
||||
|
||||
// Print initial memory addresses
|
||||
printf("Initial allocations:\n");
|
||||
printf("a: %p\n", (void *)a);
|
||||
printf("b: %p\n", (void *)b);
|
||||
printf("c: %p\n", (void *)c);
|
||||
printf("d: %p\n", (void *)d);
|
||||
printf("e: %p\n", (void *)e);
|
||||
printf("f: %p\n", (void *)f);
|
||||
printf("g: %p\n", (void *)g);
|
||||
printf("h: %p\n", (void *)h);
|
||||
printf("i: %p\n", (void *)i);
|
||||
|
||||
// Fill tcache
|
||||
free(a);
|
||||
free(b);
|
||||
free(c);
|
||||
free(d);
|
||||
free(e);
|
||||
free(f);
|
||||
free(g);
|
||||
|
||||
// Introduce double-free vulnerability in fast bin
|
||||
free(h);
|
||||
free(i);
|
||||
free(h);
|
||||
|
||||
|
||||
// Reallocate memory and print the addresses
|
||||
char *a1 = (char *)malloc(10);
|
||||
char *b1 = (char *)malloc(10);
|
||||
char *c1 = (char *)malloc(10);
|
||||
char *d1 = (char *)malloc(10);
|
||||
char *e1 = (char *)malloc(10);
|
||||
char *f1 = (char *)malloc(10);
|
||||
char *g1 = (char *)malloc(10);
|
||||
char *h1 = (char *)malloc(10);
|
||||
char *i1 = (char *)malloc(10);
|
||||
char *i2 = (char *)malloc(10);
|
||||
|
||||
// Print initial memory addresses
|
||||
printf("After reallocations:\n");
|
||||
printf("a1: %p\n", (void *)a1);
|
||||
printf("b1: %p\n", (void *)b1);
|
||||
printf("c1: %p\n", (void *)c1);
|
||||
printf("d1: %p\n", (void *)d1);
|
||||
printf("e1: %p\n", (void *)e1);
|
||||
printf("f1: %p\n", (void *)f1);
|
||||
printf("g1: %p\n", (void *)g1);
|
||||
printf("h1: %p\n", (void *)h1);
|
||||
printf("i1: %p\n", (void *)i1);
|
||||
printf("i2: %p\n", (void *)i1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
In questo esempio, dopo aver riempito la tcache con diversi chunk liberati, il codice **libera il chunk `h`, poi il chunk `i`, e poi di nuovo `h`, causando un errore di double-free**. Questo apre la possibilità di ricevere sovrapposizioni di indirizzi di memoria durante il riallocazione, il che significa che due o più puntatori possono puntare alla stessa posizione di memoria. Manipolare i dati attraverso un puntatore può quindi influenzare l'altro, creando un rischio critico per la sicurezza e un potenziale per l'exploit.
|
||||
|
||||
Eseguendolo, nota come **`i1` e `i2` abbiano lo stesso indirizzo**:
|
||||
|
||||
<pre><code>Assegnazioni iniziali:
|
||||
a: 0xaaab0f0c22a0
|
||||
b: 0xaaab0f0c22c0
|
||||
c: 0xaaab0f0c22e0
|
||||
d: 0xaaab0f0c2300
|
||||
e: 0xaaab0f0c2320
|
||||
f: 0xaaab0f0c2340
|
||||
g: 0xaaab0f0c2360
|
||||
h: 0xaaab0f0c2380
|
||||
i: 0xaaab0f0c23a0
|
||||
Dopo le riallocazioni:
|
||||
a1: 0xaaab0f0c2360
|
||||
b1: 0xaaab0f0c2340
|
||||
c1: 0xaaab0f0c2320
|
||||
d1: 0xaaab0f0c2300
|
||||
e1: 0xaaab0f0c22e0
|
||||
f1: 0xaaab0f0c22c0
|
||||
g1: 0xaaab0f0c22a0
|
||||
h1: 0xaaab0f0c2380
|
||||
<strong>i1: 0xaaab0f0c23a0
|
||||
</strong><strong>i2: 0xaaab0f0c23a0
|
||||
</strong></code></pre>
|
||||
|
||||
## Riferimenti
|
||||
|
||||
* [https://heap-exploitation.dhavalkapil.com/attacks/double\_free](https://heap-exploitation.dhavalkapil.com/attacks/double\_free)
|
||||
|
||||
<details>
|
||||
|
||||
<summary><strong>Impara l'hacking su AWS da zero a esperto con</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
||||
|
||||
Altri modi per supportare HackTricks:
|
||||
|
||||
* Se vuoi vedere la tua **azienda pubblicizzata in HackTricks** o **scaricare HackTricks in PDF** Controlla i [**PIANI DI ABBONAMENTO**](https://github.com/sponsors/carlospolop)!
|
||||
* Ottieni il [**merchandising ufficiale PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
* Scopri [**The PEASS Family**](https://opensea.io/collection/the-peass-family), la nostra collezione di [**NFT esclusivi**](https://opensea.io/collection/the-peass-family)
|
||||
* **Unisciti al** 💬 [**gruppo Discord**](https://discord.gg/hRep4RUj7f) o al [**gruppo telegram**](https://t.me/peass) o **seguici** su **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Condividi i tuoi trucchi di hacking inviando PR ai** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos di github.
|
||||
|
||||
</details>
|
92
binary-exploitation/heap/heap-functions-security-checks.md
Normal file
92
binary-exploitation/heap/heap-functions-security-checks.md
Normal file
|
@ -0,0 +1,92 @@
|
|||
# Controlli di sicurezza delle funzioni di heap
|
||||
|
||||
<details>
|
||||
|
||||
<summary><strong>Impara l'hacking di AWS da zero a eroe con</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (Esperto Red Team AWS di HackTricks)</strong></a><strong>!</strong></summary>
|
||||
|
||||
Altri modi per supportare HackTricks:
|
||||
|
||||
* Se vuoi vedere la **tua azienda pubblicizzata in HackTricks** o **scaricare HackTricks in PDF** Controlla i [**PIANI DI ABBONAMENTO**](https://github.com/sponsors/carlospolop)!
|
||||
* Ottieni il [**merchandising ufficiale di PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
* Scopri [**La Famiglia PEASS**](https://opensea.io/collection/the-peass-family), la nostra collezione di [**NFT esclusivi**](https://opensea.io/collection/the-peass-family)
|
||||
* **Unisciti al** 💬 [**gruppo Discord**](https://discord.gg/hRep4RUj7f) o al [**gruppo telegram**](https://t.me/peass) o **seguici** su **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Condividi i tuoi trucchi di hacking inviando PR ai** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos di github.
|
||||
|
||||
</details>
|
||||
|
||||
## unlink
|
||||
|
||||
Questa funzione rimuove un chunk da una lista doppiamente collegata. I controlli comuni garantiscono che la struttura della lista collegata rimanga consistente durante lo scollegamento dei chunk.
|
||||
|
||||
* **Controlli di coerenza**:
|
||||
* Verifica se `P->fd->bk == P` e `P->bk->fd == P`.
|
||||
* Messaggio di errore: `corrupted double-linked list`
|
||||
|
||||
## \_int\_malloc
|
||||
|
||||
Questa funzione è responsabile dell'allocazione di memoria dall'heap. I controlli qui garantiscono che la memoria non venga corrotta durante l'allocazione.
|
||||
|
||||
* **Controllo della dimensione di Fastbin**:
|
||||
* Quando si rimuove un chunk da un fastbin, assicurarsi che la dimensione del chunk sia all'interno dell'intervallo del fastbin.
|
||||
* Messaggio di erroro: `malloc(): memory corruption (fast)`
|
||||
* **Controllo di coerenza di Smallbin**:
|
||||
* Quando si rimuove un chunk da un smallbin, assicurarsi che i collegamenti precedenti e successivi nella lista doppiamente collegata siano coerenti.
|
||||
* Messaggio di errore: `malloc(): smallbin double linked list corrupted`
|
||||
* **Controllo dell'intervallo di memoria di Unsorted Bin**:
|
||||
* Assicurarsi che la dimensione dei chunk nell'unsorted bin sia all'interno dei limiti minimi e massimi.
|
||||
* Messaggio di errore: `malloc(): memory corruption`
|
||||
* **Controllo di coerenza di Unsorted Bin (Primo Scenario)**:
|
||||
* Quando si inserisce un chunk di resto nell'unsorted bin, controllare se `unsorted_chunks(av)->fd->bk == unsorted_chunks(av)`.
|
||||
* Messaggio di errore: `malloc(): corrupted unsorted chunks`
|
||||
* **Controllo di coerenza di Unsorted Bin (Secondo Scenario)**:
|
||||
* Come il controllo precedente, ma attivato quando si inserisce dopo aver diviso un chunk veloce o piccolo.
|
||||
* Messaggio di errore: `malloc(): corrupted unsorted chunks 2`
|
||||
|
||||
## \_int\_free
|
||||
|
||||
Questa funzione libera la memoria precedentemente allocata. I controlli qui aiutano a garantire una corretta deallocazione della memoria e a prevenire la corruzione della memoria.
|
||||
|
||||
* **Controllo del limite del puntatore**:
|
||||
* Assicurarsi che il puntatore che viene liberato non si avvolga attorno alla memoria.
|
||||
* Messaggio di errore: `free(): invalid pointer`
|
||||
* **Controllo della dimensione**:
|
||||
* Assicurarsi che la dimensione del chunk che viene liberato sia almeno `MINSIZE` o un multiplo di `MALLOC_ALIGNMENT`.
|
||||
* Messaggio di errore: `free(): invalid size`
|
||||
* **Controllo della dimensione di Fastbin**:
|
||||
* Per i chunk di fastbin, assicurarsi che la dimensione del chunk successivo sia all'interno dei limiti minimi e massimi.
|
||||
* Messaggio di errore: `free(): invalid next size (fast)`
|
||||
* **Controllo di Double Free di Fastbin**:
|
||||
* Quando si inserisce un chunk in un fastbin, assicurarsi che il chunk in testa non sia lo stesso di quello che viene inserito.
|
||||
* Messaggio di errore: `double free or corruption (fasttop)`
|
||||
* **Controllo di coerenza di Fastbin**:
|
||||
* Quando si inserisce in un fastbin, assicurarsi che le dimensioni del chunk in testa e del chunk che viene inserito siano le stesse.
|
||||
* Messaggio di errore: `invalid fastbin entry (free)`
|
||||
* **Controllo di coerenza del Top Chunk**:
|
||||
* Per i chunk non di fastbin, assicurarsi che il chunk non sia lo stesso del top chunk.
|
||||
* Messaggio di errore: `double free or corruption (top)`
|
||||
* **Controllo dei limiti di memoria**:
|
||||
* Assicurarsi che il chunk successivo per memoria sia all'interno dei limiti dell'arena.
|
||||
* Messaggio di errore: `double free or corruption (out)`
|
||||
* **Controllo del bit Prev\_inuse**:
|
||||
* Assicurarsi che il bit precedente-in-uso nel chunk successivo sia contrassegnato.
|
||||
* Messaggio di errore: `double free or corruption (!prev)`
|
||||
* **Controllo della dimensione normale**:
|
||||
* Assicurarsi che la dimensione del chunk successivo sia all'interno di intervalli validi.
|
||||
* Messaggio di errore: `free(): invalid next size (normal)`
|
||||
* **Controllo di coerenza di Unsorted Bin**:
|
||||
* Quando si inserisce un chunk fuso nell'unsorted bin, controllare se `unsorted_chunks(av)->fd->bk == unsorted_chunks(av)`.
|
||||
* Messaggio di errore: `free(): corrupted unsorted chunks`
|
||||
|
||||
<details>
|
||||
|
||||
<summary><strong>Impara l'hacking di AWS da zero a eroe con</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (Esperto Red Team AWS di HackTricks)</strong></a><strong>!</strong></summary>
|
||||
|
||||
Altri modi per supportare HackTricks:
|
||||
|
||||
* Se vuoi vedere la **tua azienda pubblicizzata in HackTricks** o **scaricare HackTricks in PDF** Controlla i [**PIANI DI ABBONAMENTO**](https://github.com/sponsors/carlospolop)!
|
||||
* Ottieni il [**merchandising ufficiale di PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
* Scopri [**La Famiglia PEASS**](https://opensea.io/collection/the-peass-family), la nostra collezione di [**NFT esclusivi**](https://opensea.io/collection/the-peass-family)
|
||||
* **Unisciti al** 💬 [**gruppo Discord**](https://discord.gg/hRep4RUj7f) o al [**gruppo telegram**](https://t.me/peass) o **seguici** su **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Condividi i tuoi trucchi di hacking inviando PR ai** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos di github.
|
||||
|
||||
</details>
|
|
@ -7,16 +7,16 @@
|
|||
Altri modi per supportare HackTricks:
|
||||
|
||||
* Se vuoi vedere la tua **azienda pubblicizzata su HackTricks** o **scaricare HackTricks in PDF** Controlla i [**PIANI DI ABBONAMENTO**](https://github.com/sponsors/carlospolop)!
|
||||
* Ottieni il [**merchandising ufficiale PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
* Ottieni il [**merchandising ufficiale di PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
* Scopri [**La Famiglia PEASS**](https://opensea.io/collection/the-peass-family), la nostra collezione di [**NFT esclusivi**](https://opensea.io/collection/the-peass-family)
|
||||
* **Unisciti al** 💬 [**gruppo Discord**](https://discord.gg/hRep4RUj7f) o al [**gruppo telegram**](https://t.me/peass) o **seguici** su **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Condividi i tuoi trucchi di hacking inviando PR ai** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
* **Condividi i tuoi trucchi di hacking inviando PR a** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos di github.
|
||||
|
||||
</details>
|
||||
|
||||
## Informazioni di Base
|
||||
|
||||
Un heap overflow è simile a un [**stack overflow**](../stack-overflow/) ma nell'heap. Fondamentalmente significa che è stato riservato dello spazio nell'heap per memorizzare dei dati e che i **dati memorizzati erano più grandi dello spazio riservato**.
|
||||
Un heap overflow è simile a un [**stack overflow**](../stack-overflow/) ma nell'heap. Fondamentalmente significa che è stato riservato dello spazio nell'heap per memorizzare alcuni dati e **i dati memorizzati erano più grandi dello spazio riservato**.
|
||||
|
||||
Nei stack overflows sappiamo che alcuni registri come il puntatore di istruzione o il frame dello stack verranno ripristinati dallo stack e potrebbe essere possibile abusarne. Nel caso degli heap overflows, **non c'è alcuna informazione sensibile memorizzata per impostazione predefinita** nel chunk dell'heap che può essere sovraffollato. Tuttavia, potrebbero esserci informazioni sensibili o puntatori, quindi la **criticità** di questa vulnerabilità **dipende** da **quali dati potrebbero essere sovrascritti** e da come un attaccante potrebbe abusarne.
|
||||
|
||||
|
@ -24,15 +24,29 @@ Nei stack overflows sappiamo che alcuni registri come il puntatore di istruzione
|
|||
Per trovare gli offset degli overflow puoi utilizzare gli stessi schemi dei [**stack overflows**](../stack-overflow/#finding-stack-overflows-offsets).
|
||||
{% endhint %}
|
||||
|
||||
### Stack Overflows vs Heap Overflows
|
||||
|
||||
Nei stack overflows l'organizzazione e i dati che saranno presenti nello stack nel momento in cui la vulnerabilità può essere attivata sono abbastanza affidabili. Questo perché lo stack è lineare, aumenta sempre in memoria in collisione, in **specifici punti dell'esecuzione del programma la memoria dello stack di solito memorizza tipi di dati simili** e ha una struttura specifica con alcuni puntatori alla fine della parte dello stack utilizzata da ciascuna funzione.
|
||||
|
||||
Tuttavia, nel caso di un heap overflow, poiché la memoria utilizzata non è lineare ma **i chunk allocati sono di solito in posizioni separate della memoria** (non uno accanto all'altro) a causa di **bin e zone** che separano le allocazioni per dimensione e perché **la memoria precedentemente liberata viene utilizzata** prima di allocare nuovi chunk. È **complicato sapere quale oggetto andrà a collidere con quello vulnerabile** a un heap overflow. Quindi, quando viene trovato un heap overflow, è necessario trovare un **modo affidabile per far sì che l'oggetto desiderato sia il successivo in memoria** rispetto a quello che può essere sovraffollato.
|
||||
|
||||
Una delle tecniche utilizzate per questo è il **Heap Grooming** che viene utilizzato ad esempio [**in questo post**](https://azeria-labs.com/grooming-the-ios-kernel-heap/). Nel post viene spiegato come nel kernel iOS quando una zona esaurisce la memoria per memorizzare chunk di memoria, la espande di una pagina del kernel, e questa pagina viene divisa in chunk delle dimensioni previste che verranno utilizzati in ordine (fino alla versione iOS 9.2, poi questi chunk vengono utilizzati in modo randomizzato per rendere più difficile lo sfruttamento di questi attacchi).
|
||||
|
||||
Pertanto, nel post precedente in cui si verifica un heap overflow, per forzare l'oggetto sovraffollato a collidere con un ordine vittima, diversi **`kallocs` sono forzati da diversi thread per cercare di garantire che tutti i chunk liberi siano riempiti e che venga creata una nuova pagina**.
|
||||
|
||||
Per forzare questo riempimento con oggetti di una dimensione specifica, l'**allocazione fuori linea associata a una porta mach iOS** è un candidato ideale. Creando la dimensione del messaggio, è possibile specificare esattamente la dimensione dell'allocazione `kalloc` e quando la porta mach corrispondente viene distrutta, l'allocazione corrispondente verrà immediatamente rilasciata a `kfree`.
|
||||
|
||||
Quindi, alcuni di questi segnaposto possono essere **liberati**. La lista di liberazione **`kalloc.4096` rilascia gli elementi in ordine di ultimo entrato, primo uscito**, il che significa fondamentalmente che se alcuni segnaposto vengono liberati e l'exploit prova a allocare diversi oggetti vittima mentre cerca di allocare l'oggetto vulnerabile all'overflow, è probabile che questo oggetto sarà seguito da un oggetto vittima.
|
||||
|
||||
## Esempio ARM64
|
||||
|
||||
Nella pagina [https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/](https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/) puoi trovare un esempio di heap overflow in cui un comando che verrà eseguito è memorizzato nel chunk seguente al chunk sovraccaricato. Quindi, è possibile modificare il comando eseguito sovrascribendolo con un exploit semplice come:
|
||||
Nella pagina [https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/](https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/) puoi trovare un esempio di heap overflow in cui un comando che verrà eseguito è memorizzato nel chunk seguente rispetto al chunk sovraffollato. Quindi, è possibile modificare il comando eseguito sovrascribendolo con un exploit semplice come:
|
||||
```bash
|
||||
python3 -c 'print("/"*0x400+"/bin/ls\x00")' > hax.txt
|
||||
```
|
||||
<details>
|
||||
|
||||
<summary><strong>Impara l'hacking su AWS da zero a eroe con</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (Esperto Red Team AWS di HackTricks)</strong></a><strong>!</strong></summary>
|
||||
<summary><strong>Impara l'hacking AWS da zero a eroe con</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (Esperto Red Team AWS di HackTricks)</strong></a><strong>!</strong></summary>
|
||||
|
||||
Altri modi per supportare HackTricks:
|
||||
|
||||
|
@ -40,6 +54,6 @@ Altri modi per supportare HackTricks:
|
|||
* Ottieni il [**merchandising ufficiale di PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
* Scopri [**La Famiglia PEASS**](https://opensea.io/collection/the-peass-family), la nostra collezione di esclusive [**NFT**](https://opensea.io/collection/the-peass-family)
|
||||
* **Unisciti al** 💬 [**gruppo Discord**](https://discord.gg/hRep4RUj7f) o al [**gruppo telegram**](https://t.me/peass) o **seguici** su **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Condividi i tuoi trucchi di hacking inviando PR ai** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos di github.
|
||||
* **Condividi i tuoi trucchi di hacking inviando PR a** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
|
||||
</details>
|
||||
|
|
46
binary-exploitation/heap/use-after-free/README.md
Normal file
46
binary-exploitation/heap/use-after-free/README.md
Normal file
|
@ -0,0 +1,46 @@
|
|||
# Uso dopo la liberazione
|
||||
|
||||
<details>
|
||||
|
||||
<summary><strong>Impara l'hacking su AWS da zero a esperto con</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (Esperto Red Team AWS di HackTricks)</strong></a><strong>!</strong></summary>
|
||||
|
||||
Altri modi per supportare HackTricks:
|
||||
|
||||
* Se vuoi vedere la **tua azienda pubblicizzata su HackTricks** o **scaricare HackTricks in PDF** controlla i [**PIANI DI ABBONAMENTO**](https://github.com/sponsors/carlospolop)!
|
||||
* Ottieni il [**merchandising ufficiale di PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
* Scopri [**La Famiglia PEASS**](https://opensea.io/collection/the-peass-family), la nostra collezione di [**NFT esclusivi**](https://opensea.io/collection/the-peass-family)
|
||||
* **Unisciti al** 💬 [**gruppo Discord**](https://discord.gg/hRep4RUj7f) o al [**gruppo telegram**](https://t.me/peass) o **seguici** su **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Condividi i tuoi trucchi di hacking inviando PR a** [**HackTricks**](https://github.com/carlospolop/hacktricks) e ai repository github di [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
||||
|
||||
</details>
|
||||
|
||||
## Informazioni di base
|
||||
|
||||
Come suggerisce il nome, questa vulnerabilità si verifica quando un programma **riserva dello spazio** nell'heap per un oggetto, **scrive** alcune informazioni lì, **lo libera** apparentemente perché non è più necessario e poi **vi accede di nuovo**.
|
||||
|
||||
Il problema qui è che non è illegale (non ci saranno errori) quando si accede a una **memoria liberata**. Quindi, se il programma (o l'attaccante) riesce a **allocare la memoria liberata e memorizzare dati arbitrari**, quando la memoria liberata viene acceduta dal puntatore iniziale quei dati saranno stati sovrascritti causando una **vulnerabilità che dipenderà dalla sensibilità dei dati** che erano stati memorizzati originariamente (se si trattava di un puntatore di una funzione che sarebbe stata chiamata, un attaccante potrebbe controllarlo).
|
||||
|
||||
### Attacco First Fit
|
||||
|
||||
Un attacco di tipo First Fit mira al modo in cui alcuni allocatori di memoria, come in glibc, gestiscono la memoria liberata. Quando si libera un blocco di memoria, viene aggiunto a una lista e le nuove richieste di memoria vengono prelevate da quella lista dalla fine. Gli attaccanti possono utilizzare questo comportamento per manipolare **quali blocchi di memoria vengono riutilizzati, potenzialmente ottenendo il controllo su di essi**. Ciò può portare a problemi di "uso dopo la liberazione", dove un attaccante potrebbe **modificare i contenuti della memoria che viene riallocata**, creando un rischio per la sicurezza.\
|
||||
Controlla ulteriori informazioni in:
|
||||
|
||||
{% content-ref url="first-fit.md" %}
|
||||
[first-fit.md](first-fit.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
##
|
||||
|
||||
<details>
|
||||
|
||||
<summary><strong>Impara l'hacking su AWS da zero a esperto con</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (Esperto Red Team AWS di HackTricks)</strong></a><strong>!</strong></summary>
|
||||
|
||||
Altri modi per supportare HackTricks:
|
||||
|
||||
* Se vuoi vedere la **tua azienda pubblicizzata su HackTricks** o **scaricare HackTricks in PDF** controlla i [**PIANI DI ABBONAMENTO**](https://github.com/sponsors/carlospolop)!
|
||||
* Ottieni il [**merchandising ufficiale di PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
* Scopri [**La Famiglia PEASS**](https://opensea.io/collection/the-peass-family), la nostra collezione di [**NFT esclusivi**](https://opensea.io/collection/the-peass-family)
|
||||
* **Unisciti al** 💬 [**gruppo Discord**](https://discord.gg/hRep4RUj7f) o al [**gruppo telegram**](https://t.me/peass) o **seguici** su **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Condividi i tuoi trucchi di hacking inviando PR a** [**HackTricks**](https://github.com/carlospolop/hacktricks) e ai repository github di [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
||||
|
||||
</details>
|
64
binary-exploitation/heap/use-after-free/first-fit.md
Normal file
64
binary-exploitation/heap/use-after-free/first-fit.md
Normal file
|
@ -0,0 +1,64 @@
|
|||
# First Fit
|
||||
|
||||
<details>
|
||||
|
||||
<summary><strong>Impara l'hacking AWS da zero a eroe con</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (Esperto Red Team AWS di HackTricks)</strong></a><strong>!</strong></summary>
|
||||
|
||||
Altri modi per supportare HackTricks:
|
||||
|
||||
* Se vuoi vedere la tua **azienda pubblicizzata in HackTricks** o **scaricare HackTricks in PDF** Controlla i [**PIANI DI ABBONAMENTO**](https://github.com/sponsors/carlospolop)!
|
||||
* Ottieni il [**merchandising ufficiale di PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
* Scopri [**La Famiglia PEASS**](https://opensea.io/collection/the-peass-family), la nostra collezione di [**NFT esclusivi**](https://opensea.io/collection/the-peass-family)
|
||||
* **Unisciti al** 💬 [**gruppo Discord**](https://discord.gg/hRep4RUj7f) o al [**gruppo telegram**](https://t.me/peass) o **seguici** su **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Condividi i tuoi trucchi di hacking inviando PR a** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||||
|
||||
</details>
|
||||
|
||||
## **First Fit**
|
||||
|
||||
Quando liberi la memoria in un programma utilizzando glibc, vengono utilizzati diversi "bin" per gestire i blocchi di memoria. Ecco una spiegazione semplificata di due scenari comuni: unsorted bins e fastbins.
|
||||
|
||||
### Unsorted Bins
|
||||
|
||||
Quando liberi un blocco di memoria che non è un blocco veloce, va al bin non ordinato. Questo bin funziona come una lista in cui i nuovi blocchi liberati vengono aggiunti all'inizio (la "testa"). Quando richiedi un nuovo blocco di memoria, l'allocatore guarda il bin non ordinato dalla fine (la "coda") per trovare un blocco abbastanza grande. Se un blocco dal bin non ordinato è più grande di quanto necessiti, viene diviso, con la parte anteriore restituita e la parte rimanente che rimane nel bin.
|
||||
|
||||
Esempio:
|
||||
|
||||
* Alloci 300 byte (`a`), quindi 250 byte (`b`), liberi `a` e richiedi di nuovo 250 byte (`c`).
|
||||
* Quando liberi `a`, va al bin non ordinato.
|
||||
* Se successivamente richiedi di nuovo 250 byte, l'allocatore trova `a` in coda e lo divide, restituendo la parte che soddisfa la tua richiesta e mantenendo il resto nel bin.
|
||||
* `c` punterà al precedente `a` e sarà riempito con i dati di `a`.
|
||||
```c
|
||||
char *a = malloc(300);
|
||||
char *b = malloc(250);
|
||||
free(a);
|
||||
char *c = malloc(250);
|
||||
```
|
||||
### Fastbins
|
||||
|
||||
I fastbins sono utilizzati per piccoli blocchi di memoria. A differenza dei blocchi non ordinati, i fastbins aggiungono nuovi blocchi all'inizio, creando un comportamento di tipo ultimo ad entrare, primo ad uscire (LIFO). Se richiedi un piccolo blocco di memoria, l'allocatore preleverà dalla testa del fastbin.
|
||||
|
||||
Esempio:
|
||||
|
||||
* Alloci quattro blocchi di 20 byte ciascuno (`a`, `b`, `c`, `d`).
|
||||
* Quando li liberi in qualsiasi ordine, i blocchi liberati vengono aggiunti alla testa del fastbin.
|
||||
* Se successivamente richiedi un blocco da 20 byte, l'allocatore restituirà il blocco liberato più di recente dalla testa del fastbin.
|
||||
```c
|
||||
char *a = malloc(20);
|
||||
char *b = malloc(20);
|
||||
char *c = malloc(20);
|
||||
char *d = malloc(20);
|
||||
free(a);
|
||||
free(b);
|
||||
free(c);
|
||||
free(d);
|
||||
a = malloc(20); // d
|
||||
b = malloc(20); // c
|
||||
c = malloc(20); // b
|
||||
d = malloc(20); // a
|
||||
```
|
||||
## Altri riferimenti ed esempi
|
||||
|
||||
* [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. Uso dopo la liberazione: Generare un oggetto utente, liberarlo, generare un oggetto che ottiene il pezzo liberato e consente di scriverci sopra, sovrascrivendo la posizione di user->password da quello precedente. Riutilizzare l'utente per aggirare il controllo della password
|
Loading…
Reference in a new issue