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.