1. Protostar Format Zero
Studenti:
Gianmarco Beato 0522500782
Francesco Maria D’Auria 0522500752
Sfida CTF:
Università degli Studi di Salerno
Dipartimento di Informatica
Corso di Laurea Magistrale in Informatica
Presentazione per il seminario del corso di “Programmazione Sicura”
Docente:
Prof.ssa Barbara Masucci
Giovedì 20 Maggio 2021
Anno Accademico 2020/2021
(bmasucci@unisa.it)
(g.beato1@studenti.unisa.it)
(f.dauria36@studenti.unisa.it)
2. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
1/63
TEAM
GIANMARCO BEATO FRANCESCO M. D’AURIA
Curriculum
Sicurezza Informatica
Curriculum
Sicurezza Informatica
3. OBIETTIVO DELLA SFIDA
INTRODUZIONE
FORMATTAZIONE DELLE
STRINGHE
Introduzione alla macchina
virtuale Protostar,
installazione, account
STRATEGIA D’ATTACCO
INDICE DELLA PRESENTAZIONE
01
04
02
05
03
Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
06
ANALISI DELLA SFIDA
INDIVIDUAZIONE DELLE DEBOLEZZE
E MITIGAZIONE
Obiettivo, codice
sorgente, suggerimenti,
modus operandi
Raccolta di informazioni,
analisi del codice sorgente,
analisi della memoria
Format Functions e
Format Strings
Preparazione dell’input,
albero di attacco Debolezze e possibili
rimedi degli attacchi
2/63
4. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
i
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
TIMING
INTRODUZIONE
OBIETTIVO
DELLA SFIDA
ANALISI DELLA
SFIDA
FORMATTAZIONE
DELLE STRINGHE
STRATEGIA
D’ATTACCO
INDIVIDUAZIONE DELLE
DEBOLEZZE E VULNERABILITA’
Gianmarco Beato
Francesco Maria d’Auria
3/63
5. INTRODUZIONE Introduzione alla macchina virtuale
Protostar, installazione, account
Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
i
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
4/63
6. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
5/63
● Buffer overflow basato su stack;
● Buffer overflow basato su heap;
● Format String;
● Network byte ordering;
INTRODUZIONE (1/5)
Protostar è una macchina virtuale vulnerabile by design contenente esercizi di sicurezza, a scopo didattico,
legati alla corruzione della memoria.
Essa possiede 23 livelli, ciascuno contenente un esercizio, per un totale di 23 esercizi, suddivisi per temi:
1. Stack Zero
2. Stack One
3. Stack Two
4. Stack Three
5. Stack Four
6. Stack Five
7. Stack Six
8. Stack Seven
9. Format Zero
10. Format One
11. Format Two
12. Format Three
13. Format Four
14. Heap Zero
15. Heap One
16. Heap Two
17. Heap Three
18. Net Zero
19. Net One
20. Net Two
21. Final Zero
22. Final One
23. Final Two
I 23 LIVELLI DI PROTOSTAR
7. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
6/63
La macchina virtuale Protostar è disponibile sul portale di exploit education al link:
http://exploit.education/protostar/
INTRODUZIONE (2/5)
Per l’installazione è necessario eseguire questi semplici passaggi:
● Scaricare l’immagine ISO “exploit-exercises-protostar-2.iso” al link:
http://exploit.education/downloads/
● Successivamente importarla in VirtualBox, creando una nuova macchina virtuale;
8. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
7/63
Sul PC su cui è stata installata la macchina virtuale, analizzato il sistema e condotto la sfida, così risulta essere
la configurazione:
INTRODUZIONE (3/5)
Oracle VM Virtual Box
9. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
8/63
INTRODUZIONE (4/5)
Protostar mette a disposizione due account:
Utente che partecipa
alla sfida.
Credenziali:
ATTACCANTE
Utente che amministra il
sistema.
Credenziali:
AMMINISTRATORE
● Username: user
● Password: user
● Username: root
● Password: godmode
10. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
9/63
INTRODUZIONE (5/5)
Protostar mette a disposizione due account:
Utente che partecipa
alla sfida.
Credenziali:
ATTACCANTE
● Username: user
● Password: user
Questo utente dopo l’autenticazione utilizza le
informazioni contenute nella cartella bin per
eseguire un certo tipo di attacco; la cartella ha il
seguente percorso:
/opt/protostar/bin
11. OBIETTIVO
DELLA SFIDA
Obiettivo, codice sorgente,
suggerimenti, modus operandi
Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
i
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
10/63
12. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
11/63
OBIETTIVO DELLA SFIDA (1/2)
Sulla relativa pagina web di exploit education (*) viene fornita una descrizione della sfida Format Zero:
“Questo livello introduce le stringhe formattate e di come un attaccante possa dare in input una stringa
formattata per cambiare il flusso di esecuzione di un programma”
(*) http://exploit.education/protostar/format-zero/
Il programma in questione si chiama format0.c ed il suo file eseguibile, format0, ha il seguente percorso:
/opt/protostar/bin/format0
13. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
12/63
OBIETTIVO DELLA SFIDA (2/2)
format0.c
L’obiettivo della sfida è impostare la variabile target allo
specifico valore 0xdeadbeef a tempo di esecuzione, per
modificare il flusso di esecuzione del programma
Vengono forniti dei piccoli suggerimenti:
● Il livello dovrebbe essere risolto con un input
avente dimensione minore di 10 byte;
● Cercare “Exploiting Format String Vulnerabilities”;
Viene fornito il codice sorgente del programma in
questione; possiamo darne un rapido sguardo:
Il modus operandi è il seguente:
1. Raccogliere quante più informazioni possibili sul
sistema;
2. Aggiornare l’albero d’attacco;
3. Provare l’attacco solo dopo aver individuato un
percorso plausibile;
4. Se l’attacco non è riuscito, tornare al punto 1;
5. Se l’attacco è riuscito, allora sfida vinta!
14. ANALISI DELLA SFIDA
Raccolta di informazioni, analisi
del codice sorgente, analisi della
memoria
Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
i
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
13/63
15. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
14/63
Prima di addentrarci nel cuore della sfida, è sempre buona norma raccogliere quante più informazioni possibili
sul sistema in questione in termini di:
● Architettura hardware (32-bit/64-bit, Intel, AMD, oppure altro...);
● Sistema Operativo (GNU/Linux, Windows, oppure altro...);
● Metodi di input (locale, remoto, oppure altro...)
ANALISI DELLA SFIDA (1/30)
RACCOLTA DI INFORMAZIONI (1/8)
16. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
15/63
Prima di addentrarci nel cuore della sfida, è sempre buona norma raccogliere quante più informazioni possibili
sul sistema in questione in termini di:
● Architettura hardware (32-bit/64-bit, Intel, AMD, oppure altro...):
ANALISI DELLA SFIDA (2/30)
Per ottenere informazioni sull’architettura è possibile digitare il seguente comando sul terminale
della macchina precedentemente avviata tramite VirtualBox: arch
Digitando il suddetto comando si scopre che la macchina virtuale Protostar viene eseguita su un
sistema operativo la cui architettura della macchina host è di tipo i686.
Effettuando una ricerca sul Web risulta che i686 è una sigla per indicare la sesta generazione delle
CPU Intel compatibili con l'architettura x86, e che tale architettura utilizza il formato little endian.
RACCOLTA DI INFORMAZIONI (2/8)
17. 1 0 0 1 0 0 1 0
0 1 0 1 0 0 0 1
0 0 0 0 0 1 1 1
0 0 0 0 0 0 1 1
Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
16/63
BIG ENDIAN VS LITTLE ENDIAN: COME VENGONO IMMAGAZZINATI I DATI IN MEMORIA? (1/2)
Il modello della memoria RAM
1 0 1 0 1 1 1 0
Una memoria può essere concettualmente
immaginata come una matrice di bit organizzata
in n righe, ciascuna di m colonne.
Il numero n di righe è una potenza di 2.
Il numero m di colonne è un multiplo di 8
(essendo 8 la dimensione in bit del byte).
Una cella è un gruppo di k bit che vengono trattati
come un’unità inscindibile, cioè cui si accede
unitariamente (in genere k = 8, cioè 1byte)
Più celle vengono raggruppate a formare una
parola (word); le dimensioni più comuni per le
parole sono 4 o 8 byte.
Ogni cella/byte viene identificata/o in maniera
univoca mediante il suo indirizzo: se la memoria
contiene N celle, gli indirizzi sono compresi tra 0
e N-1 (si parla di memorie byte-addressable)
:
Memoria da 256bit (32byte)
Byte 0
Indirizzo:
00000000
Byte 1
Indirizzo:
00000001
Byte 2
Indirizzo:
00000010
Byte 3
Indirizzo:
00000011
Byte 31
Indirizzo:
11111111
Ovviamente per memorie molto grandi (es. 4GB) occorrono indirizzi con molti bit (per
una memoria di 4GB occorrono 32bit) e per semplicità tali indirizzi (ma anche il
contenuto dei singoli byte) vengono espressi in notazione esadecimale (prefisso 0x)
e non in notazione binaria, in cui ogni byte viene espresso con due cifre esadecimali:
3970458665 0xECA86429
1110 1100 1010 1000 0110 0100 0010 0000
(Indirizzi bassi)
(Indirizzi alti)
18. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
17/63
BIG ENDIAN VS LITTLE ENDIAN: COME VENGONO IMMAGAZZINATI I DATI IN MEMORIA? (2/2)
Quando il dato da memorizzare (parola) occupa di più di 1byte (più di una cella), un calcolatore può utilizzare una delle due seguenti
modalità per immagazzinare in memoria tali dati, e quindi per accedervi ad esso:
L’ordine dei byte
BIG ENDIAN (da sinistra a
destra):
Il byte più significativo del dato
(della parola) da memorizzare,
cioè quello posto ad estrema
sinistra, ha l’indirizzo di memoria
più basso; mentre quello meno
significativo, cioè quello posto ad
estrema destra, ha l’indirizzo più
alto. In altre parole vuol dire che
l’indirizzo del byte più
significativo viene utilizzato
come indirizzo dell’intera parola,
e quindi per accedervi.
LITTLE ENDIAN (da destra a
sinistra):
Il byte meno significativo del dato
(della parola) da memorizzare,
cioè quello posto ad estrema
destra, ha l’indirizzo di memoria
più basso; mentre quello più
significativo, cioè quello posto ad
estrema sinistra, ha l’indirizzo più
alto. In altre parole vuol dire che
l’indirizzo del byte meno
significativo viene utilizzato come
indirizzo dell’intera parola, e quindi
per accedervi.
0x5C
0x1B
0x12
0x3A
0x5F
0xF4
0x0A
0x0B
:
Byte 0
Indirizzo:
0x00000000
0x12 3A 5F F4
0x5C
0x1B
0xF4
0x5F
0x3A
0x12
:
0x0A
0x0B
(Intero da 32bit=4byte da
memorizzare,
rappresentato in
esadecimale)
Byte 1
Indirizzo:
0x00000001
Byte 2
Indirizzo:
0x00000010
Byte 3
Indirizzo:
0x00000011
Byte 4
Indirizzo:
0x00000100
Byte 5
Indirizzo:
0x00000101
Byte 232
-2
Indirizzo:
0xFFFFFFFE
Byte 232
-1
Indirizzo:
0xFFFFFFFF
(Memoria RAM da 4Gb = 232
byte,
byte-addressable, con celle da
1byte)
0x12 è il
Byte più
significativo
0xF4 è il
Byte meno
significativo
Byte 0
Indirizzo:
0x00000000
Byte 1
Indirizzo:
0x00000001
Byte 2
Indirizzo:
0x00000010
Byte 3
Indirizzo:
0x00000011
Byte 4
Indirizzo:
0x00000100
Byte 5
Indirizzo:
0x00000101
Byte 232
-2
Indirizzo:
0xFFFFFFFE
Byte 232
-1
Indirizzo:
0xFFFFFFFF
(Memoria RAM da 4Gb = 232
byte,
byte-addressable, con celle da
1byte)
(Indirizzi bassi) (Indirizzi bassi)
(Indirizzi alti) (Indirizzi alti)
19. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
18/63
Prima di addentrarci nel cuore della sfida, è sempre buona norma raccogliere quante più informazioni possibili
sul sistema in questione in termini di:
● Architettura hardware (32-bit/64-bit, Intel, AMD, oppure altro...):
ANALISI DELLA SFIDA (5/30)
Per ottenere informazioni sui processori installati sulla macchina host è possibile digitare il
seguente comando sul terminale della macchina: cat /proc/cpuinfo
Digitando il suddetto comando si scopre (tra le tante informazioni che vengono mostrate) che vi è
un solo processore installato e che corrisponde all’ intel Core i7-6700 HQ.
RACCOLTA DI INFORMAZIONI (5/8)
20. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
19/63
Prima di addentrarci nel cuore della sfida, è sempre buona norma raccogliere quante più informazioni possibili
sul sistema in questione in termini di:
● Sistema Operativo (GNU/Linux, Windows, oppure altro...):
ANALISI DELLA SFIDA (6/30)
Per ottenere informazioni sul sistema operativo in esecuzione è possibile digitare il seguente
comando sul terminale della macchina: lsb_release -a
Digitando il suddetto comando si scopre che Protostar esegue su un sistema operativo Debian
GNU/Linux v. 6.0.3 (squeeze).
RACCOLTA DI INFORMAZIONI (6/8)
21. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
20/63
Prima di addentrarci nel cuore della sfida, è sempre buona norma raccogliere quante più informazioni possibili
sul sistema in questione in termini di:
● Metodi di input (locale, remoto, oppure altro...):
ANALISI DELLA SFIDA (7/30)
Una volta avviata la macchina virtuale tramite virtual box ed aver inserito le credenziali per accedere
all’utente come attaccante, si accede nella cartella di lavoro bin contenente il file eseguibile format0
della sfida digitando il seguente comando sul terminale: cd opt/protostar/bin
Dopodichè, è possibile mandare in esecuzione il programma eseguibile format0 digitando il seguente
comando sul terminale: ./format0
Si può notare che non accade nulla
(viene restituito il terminale) poichè non
è stato passato nessun dato in input.
RACCOLTA DI INFORMAZIONI (7/8)
22. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
21/63
Prima di addentrarci nel cuore della sfida, è sempre buona norma raccogliere quante più informazioni possibili
sul sistema in questione in termini di:
● Metodi di input (locale, remoto, oppure altro...):
ANALISI DELLA SFIDA (8/30)
Si deduce che il programma format0 accetta esclusivamente input locali, da tastiera o da altro
processo (tramite pipe).
L’input è una stringa generica.
Non sembrano esistere altri metodi per fornire input al programma.
Anche mandando in esecuzione il programma con un input qualsiasi (stringa: abc789 ) si nota che non
accade nulla (viene restituito il terminale, i caratteri vengono memorizzati in buffer[]):
Come procedere?
RACCOLTA DI INFORMAZIONI (8/8)
23. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
22/63
ANALISI DELLA SFIDA (9/30)
format0.c
ANALISI DEL CODICE SORGENTE (1/2) Analizzando nello specifico il codice sorgente del
programma, è possibile notare che all’interno della
funzione main viene eseguita la funzione vuln che
possiede come parametro argv[1].
All’interno della funzione vuln, invece, vengono
allocate sullo stack due variabili:
volatile int target e char buffer[64]
Viene posta la variabile target al valore 0.
Viene copiato il contenuto di string in buffer
mediante la funzione sprintf(buffer, string).
Se il valore della variabile target risulta uguale al valore
0xdeadbeef, allora viene stampato un messaggio il
quale indica che “il target è stato colpito correttamente”.
24. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
23/63
ANALISI DELLA SFIDA (10/30)
format0.c
ANALISI DEL CODICE SORGENTE (2/2) Inoltre è possibile notare che le variabili target e buffer sono
spazialmente vicine.
Saranno vicine anche in memoria centrale?
E’ necessario analizzare lo stack per capire come sono disposte le
variabili al suo interno.
Perchè? Se le due variabili sono contigue in memoria, è possibile sovrascrivere la
variabile target sfruttando la vicinanza con la variabile buffer.
L’idea è quella di scrivere, mediante una stringa formattata data in input minore di
10 byte (come esplicitamente richiesto), 68 byte all’interno di buffer; poichè
buffer può contenere 64 byte, i primi 64 byte dell’input di 10 byte espanso
riempiranno buffer, mentre i restanti 4 riempiranno target (buffer overflow).
Sarebbe potuto bastare un semplice input di lunghezza maggiore di 64
caratteri per sovrascrivere la variabile target, ma è esplicitamente
richiesto di utilizzare un input minore di 10 byte !
25. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
24/63
UTILIZZO DELLA MEMORIA DA PARTE DI UN PROCESSO (1/3)
Quando viene eseguito un programma il sistema operativo normalmente genera un
nuovo processo e alloca in memoria centrale (RAM) uno spazio di memoria virtuale
riservato al processo stesso.
Tipicamente questa porzione di memoria RAM allocata al processo viene tipicamente
suddivisa in tre parti:
● La prima è il segmento testo che contiene le istruzioni del programma che risiedono
per tutta la durata dell’esecuzione del programma. Tale segmento è posizionato vicino
al limite inferiore (indirizzi bassi) dello spazio di indirizzamento dedicato al processo.
● La seconda parte, collocata immediatamente sopra al segmento testo, è il
segmento dati, che viene ulteriormente suddiviso in due parti:
❖ La sezione dei dati statici, che contiene oggetti di dimensione nota al
compilatore e il cui tempo di vita è il periodo di esecuzione del programma
(es. variabili globali)
❖ La sezione dei dati dinamici (heap), posta immediatamente al di sopra dei dati
statici, contiene dati che vengono allocati dal programma durante la sua
esecuzione (es. malloc()). Questo segmento si espande verso gli indirizzi alti.
● La terza parte è il segmento di stack del programma che è posizionato vicino al limite
superiore (indirizzi alti) dello spazio di indirizzamento dedicato al processo. Come per i
dati dinamici, la dimensione massima di questo segmento non è nota a priori, ed ogni
qualvolta il programma introduce valori (variabili locali e parametri di una funzione), il
sistema operativo espande tale segmento verso gli indirizzi bassi.
Byte 0
Indirizzo:
0x00000000
(Indirizzi bassi)
Byte 232
-1
Indirizzo:
0xFFFFFFFF
(Indirizzi alti)
RAM da 232
byte
Segmento di stack
Segmento testo
Segmento dati
Dati statici
Dati dinamici (heap)
Riservato
26. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
25/63
UTILIZZO DELLA MEMORIA DA PARTE DI UN PROCESSO (2/3)
Byte 0
Indirizzo:
0x00000000
(Indirizzi bassi)
Byte 232
-1
Indirizzo:
0xFFFFFFFF
(Indirizzi alti)
RAM da 232
byte
Segmento di stack
Segmento testo
Segmento dati
Dati statici
Dati dinamici (heap)
Riservato
Il segmento di stack è una zona di memoria di un programma,
organizzata in forma di stack, nella quale sono immagazzinate le
informazioni (i dati oggetto dell’elaborazione) sulle funzioni attive in un
dato momento (le funzioni attive sono quelle che sono state invocate ma
la cui esecuzione non è terminata)
Durante l’esecuzione di un programma, le funzioni hanno la necessità di
archiviare tali dati.
I linguaggi di programmazione moderni hanno il costrutto di procedura
o funzione e quindi l’esecuzione di un programma consiste a sua volta
di diverse “chiamate a funzioni”. Una chiamata a procedura altera il
flusso di controllo come un salto (jump), ma, diversamente da un salto,
una volta finito il proprio compito, una funzione ritorna il controllo
all'istruzione posta appena successivamente alla chiamata.
Quest'astrazione può essere implementata proprio con il supporto di uno
stack; inoltre ciascuna chiamata genera uno stack frame all’interno dello
stack. Questi stack frame vengono impilati sullo stack (allocati) quando
viene chiamata una funzione e spilati quando la funzione ritorna
(deallocati). All’interno di uno stack frame la “funzione chiamata”
generalmente (a seconda dell’architettura) memorizza le variabili locali, i
parametri, l’indirizzo dell’istruzione della funzione chiamante a cui dovrà
restituire il controllo (return address, contenuto nell’instruction pointer o
IP) e il puntatore al frame della funzione chiamante;
:
Segmento di stack
Indirizzo di ritorno
Puntatore al frame della
funzione chiamante
Variabili locali della
funzione
Parametri della funzione
Indirizzo di ritorno
Puntatore al frame della
funzione chiamante
Parametri della funzione
Variabili locali della
funzione
}
}
Stack frame
funzione 2
Stack frame
funzione 1
Direzione
di
crescita
dello
stack
(Indirizzi bassi)
(Indirizzi alti)
(Top dello stack)
27. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
26/63
UTILIZZO DELLA MEMORIA DA PARTE DI UN PROCESSO (3/3)
:
Segmento di stack
Indirizzo di ritorno
Puntatore al frame della
funzione chiamante
Variabili locali della
funzione
Parametri della funzione
Indirizzo di ritorno
Puntatore al frame della
funzione chiamante
Parametri della funzione
Variabili locali della
funzione
}
}
Stack frame
funzione 2
(dimensione 24 byte,
dal byte 1235 al byte
1258)
Stack frame
funzione 1
Direzione
di
crescita
dello
stack
(Indirizzi bassi)
(Indirizzi alti)
(Top dello stack)
Parametro1
0xaabb89cc
Parametro2
0xacdb17cf
Indirizzo di
ritorno
0x01ab5cff
Puntatore frame
precedente
0x002376cd
Variabile
locale1
0x54ff98cf
Variabile
locale2
0xabcdef00
aa
bb
89
cc
cf
17
db
ac
ff
5c
ab
01
cd
76
23
00
cf
98
ff
54
00
ef
cd
ab
.
esp
Stack
pointer
(0x000004D3)
.
.
.
ebp
Frame
pointer
(0x002376cd)
eax
Valore di
ritorno
(Indirizzi alti)
Da precisare che Il contenuto esatto e
il layout dello stack/stack frame
variano in base all'architettura del
processore e alla convenzione delle
chiamate a funzione. In particolare
nell’architettura Intel x86 gli stack
frame vengono gestiti mediante tre
registri:
Direzione
di
crescita
dello
stack
Byte 1235 (-8 %EBP)
Indirizzo:
0x000004D3
(Indirizzi bassi)
Byte 1238 (-5 %EBP)
Indirizzo:
0x000004D6
Byte 1258 (+15 %EBP)
Indirizzo:
0x000004EA
Byte 1243 (EBP)
Indirizzo:
0x000004DB
ESP: punta al top dello stack, ovvero
contiene l’indirizzo del byte che è
posto al top dello stack.
EBP: contiene l’indirizzo del campo
“puntatore frame precedente” dello
stack frame precedente, e consente di
accedere agli argomenti e alle
variabili locali all’interno del frame
associato alla funzione in esecuzione.
Registri della CPU
EAX: utilizzato per trasferire valori di
ritorno.
BUS INDIRIZZI
28. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
27/63
ANALISI DELLA SFIDA (14/30)
format0.c
Dunque, in base a ciò che è stato detto, la variabile
buffer[] dovrebbe essere posizionata ad un indirizzo
più basso rispetto alla variabile target.
Ciò dipende dal fatto che le variabili definite per ultime si
posizionano al top dello stack (lo stack cresce verso gli
indirizzi bassi)
E’ necessario, però, ricostruire esattamente il layout dello
stack del programma in esame per determinare
esattamente dove sono posizionati i byte della variabile
target che devono essere sovrascritti mediante
overflow per raggiungere l’obiettivo della sfida, ovvero
modificare il flusso di esecuzione del programma.
29. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
28/63
ANALISI DELLA SFIDA (15/30)
E’ necessario eseguire passo passo il programma format0 mediante un debugger per determinare il layout dello stack.
Lo stack frame da analizzare è quello della funzione vuln().
Lo strumento utilizzato per disassemblare file eseguibili binari è GNU Debugger (gdb).
GDB viene invocato con il comando di shell gdb, seguito dal nome del file binario eseguibile.
L’opzione –q consente di evitare la stampa dei messaggi di copyright.
Una volta avviato, GDB legge i comandi dal terminale, fino a che non si digita quit (q).
Il comando print (p) consente di visualizzare il valore di una espressione.
Verrà simulato ciò che fa un attaccante che non ha a disposizione il codice sorgente, andando a disassemblare la
funzione vuln() e capire cosa fa: per fare ciò verrà utilizzato il comando disassemble di gdb.
30. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
29/63
ANALISI DELLA SFIDA (16/30)
Avvio di gdb digitando il seguente comando sul terminale: gdb -q /opt/protostar/bin/format0
Si può notare che gdb aspetta che viene
digitato un comando.
Viene disassemblata la funzione main() digitando il seguente comando gdb: disassemble main
Si può notare che viene invocata la
funzione vuln che è posta
all’indirizzo 0x80483f4: ora è
possibile disassemblare la funzione
vuln() e vedere in dettaglio
l’evolversi dello stack.
31. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
30/63
ANALISI DELLA SFIDA (17/30)
Viene disassemblata la funzione vuln() digitando il seguente comando gdb: disassemble vuln
Dall’analisi del codice assembly della
funzione vuln() è possibile notare che
sono coinvolti alcuni registri, tra cui quelli
legati allo stack:
● Esp (Stack Pointer): punta al top
dello stack.
● Ebp (Base Pointer): consente di
accedere agli argomenti e alle
variabili locali all’interno di un
frame.
32. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
31/63
ANALISI DELLA SFIDA (18/30)
Viene inserito un breakpoint alla prima istruzione di vuln(), per vedere come viene costruito lo stack, digitando il
seguente comando gdb b seguito dal carattere spazio e poi dal carattere * e dall’indirizzo dell’istruzione in formato
esadecimale: b *0x080483f4
Viene eseguito il programma digitando il comando gdb r (il programma viene eseguito fino all’istruzione immediatamente
precedente al breakpoint precedentemente inserito):
Per capire l’evoluzione dello stack è necessario stampare il valore degli indirizzi puntati dai registri EBP ed ESP ad ogni
passo dell’esecuzione (si digita il comando gdb p seguito dal carattere spazio e poi dal carattere $ e il nome del registro):
33. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
32/63
ANALISI DELLA SFIDA (19/30)
:
Segmento di stack
Indirizzo di ritorno
libc_start_main
EBP salvato dello stack
frame precedente
Parametri della funzione
main(): argc, argv, envp
Indirizzo di ritorno
Puntatore al frame della
funzione chiamante
Parametri della funzione
Variabili locali della
funzione
{
{
Stack frame
funzione vuln()
Stack frame
funzione main()
Direzione
di
crescita
dello
stack
(Indirizzi bassi)
(Top dello stack)
:
{
Stack frame della
funzione
_libc_start_main()
(che invoca main())
...
esp
Stack
pointer
(0xbffffd2c)
ebp
Frame
pointer
(0xbffffd48)
eax
Valore di
ritorno
Registri della CPU
BUS INDIRIZZI
(Indirizzi alti)
String
Indirizzo di ritorno
Subito prima dell’esecuzione di
vuln(), l’indirizzo di ritorno è
contenuto nelle cella (di dimensione 4
byte) puntata da ESP, che contiene
l’indirizzo (0xbffffd2c) di tale
cella, ovvero del byte meno
significativo.
34. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
33/63
ANALISI DELLA SFIDA (20/30)
E’ stato appena visto la composizione iniziale dello stack.
Ora si effettuerà una sequenza di istruzioni e si osserverà come si evolve lo stack.
Per eseguire una successiva istruzione assembly passo passo (dopo il breakpoint) si utilizza il
comando si di gdb:
35. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
34/63
ANALISI DELLA SFIDA (21/30)
:
Segmento di stack
Indirizzo di ritorno
libc_start_main
EBP salvato dello stack
frame precedente
Parametri della funzione
main(): argc, argv, envp
Indirizzo di ritorno
Puntatore al frame della
funzione chiamante
Parametri della funzione
Variabili locali della
funzione
{
{
Stack frame
funzione vuln()
Stack frame
funzione main()
Direzione
di
crescita
dello
stack
(Indirizzi bassi)
(Top dello stack)
:
{
Stack frame della
funzione
_libc_start_main()
(che invoca main())
...
esp
Stack
pointer
(0xbffffd2c)
ebp
Frame
pointer
(0xbffffd48)
eax
Valore di
ritorno
Registri della CPU
BUS INDIRIZZI
(Indirizzi alti)
String
Indirizzo di ritorno
Dopo push %ebp:
Viene salvato il valore del registro
EBP all’interno dello stack frame. In
tal modo si può risalire allo stack
frame precedente.
Viene aggiornato lo stack pointer
(esp = esp - 4 byte).
Ebp: 0xbffffd48
36. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
35/63
ANALISI DELLA SFIDA (22/30)
:
Segmento di stack
Indirizzo di ritorno
libc_start_main
EBP salvato dello stack
frame precedente
Parametri della funzione
main(): argc, argv, envp
Indirizzo di ritorno
Puntatore al frame della
funzione chiamante
Parametri della funzione
Variabili locali della
funzione
{
{
Stack frame
funzione vuln()
Stack frame
funzione main()
Direzione
di
crescita
dello
stack
(Indirizzi bassi)
(Top dello stack)
:
{
Stack frame della
funzione
_libc_start_main()
(che invoca main())
...
esp
Stack
pointer
(0xbffffd2c)
ebp
Frame
pointer
(0xbffffd2c)
eax
Valore di
ritorno
Registri della CPU
BUS INDIRIZZI
(Indirizzi alti)
String
Indirizzo di ritorno
Dopo mov %esp, %ebp:
Viene impostato un nuovo valore al
registro ebp, che adesso
corrisponde a quello di esp
(ebp = esp).
Ebp: 0xbffffd48
37. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
36/63
ANALISI DELLA SFIDA (23/30)
:
Segmento di stack
Indirizzo di ritorno
libc_start_main
EBP salvato dello stack
frame precedente
Parametri della funzione
main(): argc, argv, envp
Indirizzo di ritorno
Puntatore al frame della
funzione chiamante
Parametri della funzione
Variabili locali della
funzione
{
{
Stack frame
funzione vuln()
Stack frame
funzione main()
Direzione
di
crescita
dello
stack
(Indirizzi bassi)
(Top dello stack)
:
{
Stack frame della
funzione
_libc_start_main()
(che invoca main())
...
esp
Stack
pointer
(0xbffffcc0)
ebp
Frame
pointer
(0xbffffd2c)
eax
Valore di
ritorno
Registri della CPU
BUS INDIRIZZI
(Indirizzi alti)
String
Indirizzo di ritorno
Dopo sub %0x68, %esp:
Lo stack viene allungato di 104 byte
Viene aggiornato lo stack pointer
(esp = esp - 104 byte).
Ebp: 0xbffffd48
38. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
37/63
ANALISI DELLA SFIDA (24/30)
:
Segmento di stack
Indirizzo di ritorno
libc_start_main
EBP salvato dello stack
frame precedente
Parametri della funzione
main(): argc, argv, envp
Indirizzo di ritorno
Puntatore al frame della
funzione chiamante
Parametri della funzione
Variabili locali della
funzione
{
{
Stack frame
funzione vuln()
Stack frame
funzione main()
Direzione
di
crescita
dello
stack
(Indirizzi bassi)
(Top dello stack)
:
{
Stack frame della
funzione
_libc_start_main()
(che invoca main())
...
esp
Stack
pointer
(0xbffffcc0)
ebp
Frame
pointer
(0xbffffd2c)
eax
Valore di
ritorno
Registri della CPU
BUS INDIRIZZI
(Indirizzi alti)
String
Indirizzo di ritorno
Dopo movl $0x0, -0xc(%ebp):
Viene salvato il valore 0 all’interno
dei 4 byte posti all’indirizzo ebp - 12
byte (è la variabile target).
Ebp: 0xbffffd48
8 byte
Target
4 byte
39. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
38/63
ANALISI DELLA SFIDA (25/30)
:
Segmento di stack
Indirizzo di ritorno
libc_start_main
EBP salvato dello stack
frame precedente
Parametri della funzione
main(): argc, argv, envp
Indirizzo di ritorno
Puntatore al frame della
funzione chiamante
Parametri della funzione
Variabili locali della
funzione
{
{
Stack frame
funzione vuln()
Stack frame
funzione main()
Direzione
di
crescita
dello
stack
(Indirizzi bassi)
(Top dello stack)
:
{
Stack frame della
funzione
_libc_start_main()
(che invoca main())
...
esp
Stack
pointer
(0xbffffcc0)
ebp
Frame
pointer
(0xbffffd2c)
eax
Valore di
ritorno
Registri della CPU
BUS INDIRIZZI
(Indirizzi alti)
String
Indirizzo di ritorno
Dopo mov 0x8(%ebp), %eax:
Viene salvato l’indirizzo ebp + 8 byte
all’interno del registro eax
(eax = ebp + 8 byte)
Ebp: 0xbffffd48
8 byte
Target
4 byte
40. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
39/63
ANALISI DELLA SFIDA (26/30)
:
Segmento di stack
Indirizzo di ritorno
libc_start_main
EBP salvato dello stack
frame precedente
Parametri della funzione
main(): argc, argv, envp
Indirizzo di ritorno
Puntatore al frame della
funzione chiamante
Parametri della funzione
Variabili locali della
funzione
{
{
Stack frame
funzione vuln()
Stack frame
funzione main()
Direzione
di
crescita
dello
stack
(Indirizzi bassi)
(Top dello stack)
:
{
Stack frame della
funzione
_libc_start_main()
(che invoca main())
...
esp
Stack
pointer
(0xbffffcc0)
ebp
Frame
pointer
(0xbffffd2c)
eax
Valore di
ritorno
Registri della CPU
BUS INDIRIZZI
(Indirizzi alti)
String
Indirizzo di ritorno
Dopo mov %eax, 0x4(%esp):
Viene salvato il valore del registro
eax all’interno dei 4 byte posti
all’indirizzo esp + 4 byte.
Ebp: 0xbffffd48
8 byte
Target
4 byte
4 byte
4 byte
41. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
40/63
ANALISI DELLA SFIDA (27/30)
:
Segmento di stack
Indirizzo di ritorno
libc_start_main
EBP salvato dello stack
frame precedente
Parametri della funzione
main(): argc, argv, envp
Indirizzo di ritorno
Puntatore al frame della
funzione chiamante
Parametri della funzione
Variabili locali della
funzione
{
{
Stack frame
funzione vuln()
Stack frame
funzione main()
Direzione
di
crescita
dello
stack
(Indirizzi bassi)
(Top dello stack)
:
{
Stack frame della
funzione
_libc_start_main()
(che invoca main())
...
esp
Stack
pointer
(0xbffffcc0)
ebp
Frame
pointer
(0xbffffd2c)
eax
Valore di
ritorno
Registri della CPU
BUS INDIRIZZI
(Indirizzi alti)
String
Indirizzo di ritorno
Dopo lea -0x4c(%ebp), %eax:
Viene salvato l’indirizzo ebp - 76 byte
all’interno del registro eax, che
corrisponde all’indirizzo della
variabile buffer[].
Ebp: 0xbffffd48
8 byte
Target
4 byte
4 byte
Buffer [0, … ,63]
.
.
4 byte
64 byte
42. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
41/63
ANALISI DELLA SFIDA (28/30)
:
Segmento di stack
Indirizzo di ritorno
libc_start_main
EBP salvato dello stack
frame precedente
Parametri della funzione
main(): argc, argv, envp
Indirizzo di ritorno
Puntatore al frame della
funzione chiamante
Parametri della funzione
Variabili locali della
funzione
{
{
Stack frame
funzione vuln()
Stack frame
funzione main()
Direzione
di
crescita
dello
stack
(Indirizzi bassi)
(Top dello stack)
:
{
Stack frame della
funzione
_libc_start_main()
(che invoca main())
...
esp
Stack
pointer
(0xbffffcc0)
ebp
Frame
pointer
(0xbffffd2c)
eax
Valore di
ritorno
Registri della CPU
BUS INDIRIZZI
(Indirizzi alti)
String
Indirizzo di ritorno
Dopo mov %eax, (%esp):
Lo stack inizia ad essere distrutto;
lo stack pointer adesso punta
all’indirizzo del byte meno
significativo di buffer[].
Ebp: 0xbffffd48
8 byte
Target
Buffer [0, … ,63]
4 byte
64 byte
43. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
42/63
ANALISI DELLA SFIDA (29/30)
Viene chiamata la funzione
sprintf() che memorizzerà il
risultato all’interno della locazione
puntata da eax, quindi la variabile
buffer[] viene popolata con l’input
che è stato fornito in precedenza.
Poi viene controllato se il valore della
variabile target è uguale al valore
0xdeadbeef.
Infine l’istruzione ret preleva l’indirizzo
di ritorno e lo inserisce in EIP.
44. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
43/63
ANALISI DELLA SFIDA (30/30)
Dunque, dopo aver assistito all’evoluzione dello stack, il piano di attacco diventa più chiaro:
Le variabili buffer[] e target sono contigue in memoria centrale.
E’ necessario costruire un input che vada a sovrascrivere opportunamente i 64 byte della variabile
buffer[] e, successivamente, mediante overflow, i 4 byte della variabile target; questi ultimi
devono avere lo specifico valore 0xdeadbeef per modificare il flusso di esecuzione del programma.
Eseguire il programma format0 con tale input.
Come è possibile quindi, “riempire” 68 byte fornendone in input
al massimo 10? Utilizzando le stringhe formattate!!!
String
Indirizzo di ritorno
Ebp: 0xbffffd48
8 byte
Target
4 byte
4 byte
Buffer [0, … ,63]
.
.
4 byte
64 byte
45. FORMATTAZIONE
DELLE STRINGHE
Format Functions e Format
Strings
Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
i
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
44/63
46. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
45/63
FORMATTAZIONE DELLE STRINGHE (1/3)
Che cos’è una Format Function?
● E’ una funzione che prende in input differenti parametri, di cui uno è una “Format String”.
● E’ una funzione di conversione, usata per rappresentare tipi di dati primitivi in C in a una
rappresentazione a stringa leggibile da una persona.
https://cs155.stanford.edu/papers/formatstring-1.2.pdf
Esempi di Format Functions:
fprintf() — Stampa in un FILE stream.
printf() — Stampa nello stream “stdout”.
sprintf() — Stampa in una stringa.
snprintf() — Stampa in una stringa e controlla la lunghezza.
47. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
46/63
FORMATTAZIONE DELLE STRINGHE (2/3)
Che cos’è una Format String?
E’ una stringa in ASCIIZ che contiene testo e parametri di formattazione.
https://cs155.stanford.edu/papers/formatstring-1.2.pdf
Esempio: Il seguente codice formatta il valore “1911” come un numero intero.
printf ("The magic number is: %dn", 1911);
Esempi di Parametri di Formattazione:
● %d -- Decimale (int) -- passato come valore
● %u -- Decimale senza segno (unsigned int) -- passato come valore
● %x -- Esadecimale (unsigned int) -- passato come valore
● %s -- Stringa ((const) (unsigned) char *) -- passato come riferimento
● %n -- Numero di bytes scritti, (* int) -- passato come riferimento
48. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
47/63
FORMATTAZIONE DELLE STRINGHE (3/3)
A cosa bisogna stare attenti?
● Se un attaccante è capace di provvedere una Format String ad una Format Function, in modo
parziale o per intero, è possibile che esista una Format String Vulnerability!
● In base a come usiamo gli specificatori di formato, è possibile perfino leggere e scrivere valori dalla
memoria (con più o meno restrizioni)!
Wrong usage:
int func (char *user) {
printf (user);
}
Ok:
int func (char *user) {
printf ("%s", user);
}
49. STRATEGIA D’ATTACCO Preparazione dell’input, albero di
attacco
Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
i
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
48/63
50. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
49/63
STRATEGIA D’ATTACCO (1/6)
A questo punto si sa che, tramite un Stack-Based Buffer Overflow, è possibile sovrascrivere la variabile target!
La domanda che sorge è la seguente: è’ possibile anche a livello di codice?
Analizzando la documentazione della funzione sprintf(), scopriamo che non effettua controlli sulla taglia dell’input:
51. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
50/63
STRATEGIA D’ATTACCO (2/6)
Quindi è possibile scrivere le prime 64 locazioni della variabile buffer con lo specificatore di formattazione “%64x” per poi
aggiungere la stringa “0xdeadbeef” !
Il costo complessivo della stringa è meno di 10 byte e si può automatizzare il tutto con Python digitando il seguente comando sul
terminale:
Python -c “print ‘%64xxefxbexadxde’”
Una volta passato il tutto in input alla funzione sprintf(), lo specificatore di formattazione “%64x” espanderà la stringa!
E’ possibile effettuare un Stack-Based Buffer Overflow! Ma come è possibile riempire 64 locazioni di memoria utilizzando 10 bytes?
La risposta è sempre nella documentazione della funzione sprintf():
52. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
51/63
STRATEGIA D’ATTACCO (3/6)
ALBERO D’ATTACCO
Sovrascrittura della
variabile target
Login come utente user Preparazione dell’input
Esecuzione di
/opt/protostar/bin/format0
con l’input preparato
Individuazione
formattazione input
Preparazione dell’input
%64 + xefxbexadxde
AND
AND
P
P
P
P
P P
53. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
52/63
STRATEGIA D’ATTACCO (4/6)
Si entra nella cartella contenente il file
eseguibile del programma.
RISULTATO
Si manda in esecuzione il programma
fornendogli l’input costruito.
Si nota che la variabile target è stata
modificata con successo.
54. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
53/63
STRATEGIA D’ATTACCO (5/6)
SFIDA VINTA
55. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
54/63
STRATEGIA D’ATTACCO (6/6)
Se, dopo avere eseguito il programma con lo specifico input, si avvia gdb e si disassembla la funzione vuln() con
gli opportuni comandi visti in precedenza, e si stampano i valori delle variabili buffer[] e target, si può
osservare che l’array buffer[] è stato popolato dal valore esadecimale 0x20 corrispondente ad uno spazio
nella tabella ASCII che corrisponde proprio al valore utilizzato dalle funzioni di formattazione!
I valori dalla 57esima alla 63esima cella sono costituiti da valori spazzatura che la funzione sprintf() ha
lasciato avendo ricevuto un input scorretto!
La variabile target, invece, è stata sovrascritta con successo!
CHE COSA E’ SUCCESSO?
56. INDIVIDUAZIONE DELLE
DEBOLEZZE E
VULNERABILITA’
Debolezze e possibili rimedi degli
attacchi
Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
i
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
55/63
57. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
56/63
INDIVIDUAZIONE DELLE DEBOLEZZE E VULNERABILITA’ (1/8)
Quali sono le vulnerabilità che sono state riscontrate?
● Il buffer non controlla la size dell’input ricevuto.
● Il buffer permette di leggere e scrivere valori arbitrari dallo stack.
● La funzione “sprintf” non effettua nessun controllo o formattazione sulla stringa in input.
● Ci è stato possibile definire una Format String da input esterno come attaccante!
CWE: Stack-Based Buffer Overflow
https://cwe.mitre.org/data/definitions/121.html
CWE: Use of Externally-Controlled Format String
https://cwe.mitre.org/data/definitions/134.html
58. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
57/63
POSSIBILI MITIGAZIONI: BUFFER OVERFLOW
IL CWE in “Mitigation” offre diverse soluzioni ma non sono tutte definite
come “complete solutions”.
Soluzioni non complete:
● Architecture & Design: Usare un layer di Astrazione per API rischiose.
● Build & Compilation: Eseguire e compilare il software con estensioni/features con
meccanismi per mitigare o proteggere dai buffer overflow.
● Operation: Usare meccanismi a livello di OS come ASLR (Address Space Layout Randomization).
INDIVIDUAZIONE DELLE DEBOLEZZE E VULNERABILITA’ (2/8)
Soluzioni più complete:
● Implementation: Implementare controlli sulla lunghezza dell’input.
● Implementation: Usare funzioni capaci di controllare la lunghezza dell’input.
59. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
58/63
IL CWE in “Mitigation” propone mitigazioni semplici ed efficaci:
● Requirement: Quando possibile, non usare linguaggi che possono avere questa debolezza
● Implementation: Far si che alle Format Functions siano passati arguments non modificabili
da un potenziale attaccante. Inoltre bisogna assicurarsi che il numero di arguments passati
sia corretto.
● Build & Compilation: Usare compilatori e linkes capaci di creare warnings per questi casi.
https://cs155.stanford.edu/papers/formatstring-1.2.pdf
POSSIBILI MITIGAZIONI: FORMAT STRING
INDIVIDUAZIONE DELLE DEBOLEZZE E VULNERABILITA’ (3/8)
● Cosa propone il paper di riferimento nelle Hints:
● Far si che l’utente non possa passare delle Format Strings alle funzioni.
● Usare Specificatori di Formato in modo statico e a priori nelle funzioni.
60. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
59/63
Stando a quando detto prima, è necessario utilizzare funzioni capaci di
controllare la size dell’input ricevuto!
Pericolosa:
sprintf()
Possibile mitigazione:
snprintf()
POSSIBILI MITIGAZIONI: SNPRINTF
INDIVIDUAZIONE DELLE DEBOLEZZE E VULNERABILITA’ (4/8)
61. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
60/63
The functions snprintf() and vsnprintf() do not write more than size
bytes (including the terminating null byte ('0')).
If the output was truncated due to this limit then the return value is the
number of characters (excluding the terminating null byte) which would
have been written to the final string if enough space had been available.
Thus, a return value of size or more means that the output was
truncated. (See also below under NOTES.)
If an output error is encountered, a negative value is returned.
POSSIBILI MITIGAZIONI: SNPRINTF
INDIVIDUAZIONE DELLE DEBOLEZZE E VULNERABILITA’ (5/8)
62. int snprintf(char *str, size_t size, const char *format, ...);
*str : Puntatore al Buffer.
size : Numero massimo di bytes (caratteri) scrivibili nel buffer
format : Stringa che contiene una Format String, segue le stesse specifiche di formattazioni della
printf()
Esempio:
int j = snprintf(buffer, 64, stringa_da_scrivere);
Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
61/63
INDIVIDUAZIONE DELLE DEBOLEZZE E VULNERABILITA’ (6/8)
POSSIBILI MITIGAZIONI: BUFFER OVERFLOW
63. Void vuln(char *string){
…
Char buffer[64];
int length;
…
length = snprintf(buffer, 64, string);
if(length > 64){
printf(“Error: max buffer length exceeded! n”)
exit(-1)
}
...
Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
62/63
POSSIBILI MITIGAZIONI: BUFFER OVERFLOW
INDIVIDUAZIONE DELLE DEBOLEZZE E VULNERABILITA’ (7/8)
64. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
63/63
INDIVIDUAZIONE DELLE DEBOLEZZE E VULNERABILITA’ (8/8)
65. Presentazione per il seminario del corso di Programmazione Sicura – prof.ssa Barbara Masucci
Sfida CTF: Protostar Format Zero
Gianmarco Beato e Francesco Maria d’Auria
Giovedì 20 maggio 2021 - a.a. 2020/2021
GRAZIE A TUTTI
PER
L’ATTENZIONE!