Unsorted Bin Attack
Last updated
Last updated
Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Per ulteriori informazioni su cosa sia un unsorted bin, controlla questa pagina:
Bins & Memory AllocationsLe liste non ordinate possono 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 dell'unsorted bin, potrebbe essere in grado di scrivere quell'indirizzo in un indirizzo arbitrario che potrebbe essere utile per rivelare indirizzi Glibc o bypassare alcune difese.
Quindi, fondamentalmente, questo attacco consente di impostare un grande numero in un indirizzo arbitrario. Questo grande numero è un indirizzo, che potrebbe essere un indirizzo heap o un indirizzo Glibc. Un obiettivo tipico è global_max_fast
per consentire di creare fast bin con dimensioni maggiori (e passare da un attacco unsorted bin a un attacco fast bin).
Dando un'occhiata all'esempio fornito in 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 Tcache), è possibile vedere che oggigiorno l'errore malloc(): unsorted double linked list corrupted
viene attivato.
Pertanto, questo attacco unsorted bin ora (tra altri controlli) richiede anche di essere in grado di riparare la lista doppiamente collegata in modo che venga bypassato victim->bk->fd == victim
o non victim->fd == av (arena)
, il che significa che l'indirizzo in cui vogliamo scrivere deve avere l'indirizzo del fake chunk nella sua posizione fd
e che il fake chunk fd
punta all'arena.
Nota che questo attacco corrompe l'unsorted bin (quindi anche small e large). Quindi possiamo solo utilizzare allocazioni dal fast bin ora (un programma più complesso potrebbe fare altre allocazioni e andare in crash), e per attivare questo dobbiamo allocare la stessa dimensione o il programma andrà in crash.
Nota che sovrascrivere global_max_fast
potrebbe aiutare in questo caso fidandosi che il fast bin sarà in grado di gestire tutte le altre allocazioni fino al completamento dell'exploit.
Il codice di guyinatuxedo lo spiega molto bene, anche se se modifichi le malloc per allocare memoria abbastanza grande da non finire in un Tcache puoi vedere che l'errore precedentemente menzionato appare impedendo questa tecnica: malloc(): unsorted double linked list corrupted
Questo è in realtà un concetto molto basilare. I chunk nell'unsorted bin avranno puntatori. Il primo chunk nell'unsorted bin avrà effettivamente i link fd
e bk
che puntano a una parte dell'arena principale (Glibc).
Pertanto, se puoi mettere un chunk all'interno di un unsorted bin e leggerlo (use after free) o allocarlo di nuovo senza sovrascrivere almeno 1 dei puntatori per poi leggerlo, puoi avere una rivelazione di info Glibc.
Un simile attacco utilizzato in questo writeup è stato quello di abusare di una struttura di 4 chunk (A, B, C e D - D serve solo a prevenire la consolidazione con il top chunk) quindi un overflow di byte nullo in B è stato utilizzato per far indicare a C che B era inutilizzato. Inoltre, in B i dati prev_size
sono stati modificati in modo che la dimensione invece di essere la dimensione di B fosse A+B.
Poi C è stato deallocato e consolidato con A+B (ma B era ancora in uso). Un nuovo chunk di dimensione A è stato allocato e poi gli indirizzi libc rivelati sono stati scritti in B da dove sono stati rivelati.
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 heap con la dimensione desiderata.
L'attacco inizia creando 3 chunk: chunk0 per abusare dell'overflow, chunk1 per essere sovrascritto e chunk2 in modo che il top chunk non consolidi i precedenti.
Poi, chunk1 viene liberato e chunk0 viene sovrascritto in modo che il puntatore bk
di chunk1 punti a: bk = magic - 0x10
Poi, chunk3 viene allocato con la stessa dimensione di chunk1, il che attiverà l'attacco unsorted bin e modificherà il valore della variabile globale, rendendo possibile ottenere il flag.
La funzione di merge è vulnerabile perché se entrambi gli indici passati sono lo stesso, verrà realloc su di esso e poi liberato ma restituendo un puntatore a quella regione liberata che può essere utilizzata.
Pertanto, vengono creati 2 chunk: chunk0 che verrà unito con se stesso e chunk1 per prevenire la consolidazione con il top chunk. Poi, la funzione di merge viene chiamata con chunk0 due volte, il che causerà un use after free.
Poi, la funzione view
viene chiamata con l'indice 2 (che è l'indice del chunk use after free), il che rivelerà un indirizzo libc.
Poiché il binario ha protezioni per allocare solo dimensioni maggiori di global_max_fast
, quindi non viene utilizzato alcun fastbin, verrà utilizzato un attacco unsorted bin per sovrascrivere la variabile globale global_max_fast
.
Poi, è possibile chiamare la funzione di modifica con l'indice 2 (il puntatore use after free) e sovrascrivere il puntatore bk
per puntare a p64(global_max_fast-0x10)
. Poi, creando un nuovo chunk utilizzerà l'indirizzo liberato precedentemente compromesso (0x20) che attiverà l'attacco unsorted bin sovrascrivendo il global_max_fast
con un valore molto grande, consentendo ora di creare chunk nei fast bins.
Ora viene eseguito un attacco fast bin:
Prima di tutto, si scopre che è possibile lavorare con fast chunk di dimensione 200 nella posizione __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 a ottenere un fast chunk di dimensione 0x200 in questa posizione, sarà possibile sovrascrivere un puntatore di funzione che verrà eseguito.
Per questo, viene creato un nuovo chunk di dimensione 0xfc
e la funzione di 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.
Poi, la funzione di modifica viene chiamata in questo chunk per modificare l'indirizzo fd
di questo fast bin per puntare alla precedente funzione __free_hook
.
Poi, viene creato un chunk di dimensione 0x1f8
per recuperare dal fast bin il precedente chunk inutile, quindi viene creato un altro chunk di dimensione 0x1f8
per ottenere un fast bin chunk nella __free_hook
che viene sovrascritto con l'indirizzo della funzione system
.
E infine, un chunk contenente la stringa /bin/sh\x00
viene liberato chiamando la funzione di eliminazione, attivando la funzione __free_hook
che punta a system con /bin/sh\x00
come parametro.
Un altro esempio di abuso di un overflow di 1B per consolidare chunk nell'unsorted bin e ottenere una rivelazione di info libc e poi eseguire un attacco fast bin per sovrascrivere malloc hook con un indirizzo one gadget.
Possiamo solo allocare chunk di dimensioni maggiori di 0x100
.
Sovrascrivere global_max_fast
utilizzando un attacco Unsorted Bin (funziona 1/16 volte a causa di ASLR, perché dobbiamo modificare 12 bit, ma dobbiamo modificare 16 bit).
Attacco Fast Bin per modificare un array globale di chunk. Questo fornisce una primitiva di lettura/scrittura arbitraria, che consente di modificare il GOT e impostare alcune funzioni per puntare a system
.
Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)