Perché un attacco ret2libc deve seguire l'ordine "system (), exit (), comando?

5

In un attacco ret2libc, capisco che l'indirizzo di ritorno può essere sovrascritto con l'indirizzo del comando di sistema, che accetta una stringa di comando come argomento. In questo caso, l'indirizzo della stringa di comando non dovrebbe venire direttamente dopo l'indirizzo di system ()? Tuttavia, la maggior parte delle esercitazioni che ho visto seguono il formato: indirizzo di system () indirizzo di exit () indirizzo della stringa di comando.

Perché è obbligatorio includere l'indirizzo di exit ()? L'attacco funzionerà ancora se exit () è escluso?

    
posta Lew Wei Hao 12.09.2016 - 23:31
fonte

2 risposte

6

La tecnica ret2libc (e return oriented programming (ROP)) si basa sulla sovrascrittura dello stack per creare un nuovo stack frame che chiama la funzione di sistema. Questo articolo di wikipedia spiega in modo dettagliato i frame dello stack: link

Il frame dello stack impone l'ordine in cui vengono scritti la chiamata alla funzione e i parametri:

function address return address parameters

Quindi nel tuo esempio vuoi chiamare system() con cmdstring e tornare alla funzione exit() quando ritorna la chiamata system() . Quindi scrivi il seguente stack:

system_addr exit_addr cmdstring_addr

Se rimuovi l'indirizzo di uscita, modifica il frame dello stack nel modo seguente:

system_addr cmdstring_addr existingdataonstack_aka_junk

Quindi ora stai chiamando system() con un argomento indirizzo spazzatura e provando a tornare nella stringa di comando una volta che la funzione è stata completata. Questo è il motivo per cui fallisce. Puoi sostituire l'indirizzo exit() con altri dati come 0x41414141 che causerà un segfault una volta completata la chiamata a system() . Oppure puoi sostituirlo con l'indirizzo di una posizione pop pop ret e quindi scrivere più frame di stack sotto. Questo è ora un carico utile ROP . Ecco un esempio di base di come apparirebbe nello stack:

system_addr poppopret_addr cmdstring_addr printf_addr exit_addr addr_of_string_to_printf

Ciò ti consentirebbe di stampare qualcosa come You got hacked prima di uscire.

    
risposta data 13.09.2016 - 02:08
fonte
1

La ragione per cui exit() è inclusa è di terminare il programma con garbo . Se non si dispone di exit() alla fine della catena, il programma continuerà a funzionare in modo strano o molto probabilmente terminerà con un errore di segmentazione. Non è obbligatorio includere una chiamata a exit() . Idealmente costruirai il tuo exploit in modo tale che il programma continui a funzionare come al solito, quindi nessuno si insospettirà perché il loro servizio non è più in esecuzione.

    
risposta data 13.09.2016 - 12:23
fonte