L'idea di utilizzare più spazio di quello che ti è stato dato, e quindi riversare in un campo diverso è abbastanza semplice da visualizzare. Ma probabilmente non è chiaro come questo possa portare a un cattivo ragazzo che esegue il proprio codice.
Questo è abbastanza semplice da spiegare se lo capisci abbastanza bene. Assicurati di colpire sullo sfondo importante. Più o meno in questo ordine:
-
Lo "stack" è un luogo in cui è possibile memorizzare informazioni temporanee. Il "puntatore dello stack" determina dove si trova la fine della pila. Quando una funzione viene eseguita, sposta il puntatore dello stack per darsi da solo la memoria con cui lavorare e, una volta terminato, sposta il puntatore sul punto in cui è stato trovato.
-
Lo stack cresce all'indietro. Quindi, per darti 100 byte nello stack, sottrarre 100 dal puntatore dello stack piuttosto che aggiungerlo. Se lo stack della funzione precedente è iniziato a 1000 e voglio 100 byte, il mio stack inizia a 900.
-
Ciò significa che se usi più spazio di quello che hai dato tu stesso, non continuerai a scrivere nello spazio vuoto, in realtà inizierai a sovrascrivendo i precedenti valori dello stack.
-
Quando inizia la mia funzione, il valore massimo rimasto nella pila per me dalla funzione precedente è indirizzo di ritorno dove dovrei andare quando la mia funzione è terminata.
-
Questo significa che se la mia funzione supera il suo stack, la prima cosa che sta per sovrascrivere è l'indirizzo di ritorno. Se l'attaccante è attento a ciò con cui riempie la pila, può specificare qualsiasi indirizzo di ritorno che desidera.
-
Quando esiste la mia funzione, qualunque codice si trovi in quell'indirizzo di ritorno è ciò che verrà eseguito successivamente.
Esempio semplice
In Smashing the Stack for Fun and Profit , dove questa tecnica è stata originariamente descritta, la più semplice e diretta la tecnica è stata introdotta. Immagina che la funzione legga il tuo nome e poi ritorni. Quindi lo stack è simile a questo:
Stack Pointer Prev. Stack Ptr
+----------------------------------+--------------+................
| Your Name Here | Return Addr | Old stack ...
+----------------------------------+--------------+................
Ma il cattivo si fa il nome abbastanza a lungo da traboccare lo spazio. E non solo, invece di digitare un vero nome, digita un codice malvagio, un po 'di padding e l'indirizzo di quel codice malvagio.
+----------------------------------+--------------+................
| [ Evil Code ]xxxxxxxxxxxxxxxxxxxxxxEvil Address | Old stack ...
+----------------------------------+--------------+................
▲──────────────────────────────────┘
Ora invece di tornare al precedente chiamante, vai direttamente a [Evil Code]
. Ora stai eseguendo il suo codice invece del tuo programma. Da lì è praticamente game over.
Mitigazione e altre tecniche
Due delle tecniche utilizzate per ridurre l'efficacia dello smash stack sono DEP e ASLR.
DEP ("Data Execution Prevention") funziona contrassegnando lo stack non eseguibile. Ciò significa che [Evil Code]
sullo stack non verrà eseguito, poiché il codice in esecuzione nello stack non è più consentito. Per aggirare questo problema, l'attaccante trova frammenti di codice esistente che farà pezzi di ciò che vuole. E invece di sovrascrivere il proprio indirizzo di ritorno, crea una catena di indirizzi di ritorno attraverso lo stack per tutte le funzioni che desidera eseguire a turno. Chiamano questa "programmazione orientata al rendimento" o ROP. La catena di rendimenti è chiamata "catena ROP". Questo è davvero difficile da fare. Ma ci sono strumenti per aiutare.
ASLR ("Randomizzazione dello spazio degli indirizzi") funziona randomizzando le posizioni di tutte le funzioni interessanti. La creazione di una catena ROP non è così semplice: ogni volta che si esegue il programma, tutti gli indirizzi si trovano in luoghi diversi. Quindi, quando l'autore dell'attacco va a sovrascrivere l'indirizzo di ritorno con il proprio indirizzo malvagio, non saprà quali numeri usare perché il codice è sempre in posti diversi.
Né DEP né ASLR da solo offrono molta protezione, ma entrambi rendono lo sfruttamento molto difficile. Mentre alcune volte esistono alcune circostanze, non esiste una soluzione alternativa che funzioni ovunque . Se riesci a superare DEP + ASLR, è un successo unico.