Format string attack: differenze tra le versioni
Contenuto cancellato Contenuto aggiunto
Etichette: Inserimento di parole incomprensibili Sequenze di caratteri ripetuti da parte di un nuovo utente o IP Modifica visuale: commutato |
|||
Riga 46:
Ogni "%s" cerca di visualizzare il contenuto della memoria da un certo indirizzo presente sullo stack fino al carattere terminatore.
Inserendo quindi molti “%s”, la probabilità di andare a leggere da un “illegal address” (cioè un indirizzo non mappato per questa funzione) sono molto elevate e se succede, causeremmo l’errore “''segmentation fault”'' crashando quindi il programma.
'''Leggere lo stack'''
Utilizzando sempre la printf, potremmo andare a leggere parte del contenuto dello stack, usando una format string di questo tipo:
<source lang="c">printf( "%08x-%08x-%08x-%08x-%08x\n");</source>
l'output potrebbe essere il seguente:
<source lang="c">4306ea40-43074920-0062de90-70706970-02000002</source>
Il parametro di formato "%08x" dice alla printf() di mostrare sei parametri salvati sullo stack visualizzando in formato esadecimale a 8 cifre.
In certi casi potremmo anche essere in grado di ricostruire tutta memoria occupata dallo stack contenere importanti informazioni sul flusso del programma, sulle variabili locali di funzioni e su indirizzi permettendoci di calcolare l’esatto offset da usare per effettuare l’exploit.
'''Leggere memoria in ogni locazione di memoria'''
E’ possibile anche leggere aree di memoria diverse dallo stack. Dobbiamo però creare una format function che visualizza il contenuto della memoria all’indirizzo che gli forniamo.
Ci servirà quindi l’indirizzo da cui andare a leggere ed il giusto parametro di formato per leggerlo. Il parametro di formato che useremo sarà: "%s" che visualizzerà il contenuto dell’area di memoria in formato stringa ASCII (da un indirizzo memorizzato sullo stack).
La nostra format function mantiene all’interno dello stack il puntatore alla locazione di memoria del parametro di formato.
Se fossimo in grado di far puntare quel puntatore all’area di memoria che ci interessa, potremmo dare quell’indirizzo al formato parametro "%s" così che, invocando la printf(), questa leggerà la memoria da quell’indirizzo fino a che non trova un carattere terminatore ‘0’
Utilizzando ad esempio la seguenti stringa di formato:
<source lang=c> ("AAA0AAA1_%08x.%08x.%08x.%08x.%08x"); </source>
la sequenza di "%08x" incrementa il puntatore interno della format function verso il top dello stack. Dopo alcuni di questi incrementi, lo stack pointer punterà esattamente alla nostra format string.
Se scegliamo il numero giusto di ‘%08x’ potremmo visualizzare la memoria da un qualsiasi indirizzo mettendo alla fine delle stringa un format parametro ‘%s’
Bisogna quindi sostituire la parte iniziale della format string con un vero indirizzo.
Vogliamo leggere aree di memoria vicino a questo indirizzo ‘0x08480110’:
La codifica dell’indirizzo scelto in una stringa a 32 bit "\x10\x01\x48\x08" dove il carattere ‘\x10’ inserito in una stringa dice al compilatore di mettere un caratere esadecimale di valore 0x10 nella posizione corrente. Senza \x il valore ASCII che verrebbe salvato nella stringa sarebbe ‘1’ e ‘0’ i cui rispettivi valori ASCII sono ‘49’ e ‘48’
<source lang=c> printf ("\x10\x01\x48\x08_%08x.%08x.%08x.%08x.%08x|%s|"); </source>
Quindi la seguente invocazione andrà a leggere memoria dall’indirizzo che gli abbiamo fornito finchè non raggiunge un NULL byte.
Incrementando l’indirizzo di memoria dinamicamente possiamo mappare l’intera memoria di processo
Se si passa a una funzione che stampa una stringa a schermo (un esempio classico è la funzione [[printf]] del [[C (linguaggio)|linguaggio C]]) una stringa che in realtà contiene una serie di parametri di specifica dell'input (tipicamente si usano identificatori di formato ''%s'' e ''%x'' per esaminare il contenuto della memoria e ''%n'' per sovrascrivere parti della memoria, in particolare dello [[stack]]) si permette l'avvio di un attacco di tipo [[stack overflow]] e ''return to libc''. Per proteggersi da questo attacco, quando si vuole stampare una stringa ''s'' usando la printf() o una qualsiasi funzione C che accetti un numero illimitato di identificatori di formato, bisogna scrivere la funzione
|