Ci sono due "incognite" con cui l'attaccante deve fare i conti.
In primo luogo, l'attaccante sta traboccando un buffer, presumibilmente in pila, e tra i byte che seguono il buffer in RAM sono i byte che memorizzano il "indirizzo di ritorno" in cui l'esecuzione salta dopo che la funzione corrente è finita. L'autore dell'attacco desidera sovrascrivere questi byte con un altro indirizzo, facendo in modo che la CPU salti nel codice scritto dall'attaccante. La prima incognita è quindi: "qual è la distanza tra il buffer (che è overflow) e lo slot di indirizzo di ritorno?". L'attaccante deve indovinare che, per sapere a quale punto dei dati forniti dall'attaccante deve essere impostata la "sostituzione dell'indirizzo di ritorno".
La seconda sconosciuta è l'indirizzo effettivo del suo codice shell. In un buffer overflow tradizionale nello stack, il codice shell è parte dei dati che attivano l'overflow, cioè nel buffer. L'indirizzo di ritorno è absolute quindi non è sufficiente che l'attacker conosca il codice della funzione attaccata; l'attaccante deve anche sapere qual è la profondità dello stack in quel momento, e questo dipende dal comportamento dell'applicazione precedente.
La diapositiva NOP , o la slitta NOP, è una tecnica semplice per far fronte al problema di precisione per il secondo sconosciuto. Quando l'utente malintenzionato indovina l'indirizzo del suo codice shell con qualche possibile jitter, l'autore dell'attacco mette un sacco di nop
opcodes (o opcode altrettanto innocui) prima del suo codice shell; quindi, è sufficiente che la CPU salti da qualche parte nella slitta per poter raggiungere, in definitiva, il codice shell.
Per la prima sconosciuta, lo strumento non è una slitta NOP, ma un altro tipo di slitta. In poche parole, l'overflow completo sarà simile a questo:
90 90 90 90 90... 90 shellcode addr addr addr... addr
dove shellcode
è il payload effettivo, 90
è il codice esadecimale per l'opcode nop
e addr
è l'ipotesi dell'attaccante dell'indirizzo di avvio del buffer nella RAM. Quando si verifica l'overflow, uno dei valori di addr
sovrascrive lo slot dell'indirizzo di ritorno e fa saltare la CPU all'indirizzo addr
; quale del addr
fa il trucco è la "prima sconosciuta" descritta sopra. Di solito, il "primo sconosciuto" non è così sconosciuto, perché dipende solo dal layout delle variabili locali nella funzione stessa, che è noto attraverso il reverse-engineering (disassembly).
L'autore dell'attacco ha intuito che il byte all'indirizzo addr
sarà uno di 90
, quindi l'esecuzione salta lì. Quale non è molto importante, perché la CPU procederà ad eseguire tutti i successivi nop
opcode e quindi raggiungere lo shellcode.
Le foto che mostri sono davvero piuttosto confuse. Sembrano riferirsi a casi più complessi in cui l'attaccante, per qualche motivo, non può mettere immediatamente il suo codice shell dopo la slitta NOP, ma in qualche posto prima la slitta NOP, quindi deve quindi organizzare un salto appropriato alla fine della slitta (i codici operativi di salto usano l'indirizzamento relativo, in modo che il salto sia facile da ottenere a destra).