Buffer Overflow e segmenti

2

So che sovrascrivendo l'indirizzo di ritorno nel programma vulnerabile possiamo cambiare l'offset dell'istruzione successiva e farlo puntare al nostro buffer iniettato. ma questo buffer è nel segmento di stack e l'offset (ip) è calcolato per "segmento di codice", quindi come è possibile che il programma esegua il codice nel segmento di dati? (Supponiamo vicino alla chiamata.)

    
posta user2808671 15.03.2015 - 17:30
fonte

1 risposta

2

Nella maggior parte (se non tutti) i moderni sistemi operativi eseguiti su hardware x86, i segmenti vengono ignorati. I registri di segmento sono impostati per iniziare all'indirizzo 0 e per estendere per l'intero spazio di indirizzamento a 32 bit; pertanto, gli offset calcolati relativamente a un segmento sono validi per tutti i segmenti, poiché iniziano tutti nello stesso punto e si sovrappongono esattamente l'un l'altro. In pratica, il codice dell'applicazione non interferisce con i registri di segmenti; presume solo che siano già impostati come descritto sopra e si dimentica di loro.

Di conseguenza, in un sistema operativo moderno non ci sono "chiamate lontane". Tutte le chiamate, tutti gli accessi ai dati sono "vicini". La nozione di "OS moderno" include qui tutte le versioni di Windows da Windows 95 (e anche il vecchio Windows 3.1 quando sono installate le estensioni "win32s") e tutte le versioni di Linux dal primo giorno.

Alcuni dettagli più fini:

  • Quando la macchina è in grado di 64 bit e il kernel del sistema operativo viene eseguito in modalità a 64 bit, può ancora eseguire codice in modalità a 32 bit, ma questa è solo una "emulazione". In quella modalità emulata, i segmenti sono realmente fissati all'indirizzo 0 e non possono essere modificati dal kernel. Ciò significa che anche la posizione "dimentichiamo i registri dei segmenti" si è consolidata saldamente nell'hardware.

  • Alcuni sistemi operativi rendono lo stack (e altri dati) "non eseguibili" in modo da rendere la vita più difficile per l'attaccante; questo è chiamato Prevenzione dell'esecuzione dei dati . Un possibile trucco per questo è, in effetti, l'uso di registri di segmenti: ad esempio, il segmento CS coprirà gli indirizzi da 0 a 1073741823 e il sistema operativo organizzerà la collocazione di elementi non eseguibili (in particolare lo stack) con un offset superiore a 1073741824. In tal caso, qualsiasi tentativo di saltando nel codice che è nella pila, la CPU cercherà di leggere gli opcode (quindi relativamente a CS ) oltre il limite di quel segmento, che quindi farà scattare un'eccezione. Tuttavia, gli accessi ai dati saranno effettuati con DS o SS , il cui limite superiore è mantenuto a 4294967295, e sarà quindi senza impedimenti.

    Come meccanismo DEP, i registri dei segmenti non sono molto flessibili, poiché richiedono una netta separazione tra le aree che possono essere eseguite e le aree che non possono. I compilatori JIT , in particolare, non sono molto contenti di questo, dal momento che devono allocare RAM, scrivere codice in esso, quindi rendere l'area eseguibile, che non può essere eseguita se non è stata allocata nello "spazio eseguibile" (l'area coperta da CS ) in primo luogo. Inoltre, come detto sopra, i trucchi basati su segmenti non funzionano quando il kernel è in modalità 64 bit. Questo è il motivo per cui il SO moderno, quando si fa il DEP, preferisce farlo attraverso la MMU , che consente di consentire o impedire l'esecuzione su una base per pagina e per modificare dinamicamente i diritti di esecuzione per ciascuna pagina.

    (Inoltre, DEP è solo un tentativo di ostacolare l'autore dell'attacco, ma esistono soluzioni alternative . Per motivi di sicurezza, è molto meglio non permettere ai buffer di essere sorvolati, piuttosto che provare a recuperare più o meno da un buffer overfunk.)

  • Il registro GS è speciale; il suo indirizzo di base è non l'indirizzo 0, e funziona ancora quando il kernel è in modalità 64-bit. È utilizzato per l'efficiente archiviazione locale dei thread .

risposta data 15.03.2015 - 19:30
fonte

Leggi altre domande sui tag