Buffer overflow: differenze tra le versioni

Contenuto cancellato Contenuto aggiunto
Baxi89 (discussione | contributi)
Baxi89 (discussione | contributi)
Aggiunta sezione Heap Overflow e paragrafo sulla sovrascrittura del frame pointer in Stack Buffer Overflow
Riga 23:
Per i linguaggi di basso livello, come l’assembly, i dati sono semplici array di byte, memorizzati in registri o in memoria centrale: la corretta interpretazione di questi dati (indirizzi, interi, caratteri, istruzioni ecc…) è affidata alle funzioni e alle istruzioni che li accedono e manipolano; utilizzando linguaggi di basso livello si ha dunque un maggiore controllo delle risorse della macchina, ma è richiesta una maggiore attenzione in fase di programmazione in modo da assicurare l’integrità dei dati (e quindi evitare fenomeni come il buffer overflow). I linguaggi di più alto livello, come il Java e il Python (e molti altri), che definiscono invece il concetto di tipo di una variabile e che definiscono un insieme di operazioni permesse a seconda della tipologia, non soffrono di vulnerabilità come il buffer overflow, perché non consentono di memorizzare in un buffer una quantità maggiore di dati rispetto alla sua dimensione. Fra questi due estremi si trova il linguaggio C che presenta alcune delle astrazioni tipiche dei linguaggi di alto livello insieme a elementi tipici dei linguaggi di basso livello, come la possibilità di accedere e manipolare indirizzi di memoria: ciò rende il linguaggio suscettibile ad usi inappropriati della memoria; se a questo si unisce il fatto che alcune librerie di funzioni molto diffuse (in particolare per l’input e la manipolazione di stringhe come la gets() ) non effettuano un corretto controllo della dimensione dei buffer su cui lavorano, e che il C è stato usato negli anni ’70 per scrivere il sistema operativo UNIX (e da questo sono poi derivati i sistemi come Linux) e molte delle applicazioni pensate per eseguire su di esso, ne consegue che ancora oggi è presente e circola una grande quantità di codice vulnerabile al buffer overflow. <ref name=":0">{{Cita libro|autore=William Stallings, Lawrie Brown|titolo=Computer Security - Principles and Practice|anno=2015|editore=Pearson|città=|p=|pp=|ISBN=978-0-133-77392-7}}</ref>
 
== Tipi di buffer overflow e conseguenzepossibili attacchi ==
Il buffer overflow può essere indicato con diversi nomi a seconda della posizione occupata dal buffer all’interno della memoria allocata per il processo.
 
Riga 60:
Quando il buffer è allocato nello stack, ovvero è una variabile locale di una funzione, l’eventuale immissione all’interno del buffer di una quantità di dati superiore alla sua portata prende il nome di '''stack buffer overflow''' (o '''stack smashing''', o '''stack-based buffer overflow''').
 
In questo caso i dati adiacenti al buffer sonoche ilpotrebbero returnessere addresssovrascritti edai ildati frame''extra'' pointer: al termine dell’esecuzione la funzione tenta di restituiresono il controllo all’istruzione puntata dal return address che,e seil èframe stato sovrascritto dai dati in eccesso del buffer, può contenere:pointer.
 
* L’indirizzo di un’area di memoria non accessibile: i dati in eccesso sono casuali, il programma va in crash restituendo tipicamente un [[Errore di segmentazione|segmentation fault]]. E’ un esempio di come lo stack buffer overflow può essere utilizzato come attacco del tipo [[Denial of Service|denial-of-service]] (DoS), compromettendo la disponibilità del servizio colpito.
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 [[Errore di segmentazione|segmentation fault]]. E’ un esempio di come lo stack buffer overflow puòpossa essere utilizzato come attacco del tipo [[Denial of Service|denial-of-service]] (DoS), compromettendo la disponibilità del servizio colpito.
* 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. <ref name=":0" />
 
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" />
E’ importante non confondere [[stack overflow]] e stack buffer overflow: 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à=|p=|pp=|ISBN=978-1-59327-144-2}}</ref>
 
E’Infine importantebisogna nonricordare confondereche [[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à=|p=|pp=|ISBN=978-1-59327-144-2}}</ref>
 
=== Heap overflow ===
Un programma può richiedere al sistema operativo di allocare dinamicamente una certa quantità di memoria nell'area [[heap]], sfruttando chiamate di sistema come ''malloc()'' e ''free''() in C/UNIX. Questi buffer possono ugualmente essere suscettibili a problemi di overflow nel momento in cui vi si possa inserire una quantità di dati superiore alla memoria allocata, e questi dati andrebbero come al solito a sovrascrivere le aree di memoria adiacenti al buffer.
L'heap overflow avviene quando vi è un eccesso di dati in ingresso nell'area [[heap]] della memoria. Solitamente i cracker generano volutamente degli heap overflow per perforare programmi scritti in modo non impeccabile.
 
Si parla in questi casi di '''heap overflow''', ma a differenza dello stack, nell'area heap non sono memorizzati né indirizzi di ritorno, né frame pointer che possano essere alterati da un attaccante per trasferire il controllo dell'esecuzione a codice arbitrario. Tuttavia questo non significa che tali anomalie non costituiscano delle vulnerabilità pericolose: nel 2002 fu riscontrata una vulnerabilità di tipo heap overflow in un'estensione di Microsoft IIS che poteva essere sfruttata per eseguire codice arbitrario proprio su questa tipologia di server. <ref>{{Cita web|url=http://www.kb.cert.org/vuls/id/363715|titolo=Vulnerability Note VU#363715 - Microsoft Internet Information Server (IIS) vulnerable to heap overflow during processing of crafted ".htr" request by "ISM.DLL" ISAPI filter|sito=www.kb.cert.org|accesso=2016-08-19}}</ref>
 
Quando un programma presenta diverse funzioni che eseguono la stessa operazione ma in modo diverso (ad esempio il ''sorting''), e si desidera stabilire a ''runtime'' quale utilizzare per processare i dati in ingresso, spesso si usa memorizzare dei puntatori a funzione nell'area heap: questi puntatori contengono gli indirizzi iniziali delle funzioni, e vengono utilizzati per richiamarne successivamente l'esecuzione. In uno scenario del genere, un attaccante potrebbe sfruttare l'overflow di un buffer allocato sullo heap per sovrascrivere tali puntatori, sostituendoli con un puntatore allo shellcode iniettato attraverso l'overflow: la successiva chiamata a una delle funzioni comporterebbe il trasferimento del controllo allo shellcode invece che alla funzione attesa.<ref>{{Cita web|url=https://www.sans.org/reading-room/whitepapers/threats/buffer-overflows-dummies-481|titolo=Buffer Overflows for Dummies - SANS Institute}}</ref>
 
== Voci correlate ==