Esercitazioni, Competizioni e Test:
LABORATORIO DI SICUREZZA INFORMATICA
a cura di: Francesco (Galt) Faloci
Per poter svolgere l’esercitazione bisogna prima scaricare tre file che spiegheremo nel dettaglio successivamente:
Disattiviamo la prima protezione utilizzate dai
sistemi Linux per la memoria dinamica
Prima di cominciare l’attacco abbiamo bisogno di uno shellcode, ovvero un codice per lanciare una shell
Esso deve essere caricato in memoria così da permetterci di forzare il programma vulnerabile a "saltarci dentro"
Nel nostro caso è un codice assembler "shellcode.c" :
crea un array di caratteri che contiene lo shellcode
all'interno del main copia l’array in un buffer
Compiliamo e lanciamo il file:
Il nostro scopo sarà usare questo shell code in modo da poter aprire una bash con i permessi di root
Passiamo ora a vedere il programma vulnerabile stack.c
Contiene 2 funzioni:
poiché la funzione strcpy() non controlla la lunghezza del buffer, continua a copiare il buffer di input all'interno del buffer locale andando a sovrascrivere il contenuto dello
stack sopra il buffer locale
Il compilatore gcc implementa un meccanismo di sicurezza
chiamato Stack Guard per Prevenire buffer overflows.
In presenza di questa protezione il buffer overflow non lavora
perciò bisogna disabilitarlo compilando il programma con il
flag -fno-stack-protector
Il nostro scopo è quello di creare il contenuto del file badfile in
modo da ottenere una shell con privilegi di root
Per ottenere ciò il nostro badfile dovrà contenere:
Lo shell code presente in badfile sarà copiato nello stack del
programma in modo da provocare un buffer overflow e sarà
eseguito solo se l’indirizzo di ritorno di bof contiene il suo
indirizzo. Dovrà quindi essere piazzato alla giusta distanza dall'inizio del badfile
Per trovare l’indirizzo della variabile buffer in bof() bisogna
prima compilare una copia di stack.c usando i flag di debug
Dallo screen precedente si può vedere che l’indirizzo di buffer è
0xbffff118 mentre quello dell’ebp è 0xbffff138
Calcoliamo la distanza tra di essi...
L'indirizzo del buffer dista dall’ebp 0x20 bytes; nei sistemi a 32bit i puntatori sono lunghi 4 byte
Per questo motivo per arrivare all'indirizzo di ritorno bisogna sommare 4 bytes alla distanza = 0x20+4 = 0x24
Bisogna quindi aggiungere altri 4 bytes a causa dell’indirizzo di ritorno: per iniettare il nostro sarà "indirizzo" + 0x28 bytes
L’indirizzo di ritorno è almeno 0xbffff118 + 0x28 = 0xbffff140
Avendo runnato il programma precedente sotto gdb, ci sono
delle possibilità che lo stack frame sia alcuni bytes sfasato
rispetto alla normale esecuzione
Per incrementare le nostre chance di successo riempiamo il
nostro badfile con istruzioni NOP (una istruzione che fa
avanzare il contatore del programma all'istruzione successiva)
Inseriremo lo shellcode alla fine del file
Modifichiamo quindi il file exploit.cs
Aggiungeremo a exploit.cs:
*((long *) (buffer + 0x30)) = 0xbffff140;
memcpy(buffer + sizeof(buffer) - sizeof(shellcode), shellcode, sizeof(shellcode));
Per verificare che tutto sia stato correttamente compilato:
Eseguendo ora stack, precedentemente salvato coi privilegi di root, avremo:
Riattiviamo la address randomization ed eseguiremo lo stesso attacco sviluppato nel primo task
Essendo dinamica l'allocazione della memoria però, il sistema non ci permette di scrivere in posizioni non idonee...
Bisogna individuare una posizione adeguata quindi...
Per vedere come lavora la randomizzazione modifichiamo il
programma stack.c in modo da stampare l’indirizzo del buffer
Aggiungeremo:
... cambia in continuazione
Per aggirare questa protezione creiamo uno script bash che
ripete all’infinito l’esecuzione dello script
Se siamo fortunati ad un certo punto avverrà una esecuzione
uguale a quella che abbiamo calcolato nello script precedente
... grazie per l'attenzione.