Buffer overflow: differenze tra le versioni
Contenuto cancellato Contenuto aggiunto
Recupero di 2 fonte/i e segnalazione di 0 link interrotto/i.) #IABot (v2.0.1 |
Nessun oggetto della modifica |
||
Riga 68:
Se i dati in eccesso sovrascrivono frame pointer e return address, al termine dell’esecuzione la funzione tenterebbe di restituire il controllo all’istruzione puntata dal return address che potrebbe contenere:
* L’indirizzo di un’area di memoria non accessibile: i dati in eccesso sono casuali, il programma va in crash restituendo tipicamente un [[
* Un indirizzo di memoria ben preciso: i dati in eccesso sono calcolati in modo da sovrascrivere il return address con l’indirizzo di un’area di memoria a cui l’attaccante vuole avere accesso, o con l’indirizzo in cui si trova il codice che l’attaccante vuole eseguire.
In questo secondo caso rientrano gli attacchi basati sull’iniezione di [[shellcode]]; i dati inseriti all’interno del buffer contengono codice eseguibile in linguaggio macchina ([[assembly]]), e la sovrascrittura del return address viene fatta in modo da rimandare al codice iniettato all’interno del buffer. Compito di tale codice è normalmente quello di richiamare un’interfaccia a riga di comando, ovvero una [[Shell (informatica)|shell]], motivo per cui tale codice è detto shellcode (una chiamata alla funzione ''execve'' che esegue la Bourne shell per i sistemi UNIX, una chiamata a ''system(“command.exe”)'' nei sistemi Windows). In ogni caso il programma in esecuzione viene sostituito dalla shell, che eseguirà con gli stessi privilegi del programma di partenza.
Esiste una variante di questo tipo di attacco che si basa sulla sostituzione solo del frame pointer, e che può essere utilizzata quando l'overflow consentito è limitato e non permette di arrivare alla sovrascrittura del return address. L'attacco consiste nello sfruttare l'overflow per sostituire il frame pointer memorizzato in modo da farlo puntare a uno stack frame fasullo, iniettato all'interno del buffer insieme allo shellcode; in questo ''stack frame'' fasullo l'attaccante ha inserito come return address un puntatore allo shellcode: quando la funzione colpita termina la sua esecuzione, quindi, restituisce correttamente il controllo alla funzione chiamante (il return address infatti non è stato cambiato), ma questa riprenderà l'esecuzione con un contesto fasullo e, quando a sua volta anche lei terminerà di eseguire, il controllo verrà infine trasferito allo shellcode (poiché in questo stack frame è stato alterato il RA in modo da puntare al codice maligno). Gli attacchi [[Off-by-one error|off-by-one]] si basano proprio su questo principio: se per un errore di scrittura il programmatore consente l'immissione all'interno di un buffer anche solo di un byte in più del dovuto (usando ad esempio un <= invece del ''<'' nel test di una condizione di controllo), questo semplice byte in più potrebbe essere utilizzato da un attaccante per modificare il frame pointer memorizzato a sufficienza da farlo puntare ad uno stack frame fasullo, e ottenere quindi indirettamente il trasferimento del controllo al codice maligno iniettato.<ref name=":0" />
Infine bisogna ricordare che [[stack overflow]] e stack buffer overflow non sono sinonimi: il primo indica una situazione per cui si richiede una quantità troppo elevata di memoria nello stack, il secondo una situazione in cui (per varie ragioni) si inserisce in un buffer nello stack una quantità di dati più grande della capacità del buffer stesso.<ref>{{Cita libro|autore=Jon Erickson|titolo=Hacking - The Art of Exploitation|anno=2008|editore=No Starch Press|città=|ISBN=978-1-59327-144-2}}</ref>
Riga 93:
La miglior difesa da attacchi basati sul buffer overflow sta nella scelta di un linguaggio di programmazione che fornisca controlli automatici sulla dimensione dei buffer (o a tempo di compilazione o a ''runtime'') come Java, Python o Perl. Se questa opzione può essere presa in considerazione per lo sviluppo di nuovi programmi, resta però difficilmente applicabile nel caso di progetti esistenti, in cui ciò comporterebbe la riscrittura del codice nel nuovo linguaggio.<ref name=":1" />
Un'alternativa consiste nell'utilizzo di ''safe libraries'', ovvero librerie di funzioni che implementano protezioni contro il buffer overflow: in C rappresentano funzioni vulnerabili ''strcat'', ''strcpy'', ''gets'', ''sprintf'' (e altre ancora...) di cui esistono controparti "sicure" come ''strncpy'', ''strncat'', ''snprintf''. Un esempio di queste ''safe libraries'' sono "libsafe", "libparanoia" e "libverify".<ref>{{Cita web|url=https://www.freebsd.org/doc/en/books/developers-handbook/secure-bufferov.html|titolo=3.3. Buffer Overflows|sito=www.freebsd.org|accesso=31 agosto 2016}}</ref> Libsafe, ad esempio, implementa una tecnica di protezione dallo stack buffer overflow basata sul controllo di eventuali alterazioni dello stack quando una funzione termina di eseguire: se lo stack risulta modificato, il processo termina con un [[
=== Difese a livello di codice sorgente ===
Riga 100:
"Its4" è un semplicissimo esempio di analizzatore statico che effettua la ricerca di eventuali chiamate di funzioni vulnerabili note (come ''strcpy'' o ''popen''), pensato come sostituzione alla ricerca tramite ''grep'': data la sua semplicità e la rudimentale analisi del codice che realizza è molto facile incappare in falsi positivi e negativi.<ref>{{Cita web|url=http://seclab.cs.ucdavis.edu/projects/testing/tools/its4.html|titolo=Its4}}</ref>
In alternativa esistono tool più complessi in grado di effettuare l'analisi dinamica del programma, come "Rational Purify", un debugger di memoria realizzato da IBM in grado di individuare eventuali anomalie nella gestione della memoria durante l'esecuzione del programma (accesso a variabili non inizializzate, ''buffer
=== Difese a livello di compilatore ===
Riga 109:
Approccio differente è invece quello di "StackShield", un'estensione del compilatore ''gcc'' per la protezione dallo stack smashing nei sistemi Linux; anziché inserire a tempo di compilazione i controlli per il ''bounds checking'' dei buffer, l'obiettivo di StackShield è quello di impedire la sovrascrittura dei ''return address'' memorizzandone una copia in una zona sicura non sovrascrivibile (all'inizio del segmento dati) all'inizio di ogni chiamata di funzione, copia che viene poi confrontata al termine dell'esecuzione della funzione con il valore memorizzato nello stack: se i valori non combaciano StackShield può terminare l'esecuzione del programma o tentare di proseguire ignorando l'attacco e rischiando al massimo il crash del programma.<ref>{{Cita web|url=http://www.angelfire.com/sk/stackshield/info.html|titolo=StackShield}}</ref>
Un'altra estensione del compilatore ''gcc'', "StackGuard", consente sia la rivelazione di eventuali ''stack buffer'' overflow sia la prevenzione degli stessi: la prima difesa tuttavia risulta molto più efficiente e portabile della seconda, in generale meno affidabile e sicura. La rivelazione si basa sulla scrittura nello ''stack frame'' di una ''canary'' ''word'' fra le variabili locali e il ''return address'' memorizzato e sull'assunto che non sia possibile sovrascrivere il RA senza alterare la ''canary word'', che prende quindi questo nome proprio in analogia all'uso dei [[Canarino domestico|canarini nelle miniere di carbone]] come primo sistema di allarme. Prima di restituire il controllo all'istruzione puntata dal RA, si controlla se la ''canary word'' ha subito alterazioni: eventuali modifiche vengono considerate come un potenziale tentativo di alterare il controllo dell'esecuzione del programma e quindi di attacco. La tecnica adottata da StackGuard è efficace solo se l'attaccante non è in grado di prevedere la ''canary word'', in questo caso sarebbe infatti in grado di progettare l'overflow in modo da sovrascrivere la ''canary word'' con il suo valore originale: StackGuard a questo scopo esegue la randomizzazione del ''canary''.<ref>{{Cita web|url=https://www.usenix.org/legacy/publications/library/proceedings/sec98/full_papers/cowan/cowan.pdf|titolo=StackGuard: Automatic Adaptive Detection and Prevention of Buffer-Overflow Attacks}}</ref>
=== Difese a livello di sistema operativo ===
Riga 156:
*[[Attacco man in the middle|Man-in-the-middle]]
*[[LIFO]]
*[[Errore di segmentazione
*[[Denial of Service|Denial-of-service]]
*[[Assembly]]
|