Format string attack: differenze tra le versioni
Contenuto cancellato Contenuto aggiunto
Etichette: Sequenze di caratteri ripetuti da parte di un nuovo utente o IP Modifica visuale |
|||
Riga 45:
Un modo molto semplice per mandare in crash un programma è passando alla funzione printf() una stringa formattata in questo modo: <source lang="c">printf("%s%s%s%s%s%s%s%s%s%s%s");</source>
Ogni "%s" cerca di visualizzare il contenuto di un buffer di caratteri (una stringa) dall'indirizzo iniziale presente sullo stack fino al carattere terminatore ("0"). Inserendo quindi molti “%s", la funzione sposterà il puntatore in avanti fino ad aree di memoria non mappate nel frame dell'applicazione, così facendo cercherà di leggere da "indirizzi illegali", causando l'errore “''segmentation fault”'' che manda in crash il programma.
'''Leggere lo stack'''
Utilizzando sempre la printf(), è possibile leggere parte del contenuto dello stack, usando una format string di questo tipo:
<source lang="c">printf(
l'output potrebbe essere il seguente:
<source lang="c">4306ea40-43074920-0062de90-70706970-02000002</source>
Questo perché essendo il numero degli argomenti della printf() variabili, questa utilizza la format string per sapere quanti gliene sono stati passati. In questo caso quindi crede (erroneamente) che siano cinque parametri, e andrà quindi a stampare i prossimi cinque indirizzi sullo stack, pensando siamo i parametri richiesti.
Il parametro di formato "%08x" è costituito dai seguenti componenti:
* x (converti i carratteri in esadecimale), * 8 (mostra otto caratteri), * 0 (riempi di zeri i caratteri nulli, se presenti). '''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.
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’.▼
▲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"> printf ("
[[File:StackMemory.png|miniatura|446x446px|Salvataggio variabili sullo stack]]
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
Bisogna quindi sostituire la parte iniziale della format string con un vero indirizzo. ▼
▲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.
▲Bisogna quindi sostituire la parte iniziale della format string con un vero indirizzo.
Vogliamo leggere aree di memoria vicino a questo indirizzo ‘0x08480110’:
* Per prima cosa bisogna codificare l'indirizzo in una stringa a 32 bit secondo la regola little-endian.
* l'indirizzo "0x08480110" verà quindi ribaltato e separato da caratteri speciali diventando: "\x10\x01\x48\x08"
La codifica dell’indirizzo scelto in una stringa a 32 bit "\x10\x01\x48\x08" dove il carattere
▲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.▼
▲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!
== Voci correlate ==
|