Leaking libc address with ROP
Breve Riassunto
Trova l'offset dell'overflow
Trova il gadget
POP_RDI
,PUTS_PLT
eMAIN
, ePUTS
gadgetsUsa i gadget precedenti per leakare l'indirizzo di memoria di puts o un'altra funzione di libc e trova la versione di libc (scaricala)
Con la libreria, calcola il ROP ed esploralo
Altri tutorial e binari per praticare
Questo tutorial sfrutta il codice/binario proposto in questo tutorial: https://tasteofsecurity.com/security/ret2libc-unknown-libc/ Altri tutorial utili: https://made0x78.com/bseries-ret2libc/, https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html
Codice
Nome file: vuln.c
Modello ROP - Leak LIBC
Scarica l'exploit e posizionalo nella stessa directory dell'eseguibile vulnerabile e fornisci i dati necessari allo script:
pageLeaking libc - template1- Trovare l'offset
Il modello necessita di un offset prima di continuare con l'exploit. Se non ne viene fornito alcuno, eseguirà il codice necessario per trovarlo (per impostazione predefinita OFFSET = ""
):
Esegui python template.py
verrà aperta una console GDB con il programma che si è bloccato. All'interno di quella console GDB esegui x/wx $rsp
per ottenere i byte che sovrascriveranno il RIP. Infine ottieni l'offset utilizzando una console python:
Dopo aver trovato l'offset (in questo caso 40), cambia la variabile OFFSET all'interno del modello utilizzando quel valore.
OFFSET = "A" * 40
Un altro modo sarebbe utilizzare: pattern create 1000
-- eseguire fino a ret -- pattern search $rsp
da GEF.
2- Trovare i Gadgets
Ora dobbiamo trovare i gadget ROP all'interno del binario. Questi gadget ROP saranno utili per chiamare puts
per trovare la libc in uso e successivamente per eseguire l'exploit finale.
Il PUTS_PLT
è necessario per chiamare la funzione puts.
Il MAIN_PLT
è necessario per chiamare di nuovo la funzione principale dopo un'interazione per sfruttare nuovamente il buffer overflow (round infiniti di sfruttamento). Viene utilizzato alla fine di ogni ROP per richiamare il programma nuovamente.
Il POP_RDI è necessario per passare un parametro alla funzione chiamata.
In questo passaggio non è necessario eseguire nulla poiché tutto verrà trovato da pwntools durante l'esecuzione.
3- Trovare la libreria libc
È ora di trovare quale versione della libreria libc viene utilizzata. Per farlo, andremo a rivelare l'indirizzo in memoria della funzione puts
e poi andremo a cercare in quale versione della libreria si trova la versione di puts in quell'indirizzo.
Per farlo, la linea più importante del codice eseguito è:
Questo invierà alcuni byte fino a sovrascrivere il RIP è possibile: OFFSET
.
Successivamente, imposterà l'indirizzo del gadget POP_RDI
in modo che il prossimo indirizzo (FUNC_GOT
) venga salvato nel registro RDI. Questo perché vogliamo chiamare puts passandogli l'indirizzo del PUTS_GOT
poiché l'indirizzo in memoria della funzione puts è salvato nell'indirizzo puntato da PUTS_GOT
.
Dopo di che, verrà chiamato PUTS_PLT
(con PUTS_GOT
all'interno del RDI) in modo che puts possa leggere il contenuto all'interno di PUTS_GOT
(l'indirizzo della funzione puts in memoria) e lo stampi.
Infine, la funzione principale viene chiamata di nuovo in modo da poter sfruttare nuovamente l'overflow.
In questo modo abbiamo ingannato la funzione puts per stampare l'indirizzo in memoria della funzione puts (che si trova nella libreria libc). Ora che abbiamo quell'indirizzo possiamo verificare quale versione di libc viene utilizzata.
Poiché stiamo sfruttando un binario locale, non è necessario scoprire quale versione di libc viene utilizzata (basta trovare la libreria in /lib/x86_64-linux-gnu/libc.so.6
).
Ma, in caso di exploit remoto, spiegherò qui come puoi trovarlo:
3.1- Ricerca della versione di libc (1)
Puoi cercare quale libreria viene utilizzata nella pagina web: https://libc.blukat.me/ Ti permetterà anche di scaricare la versione di libc scoperta
3.2- Ricerca della versione di libc (2)
Puoi anche fare:
$ git clone https://github.com/niklasb/libc-database.git
$ cd libc-database
$ ./get
Ci vorrà del tempo, sii paziente. Per far funzionare questo abbiamo bisogno di:
Nome del simbolo libc:
puts
Indirizzo libc leakato:
0x7ff629878690
Possiamo capire quale libc è più probabile che venga utilizzata.
Riceviamo 2 corrispondenze (dovresti provare la seconda se la prima non funziona). Scarica la prima:
3.3- Altre funzioni per ottenere informazioni
Copia la libc da libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so
nella nostra directory di lavoro.
4- Trovare l'indirizzo basato sulla libc e sfruttarlo
A questo punto dovremmo conoscere la libreria libc utilizzata. Poiché stiamo sfruttando un binario locale, userò semplicemente: /lib/x86_64-linux-gnu/libc.so.6
Quindi, all'inizio di template.py
cambia la variabile libc in: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #Imposta il percorso della libreria quando lo conosci
Dando il percorso alla libreria libc, il resto dello sfruttamento verrà calcolato automaticamente.
All'interno della funzione get_addr
verrà calcolato l'indirizzo base della libc:
Si noti che l'indirizzo di base finale della libc deve terminare in 00. Se non è il tuo caso, potresti aver rivelato una libreria incorretta.
Quindi, l'indirizzo della funzione system
e l'indirizzo della stringa "/bin/sh" verranno calcolati dall'indirizzo di base della libc e dalla libreria libc fornita.
Finalmente, l'exploit di esecuzione /bin/sh sta per essere preparato e inviato:
Spieghiamo questo ultimo ROP.
L'ultimo ROP (rop1
) ha finito chiamando di nuovo la funzione principale, quindi possiamo sfruttare nuovamente l'overflow (per questo il OFFSET
è qui di nuovo). Quindi, vogliamo chiamare POP_RDI
puntando all'indirizzo di "/bin/sh" (BINSH
) e chiamare la funzione system (SYSTEM
) poiché l'indirizzo di "/bin/sh" verrà passato come parametro.
Infine, viene chiamato l'indirizzo della funzione di uscita in modo che il processo termini correttamente e non venga generato alcun avviso.
In questo modo l'exploit eseguirà una shell _/bin/sh**.**
4(2)- Utilizzando ONE_GADGET
Potresti anche utilizzare ONE_GADGET per ottenere una shell anziché utilizzare system e "/bin/sh". ONE_GADGET troverà all'interno della libreria libc un modo per ottenere una shell utilizzando un solo indirizzo ROP.
Tuttavia, di solito ci sono alcune restrizioni, le più comuni e facili da evitare sono come [rsp+0x30] == NULL
. Poiché controlli i valori all'interno del RSP, devi solo inviare alcuni valori NULL in più in modo che la restrizione venga evitata.
FILE DI EXPLOIT
Puoi trovare un modello per sfruttare questa vulnerabilità qui:
pageLeaking libc - templateProblemi comuni
MAIN_PLT = elf.symbols['main'] non trovato
Se il simbolo "main" non esiste. Allora puoi trovare dove si trova il codice principale:
e impostare manualmente l'indirizzo:
Puts non trovato
Se il binario non sta utilizzando Puts, dovresti controllare se sta utilizzando
sh: 1: %s%s%s%s%s%s%s%s: not found
sh: 1: %s%s%s%s%s%s%s%s: not found
Se trovi questo errore dopo aver creato tutto l'exploit: sh: 1: %s%s%s%s%s%s%s%s: not found
Prova a sottrarre 64 byte all'indirizzo di "/bin/sh":
Last updated