Ogni vulnerabilità ha una causa specifica, che a sua volta porta a sfruttare la vulnerabilità. È difficile capire come si possa sfruttare qualcosa di astratto e ottenere risultati astratti, ma è molto più facile da capire se illustrato con esempi. Il più semplice sarebbe il classico overflow del buffer basato su stack:
void f(const char *str) {
char buf[10];
strcpy(buf, str);
}
Questo è un esempio primitivo che dovrebbe essere sufficiente per dimostrare il problema. Supponiamo che l'argomento str
punti a una stringa con terminazione NULL più lunga dei 10 caratteri allocati per la variabile in fase di copia. Cosa accadrà? strcpy()
copierà ciecamente i dati oltre la fine del buffer, sovrascrivendo quello che c'era. Ma cosa esattamente è lì?
Su x86, ad esempio, la variabile buf
verrebbe allocata nello stack. Lo stack viene anche utilizzato per salvare l'indirizzo di ritorno quando viene eseguita un'istruzione CALL
. Quindi il layout dello stack (semplificato) sarà simile a questo (gli indirizzi aumentano dall'alto al basso):
...
buf[0..3]
buf[4..7]
buf[8..9]
return address
...
Quindi, fornendo una stringa troppo lunga tramite l'argomento str
, saremmo in grado di sovrascrivere l'indirizzo di ritorno da f()
. Se l'attaccante è in grado di controllare la stringa, allora può controllare dove andrà il flusso di controllo dopo il ritorno di f()
. Ciò può verificarsi quando si analizza un file appositamente predisposto, ad esempio.
La prossima cosa sarebbe dirigere il controllo su un'istruzione JMP ESP
o simile in effetti, causando l'esecuzione del codice dallo stack. Questa esecuzione "diretta" del codice è impedita da DEP.
Ovviamente, l'esempio precedente non include il bypass di nessuna delle mitigazioni moderne (stack canaries, SafeSEH, DEP). Ciò non significa che sia globalmente impossibile, ma potrebbe essere impossibile in alcuni casi. Bypassare il DEP di solito implica programmazione orientata al ritorno - invece del codice stesso, i dati appositamente predisposti vengono messi in pila, che utilizza frammenti di funzioni già esistenti nell'immagine di processo (chiamati gadget) per eseguire il codice. Questo, a sua volta, viene mitigato da ASLR, rendendo gli indirizzi del gadget un po 'imprevedibili. Esistono anche tecniche per aggirare l'ASLR.
Se vuoi mettere le mani sullo sfruttamento di programmi reali, ti suggerisco corelanc0d3r come punto di partenza.
EDIT : sostituisce la parte che causa l'errore.