Sicurezza Informatica

Esercitazioni, Competizioni e Test:
LABORATORIO DI SICUREZZA INFORMATICA
a cura di: Francesco (Galt) Faloci
General Software Security
-
General Software Security
- Buffer Overflow
- Format String
BUF-...WHU?
- E’ il più comune tra tutti i tipi di insicurezza nel
codice C
- E’ quasi del tutto assente nei linguaggi ad alto
livello che non permettono la gestione diretta
della memoria
- Consiste nel forzare la scrittura in memoria con una quantità di informazione superiore a quella accettabile
- Se il software è privo di controlli è possibile
inserire del codice eseguibile in queste stringhe di
overflow
- Può essere eseguito nello stack, nell’heap e nel
BSS(block started by symbol, contiene variabili
statiche)
BUF-...WHU?
Per poter svolgere l’esercitazione bisogna prima scaricare tre file che spiegheremo nel dettaglio successivamente:
- call_shellcode.c
- exploit.c
- stack.c
BUF-...WHU?
Weird thing
Disattiviamo la prima protezione utilizzate dai
sistemi Linux per la memoria dinamica
- - sudo sysctl -w kernel.randomize_va_space=0
- - sudo sysctl kernel.randomize_va_space (verifica)
First Try
-
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
-
First Try
Compiliamo e lanciamo il file:
- gcc -z execstack -o call_shellcode call_shellcode.c
- ./call_shellcode
- > id (vedere che siamo ancora seed)
First Try
Il nostro scopo sarà usare questo shell code in modo da poter aprire una bash con i permessi di root
- sudo chown root call_shellcode (pass di seed)
- sudo chmod u+s call_shellcode
- ./call_shellcode
- > id (vedere che NON siamo seed)
Second Try
Passiamo ora a vedere il programma vulnerabile stack.c
Contiene 2 funzioni:
- Main(): legge il contenuto di un file chiamato badfile da un buffer di lunghezza 517 byte
- Bof(): prende come parametro l’indirizzo del buffer precedente e ne copia il contenuto in un buffer locale
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
Second Try
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
Second Try
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 shellcode
- Indirizzo dello shell code
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
Second Try
- Trovare l’indirizzo della variabile buffer[ ] nel metodo bof
- Trovare la distanza dell’indirizzo di ritorno dalla variabile buffer
- Trovare la distanza dello shell code dalla variabile buffer
- Dato 1) e 3), trovare l’indirizzo a nel quale posizionare lo shellcode
- Dato 2) e 4), inserire l’indirizzo citato sopra alla giusta distanza dall'inizio di badfile
Second Try
Per trovare l’indirizzo della variabile buffer in bof() bisogna
prima compilare una copia di stack.c usando i flag di debug
- gcc -z execstack -fno-stack-protector -g -o stack_dbg stack.c
- touch badfile
- gdb stack_dbg
- b bof
- x &buffer (indirizzo di buffer)
- x $ebp (indirizzo dell'ebp)
Second Try
Second Try
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
Second Try
Second Try
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
Second Try
Second Try
Aggiungeremo a exploit.cs:
*((long *) (buffer + 0x30)) = 0xbffff140;
memcpy(buffer + sizeof(buffer) - sizeof(shellcode), shellcode, sizeof(shellcode));
Second Try
Per verificare che tutto sia stato correttamente compilato:
- gcc exploit.c -o exploit
- hexdump -C badfile
Second Try
Eseguendo ora stack, precedentemente salvato coi privilegi di root, avremo:
Third Try
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...
Third Try
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:
- printf("%p/n", &buffer);
Third Try
... cambia in continuazione
Third Try
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
/end

... grazie per l'attenzione.
CSLESS3
By frafolo
CSLESS3
- 207