WWW2Exec - atexit()
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Oggigiorno è molto strano sfruttare questo!
atexit()
è una funzione a cui altre funzioni vengono passate come parametri. Queste funzioni verranno eseguite quando si esegue un exit()
o il ritorno del main.
Se puoi modificare l'indirizzo di una di queste funzioni per puntare a un shellcode, ad esempio, guadagnerai il controllo del processo, ma attualmente questo è più complicato.
Attualmente gli indirizzi delle funzioni da eseguire sono nascosti dietro diverse strutture e infine l'indirizzo a cui puntano non è l'indirizzo delle funzioni, ma è crittografato con XOR e spostamenti con una chiave casuale. Quindi attualmente questo vettore di attacco non è molto utile almeno su x86 e x64_86.
La funzione di crittografia è PTR_MANGLE
. Altre architetture come m68k, mips32, mips64, aarch64, arm, hppa... non implementano la funzione di crittografia perché restituisce lo stesso di ciò che ha ricevuto come input. Quindi queste architetture sarebbero attaccabili tramite questo vettore.
Puoi trovare una spiegazione approfondita su come funziona in https://m101.github.io/binholic/2017/05/20/notes-on-abusing-exit-handlers.html
Come spiegato in questo post, se il programma esce usando return
o exit()
verrà eseguito __run_exit_handlers()
che chiamerà i distruttori registrati.
Se il programma esce tramite la funzione _exit()
, chiamerà la syscall exit
e i gestori di uscita non verranno eseguiti. Quindi, per confermare che __run_exit_handlers()
venga eseguito, puoi impostare un breakpoint su di esso.
Il codice importante è (source):
Nota come map -> l_addr + fini_array -> d_un.d_ptr
venga utilizzato per calcolare la posizione dell'array di funzioni da chiamare.
Ci sono un paio di opzioni:
Sovrascrivere il valore di map->l_addr
per farlo puntare a un falso fini_array
con istruzioni per eseguire codice arbitrario
Sovrascrivere le voci l_info[DT_FINI_ARRAY]
e l_info[DT_FINI_ARRAYSZ]
(che sono più o meno consecutive in memoria), per farle puntare a una struttura Elf64_Dyn
contraffatta che farà nuovamente array
puntare a una zona di memoria controllata dall'attaccante.
Questo writeup sovrascrive l_info[DT_FINI_ARRAY]
con l'indirizzo di una memoria controllata in .bss
contenente un falso fini_array
. Questo array falso contiene prima un one gadget indirizzo che verrà eseguito e poi la differenza tra l'indirizzo di questo falso array e il valore di map->l_addr
in modo che *array
punti all'array falso.
Secondo il post principale di questa tecnica e questo writeup ld.so lascia un puntatore nello stack che punta al link_map
binario in ld.so. Con una scrittura arbitraria è possibile sovrascriverlo e farlo puntare a un falso fini_array
controllato dall'attaccante con l'indirizzo di un one gadget per esempio.
Seguendo il codice precedente puoi trovare un'altra sezione interessante con il codice:
In questo caso sarebbe possibile sovrascrivere il valore di map->l_info[DT_FINI]
puntando a una struttura ElfW(Dyn)
contraffatta. Trova ulteriori informazioni qui.
__run_exit_handlers
Come spiegato qui, se un programma termina tramite return
o exit()
, eseguirà __run_exit_handlers()
che chiamerà qualsiasi funzione distruttrice registrata.
Codice da _run_exit_handlers()
:
Codice da __call_tls_dtors()
:
Per ogni funzione registrata in tls_dtor_list
, verrà demanglato il puntatore da cur->func
e chiamato con l'argomento cur->obj
.
Utilizzando la funzione tls
da questo fork di GEF, è possibile vedere che in realtà la dtor_list
è molto vicina al stack canary e al PTR_MANGLE cookie. Quindi, con un overflow su di essa sarebbe possibile sovrascrivere il cookie e lo stack canary.
Sovrascrivendo il PTR_MANGLE cookie, sarebbe possibile bypassare la funzione PTR_DEMANLE
impostandola a 0x00, il che significa che il xor
utilizzato per ottenere l'indirizzo reale è semplicemente l'indirizzo configurato. Poi, scrivendo sulla dtor_list
è possibile collegare diverse funzioni con l'indirizzo della funzione e il suo argomento.
Infine, nota che il puntatore memorizzato non verrà solo xored con il cookie ma anche ruotato di 17 bit:
Quindi devi tenere conto di questo prima di aggiungere un nuovo indirizzo.
Trova un esempio nel post originale.
__run_exit_handlers
Questa tecnica è spiegata qui e dipende ancora dal programma che termina chiamando return
o exit()
quindi __run_exit_handlers()
viene chiamato.
Controlliamo più codice di questa funzione:
La variabile f
punta alla struttura initial
e a seconda del valore di f->flavor
verranno chiamate diverse funzioni.
A seconda del valore, l'indirizzo della funzione da chiamare sarà in un posto diverso, ma sarà sempre demangled.
Inoltre, nelle opzioni ef_on
e ef_cxa
è anche possibile controllare un argomento.
È possibile controllare la struttura initial
in una sessione di debug con GEF in esecuzione gef> p initial
.
Per abusare di questo è necessario leakare o cancellare il PTR_MANGLE
cookie e poi sovrascrivere un'entrata cxa
in initial con system('/bin/sh')
.
Puoi trovare un esempio di questo nel post originale del blog sulla tecnica.
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)