it-swarm-eu.dev

Come spiegare l'overflow del buffer a un laico

Ogni tanto (quando penso ad alta voce e la gente mi ascolta) sono costretto a spiegare cos'è un buffer overflow. Poiché non riesco davvero a pensare a una buona metafora, finisco per spendere circa 10 minuti a spiegare come funzionano i programmi (vulnerabili) e l'allocazione della memoria, e quindi ho circa 2 frasi sull'exploit effettivo ("quindi un overflow del buffer riempie il buffer con sciocchezze e sovrascrive il puntatore per puntare a tutto ciò che voglio che indichi "). A questo punto, la maggior parte delle persone è diventata suicida ... Qual è un buon modo per spiegare un buffer overflow ai laici? Se possibile, si prega di includere un componente "overflow", ma anche almeno una spiegazione del perché ciò significa che l'attaccante può ottenere ciò che vuole. Ricorda, le persone di intelligenza media (e inferiore alla media) dovrebbero essere in grado di farsi un'idea di ciò di cui sto parlando, quindi mentre dovresti assolutamente sentirti libero (incoraggiato, in realtà) di spiegare cosa rappresenta ciascuna parte della tua metafora (analogia?) , non fare affidamento su descrizioni super tecniche ...

PS, una domanda correlata che spiega in termini tecnici cosa fa il buffer overflow: Che cos'è un buffer overflow?

52
KnightOfNi

Immagina di avere un elenco di persone a cui devi dei soldi.

Name | Amount owing

Inoltre, hai una bizzarra penna con fluido correttore incorporato, in modo che se scrivi qualcosa in un determinato posto e poi scrivi qualcos'altro, cancella la prima cosa che hai scritto. Ecco come funziona la memoria del computer, che è leggermente diversa da come funziona normalmente la scrittura.

Paghi a qualcuno un deposito di $ 500 su un'auto da $ 5000, quindi ora devi loro $ 4500. Ti dicono che si chiamano John Smith. Scrivi la quantità (4500) e il nome (John Smith) nella tabella. Il tuo tavolo ora è simile al seguente:

John Smith | 4500

Più tardi il tuo tavolo ti ricorda di ripagarli. Paghi $ 4500 (più interessi) e li cancelli dal tavolo, quindi ora il tuo tavolo è di nuovo vuoto.

Quindi ricevi un prestito di $ 1000 da qualcun altro. Ti dicono che il loro nome è "John Smithxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx999999999999". Scrivi l'importo (1000) e il nome (John Smithxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx9999999999) nella tabella. Il tuo tavolo ora è simile al seguente:

John Smithxxxxxxxxxxxxxxxxxxxxxxx|x99999999990

(l'ultimo 0 da 1000 non è stato sovrascritto. Questo non è importante.)

Durante la scrittura del nome, non ti sei fermato quando sei arrivato alla fine della colonna "nome" e hai continuato a scrivere nella colonna "importo dovuto"! Questo è un buffer overflow.

Successivamente, il tuo tavolo ti ricorda che devi $ 99999999990 a John Smithxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. Lo trovi di nuovo e gli paghi quasi 100 miliardi di dollari.

110
user253751

L'idea di utilizzare più spazio di quanto ti è stato dato, e quindi riversarsi in un altro campo è abbastanza semplice da visualizzare. Ma probabilmente non è chiaro come questo possa portare un cattivo a eseguire 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 dello stack. Quando una funzione viene eseguita, sposta il puntatore dello stack per darsi memoria con cui lavorare e, una volta terminato, sposta il puntatore nel punto in cui lo ha trovato.

  • La pila cresce all'indietro. Quindi, per darti 100 byte nello stack, tu sottrai 100 dal puntatore dello stack anziché aggiungerlo. Se lo stack della funzione precedente è iniziato a 1000 e voglio 100 byte, lo stack inizia a 900.

  • Ciò significa che se usi più spazio di quello che ti sei concesso, non continuerai semplicemente a scrivere nello spazio vuoto, in realtà inizierai sovrascrittura precedente valori dello stack.

  • All'avvio della mia funzione, il valore più alto lasciato in pila per me dalla funzione precedente è l'indirizzo di ritorno dove dovrei andare quando la mia funzione è terminata .

  • Ciò significa che se la mia funzione supera il suo stack, la prima cosa che sovrascriverà è l'indirizzo di ritorno. Se l'attaccante è attento a ciò che riempie lo stack, può specificare l'indirizzo di ritorno che desidera.

  • Quando esiste la mia funzione, qualunque codice si trovi a 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, è stata introdotta la tecnica più semplice e diretta. Immagina che la funzione legga il tuo nome e poi ritorni. Quindi il tuo stack è simile al seguente:

Stack Pointer                                      Prev. Stack Ptr
+----------------------------------+--------------+................
| Your Name Here                   | Return Addr  |  Old stack ...
+----------------------------------+--------------+................

Ma il cattivo rende il suo nome abbastanza lungo da traboccare lo spazio. E non solo, invece di digitare un vero nome, digita un codice malvagio, un po 'di imbottitura e l'indirizzo di quel codice malvagio.

+----------------------------------+--------------+................
| [ Evil Code ]xxxxxxxxxxxxxxxxxxxxxxEvil Address |  Old stack ...
+----------------------------------+--------------+................
  ▲──────────────────────────────────┘

Ora invece di tornare al chiamante precedente, si passa direttamente al [Evil Code]. Ora stai eseguendo il suo codice anziché il tuo programma. Da lì è praticamente finita la partita.

Mitigazione e altre tecniche

Due delle tecniche utilizzate per ridurre l'efficacia dello smashing dello stack sono DEP e ASLR.

DEP ("Data Execution Prevention") funziona contrassegnando lo stack come non eseguibile. Ciò significa che il [Evil Code] sullo stack non verrà eseguito, poiché l'esecuzione del codice sullo stack non è più consentita. Per ovviare a questo, l'aggressore trova pezzi di codice esistente che farà frammenti di ciò che vuole. E invece di sovrascrivere il proprio indirizzo di ritorno, crea una catena di indirizzi di ritorno nello stack per tutte le funzioni che desidera eseguire a turno. Lo chiamano "Programmazione orientata al ritorno" o ROP. La catena di rendimenti è chiamata "catena ROP". Questo è davvero difficile da fare. Ma ci sono strumenti per aiutare.

ASLR ("Randomizzazione del layout dello spazio degli indirizzi") funziona randomizzando le posizioni di tutte le funzioni interessanti. Ora creare una catena ROP non è così semplice: ogni volta che il programma viene eseguito, tutti gli indirizzi si trovano in luoghi diversi. Quindi quando l'attaccante va a sovrascrivere l'indirizzo di ritorno con il proprio indirizzo malvagio, non saprà quali numeri usare perché il codice si trova sempre in luoghi diversi.

Né DEP né ASLR da soli offrono molta protezione, ma entrambi insieme rendono lo sfruttamento riuscito molto molto difficile. Mentre a volte esistono alcune elusioni, non esiste una soluzione alternativa che funzioni ovunque . Se riesci ad aggirare DEP + ASLR, è un successo una tantum.

16
tylerl

Le altre risposte sono ancora piuttosto tecniche, quindi sto offrendo questo.

Immaginiamo di avere una scuola materna. Ci sono buchi in cui ogni studente può infilare le scarpe. Ogni buco in una gabbia contiene una scarpa. Quindi, per ogni studente, fornisci due buchi in gabbia.

A ogni studente vengono assegnati due fori adiacenti. L'insegnante chiama quindi gli studenti a caso per mettere le scarpe nei buchi a cui sono assegnati.

Quando l'insegnante chiama Bad Billy Bad Billy vuole scherzare con Stupid Sally . I buchi cubby di Billy sono numeri 5 e 6 e Sally sono numeri 7 e 8. Billy inserisce i suoi spettacoli in 5 e 6 quindi supera il limite definito e inserisce un rospo viscoso nel numero di cubby di Sally 7.

Poiché l'insegnante non impone alcuna protezione sul limite definito per l'utilizzo di buchi nell'ordine adiacente, Billy è in grado di traboccare il suo limite e confondere con Memoria di Sally . Ora quando Sally va a prendere la sua scarpa, otterrà un rospo viscido invece schifo!


+-------------------+--------------------+-------------------+--------------------+
|      CUBBY 5      |       CUBBY 6      |      CUBBY 7      |       CUBBY 8      |
+-------------------+--------------------+-------------------+--------------------+
|                   |                    |                   |                    |
| Billy's Left Shoe | Billy's Right Shoe | Sally's Left Shoe | Sally's Right Shoe |
+-------------------+--------------------+-------------------+--------------------+

Billy inserisci tre elementi in cui è definito, dovrebbe solo inserire 2, ecco come funziona un overflow dello stack ad alto livello, qualcuno sta facendo casino con l'archiviazione per i quali non sono autorizzati e quindi quando viene letto lo spazio di archiviazione non è quello che ti aspettavi.

+-------------------+--------------------+------------+--------------------+
|      CUBBY 5      |       CUBBY 6      |   CUBBY 7  |       CUBBY 8      |
+-------------------+--------------------+------------+--------------------+
|                   |                    |            |                    |
| Billy's Left Shoe | Billy's Right Shoe | Slimy Toad | Sally's Right Shoe |
+-------------------+--------------------+------------+--------------------+

Un overflow del buffer avrebbe potuto essere evitato se l'insegnante prestasse maggiore attenzione e assicurasse che ogni studente usasse solo la quantità di spazio di archiviazione previsto.

3
Eric G

Proverò questo senza usare alcuna analogia.

Un computer è fondamentalmente tutta la memoria, questa è la parte importante, i contenuti della memoria sono istruzioni, che dicono al computer cosa fare e dati, che le istruzioni fanno uso e possono usare o modificare. Spesso è necessario archiviare dati di lunghezza variabile. Ad esempio, se un programma deve tenere traccia dell'indirizzo e-mail di qualcuno che potrebbe essere molto breve ([email protected]) o molto lungo ([email protected]). Alcuni programmi non tengono molto bene traccia della lunghezza massima dei loro record di dati. Quindi se un programma fosse progettato con un massimo di, diciamo, 100 caratteri per un indirizzo e-mail e qualcuno gli avesse dato un indirizzo e-mail con più di 100 caratteri, il programma avrebbe continuato a scrivere il resto dell'indirizzo in memoria oltre la fine del suo pre spazio allocato. La parte importante da ricordare è che la memoria è tutto, il programma stesso è in memoria accanto ai record di dati.

Qualcuno che sapeva esattamente come funzionava questo programma poteva dargli un indirizzo e-mail elaborato con molta attenzione che era molto lungo e alla fine aveva caratteri speciali. L'idea è che quando il programma memorizzava l'indirizzo e-mail in memoria, scriveva ciecamente quei caratteri speciali in una parte della memoria in cui il programma pensava che fossero altre parti di se stesso, e quindi quando andava a eseguire quelle parti invece eseguiva qualunque cosa programmare quei caratteri speciali tradotti in, in codice informatico. In questo modo sarebbe possibile per qualcuno far eseguire al computer tutto ciò che desiderava, semplicemente elaborando con cura i dati forniti al programma.

3
Wedge

Lo spiego sempre come come far esplodere un secchio. Il bucket è lì per proteggere i contenuti dall'esterno e viceversa, ma stai usando i contenuti per arrivare all'esterno del bucket e quindi accedere alle aree del sistema a cui non dovresti altrimenti avere accesso.

1
David

Buona domanda. Ecco un'analogia che non è la più tecnicamente accurata, ma dovrebbe far passare l'idea.

Immagina un ricettario su carta perforata a 3 fori in un raccoglitore (memoria) e un cuoco molto stupido (il processore, cioè la CPU).

  • Le persone possono aggiungere o rimuovere pagine dal raccoglitore (caricare o scaricare programmi e dati in memoria)
  • Il cuoco segue semplicemente tutte le istruzioni sulla pagina in cui si trovano
  • Il cuoco inizia all'inizio (bootloader) e continua fino a quando l'istruzione è "libro chiuso"
    • Anche se l'istruzione è di passare a un'altra pagina (vai a pagina 394)

Quindi, normalmente, scriveresti a pagina uno "Vai a pagina 200 (waffle)", apri il raccoglitore e metti i waffle a pagina 200. Quindi fai partire il cuoco - il cuoco dovrebbe fare i waffle!

Ma aspetta ... c'è un attaccante! Hanno scritto delle note a margine della tua ricetta per waffle (fuori dal buffer) e il cuoco esegue queste istruzioni anche se sono ovviamente scritte a mano.

Al cuoco non è mai stato detto di fare solo ciò che è stampato sul foglio originale (nel normale spazio del buffer) - anche il cuoco farà qualsiasi cosa dopo (in memoria dopo il buffer).

Forse il cuoco aggiunge aceto ai waffle (corrompe i tuoi file). Forse il cuoco gira a pagina trecentonovantaquattro e lascia l'uovo crudo seduto lì, inutilizzato, fino a quando non marcisce e si modella (spegne il tuo antivirus). Forse il cuoco butta via tutto in cucina (elimina tutti i tuoi file) o mette un lucchetto sulla porta della cucina per tenerti fuori (ransomware) o apre la finestra (installa un trojan/backdoor) in modo che l'attaccante possa arrampicarsi nel finestra.

1

Com'è questo?

I dati in un computer sono memorizzati come un lungo elenco di numeri, come i brani di una cassetta musicale. A differenza della musica, che viene riprodotta dall'inizio alla fine, i computer devono saltare da una traccia all'altra, quindi hanno bisogno di un 'elenco di tracce' per dire loro dove inizia ciascuna.

Gli elenchi delle tracce sono facili per la musica, poiché ogni brano ha una lunghezza nota. Con un computer, la quantità di dati che dobbiamo archiviare potrebbe non essere ancora nota, ad esempio se proviene da Internet. Se la traccia che stiamo utilizzando si riempie, dobbiamo passare a una diversa, non utilizzata. Se non lo facciamo, ad esempio se assumiamo erroneamente che non ci verrà mai fornito più di una certa quantità di dati, potremmo usare troppo nastro e "nastro" sulla traccia successiva. Quando un programma tenta di leggere quella traccia successiva, recupererà parte dei nostri dati invece di qualsiasi cosa ci fosse prima.

Questo può essere pericoloso, perché i dati sovrascritti potrebbero essere stati un insieme di istruzioni da eseguire. In tal caso, il computer eseguirà ora le istruzioni scaricate direttamente da Internet!

0
Warbo