Quando l'allocazione di memoria / layout è deterministica?

7

Sto cercando di conoscere gli attacchi di overflow del buffer, sia sullo stack che sull'heap. Tuttavia, sono confuso su quando è possibile determinare l'indirizzo del buffer.

Il classico "Smashing the Stack for Fun and Profit" menziona la necessità di utilizzare un% sdrucciolevole NOP in un attacco di overflow del buffer basato sullo stack per saltare in modo affidabile nello shellcode inserito il buffer Questo sembra essere dovuto al fatto che il buffer finisce in una diversa posizione di memoria in ogni esecuzione del programma. Tuttavia, non è completamente casuale, dal momento che è possibile indovinare l'indirizzo del buffer aumentando le probabilità utilizzando una NOP slitta.

Al contrario, le variabili di ambiente passate al programma vengono inserite ogni volta negli stessi indirizzi, consentendo un attacco locale molto più semplice in cui l'utente malintenzionato colloca lo shellcode in una variabile di ambiente, quindi può passare direttamente alla posizione di tale variabile d'ambiente.

Sono ancora all'oscuro su come questo viene eseguito per i buffer basati su heap (ad esempio quelli assegnati da malloc ) e in altre situazioni. Pertanto:

  1. In quali circostanze è deterministico il layout della memoria?
  2. Quanto è prevedibile anche quando non è del tutto deterministico? Infine, come influiscono le mitigazioni di exploit come ASLR e PIE?
posta ikdc 04.02.2015 - 03:11
fonte

2 risposte

3

Una parte del problema ha a che fare con il layout della memoria durante l'inizializzazione del programma e l'aspetto del layout della memoria dopo che è stato eseguito per un po 'e si riesce a far traboccare il buffer. Devi anche fare i conti con il problema "funziona sulla mia macchina".

Quindi, durante l'inizializzazione, tutte le variabili di ambiente verranno caricate nello stesso posto, poiché si tratta di un processo ragionevole e tempestivo. Quando si tratta di sovraccaricare il buffer non è sempre possibile garantire che si sta attivando allo stesso tempo ogni volta. ad esempio se l'applicazione riceve pacchetti di rete, sarebbe molto difficile per te inviare sempre gli stessi pacchetti sempre. Quindi, di conseguenza, quando si arriva a innescare l'overflow, il layout della memoria potrebbe non essere esattamente lo stesso. Da qui la necessità per la NOP di slittare come da qualche parte per 'atterrare'.

Il problema "funziona sulla mia macchina" è che, in realtà, vuoi che il tuo exploit funzioni su altre macchine di persone, ed è improbabile che sia configurato esattamente come il tuo. Potrebbero esserci diverse versioni di librerie, diverse configurazioni hardware, il che significa che l'indirizzo di overflow di destinazione non sarà lo stesso del tuo.

Questi problemi possono rendere difficile garantire che il layout della memoria sia sempre lo stesso, quindi si lavora su una serie di valori probabili e quindi sulla necessità di una slitta NOP.

    
risposta data 20.01.2017 - 11:35
fonte
0

Determinism From Within Programs

Sebbene tutte le operazioni deterministiche sui dati noti producano risultati deterministici, il layout della memoria non è pensato per essere deterministico per chiunque non sia uno sviluppatore del kernel. Sebbene il layout sia deterministico in senso matematico 1 , la natura mutevole e diversificata dell'industria del software rende la vista di un'applicazione delle strutture di sistema effettivamente stocastica.

Funzioni di sicurezza portatili

Nessun codice portatile o affidabile può basarsi su supposizioni sulla memoria al di fuori dei modelli di programmazione standardizzati forniti. Le intestazioni di stack, allocazioni dinamiche o di memoria statica possono cambiare e il compilatore può cambiare in sincrono in modo che un programma conforme agli standard possa funzionare senza intoppi, ma uno che sfrutta la conoscenza speciale del sistema operativo può spezzare e creare più rischi di sicurezza di quanto pretende di eliminare .

Un programma non può dipendere dalla coerenza delle strutture del kernel nel tempo. Le architetture della CPU, i loro set di istruzioni, i modelli di esecuzione, la gestione dello stack e la meccanica di malloc e free sotto il cofano possono cambiare in qualsiasi momento. Questa è la ragione per POSIX e altri standard. Solo le facciate fornite attraverso chiamate di sistemi standardizzati possono essere (di solito) attendibili per esibire un comportamento prevedibile.

Evitare gli exploit variabili d'ambiente

Si può, se si desidera, iterare attraverso le variabili di ambiente, copiare i valori necessari e quindi scrivere zeri sull'intervallo esatto occupato da ciascuno. Ma questa non è la migliore strategia.

Utilità generica di sistema e sorgente

Il frutto basso che è stato utilizzato da molti team di sicurezza è quello di bloccare l'esecuzione di tutti i software eseguibili da tutti gli utenti ad eccezione di quelle combinazioni di software utente che hanno senso. Quelli consentiti vengono analizzati per potenziali buchi di sicurezza e vengono applicate patch appropriate per ridurli al minimo.

La protezione specifica per l'exploit contro l'overflow e l'underflow del buffer è un'attenta convalida dell'indice del buffer in linguaggi come C o l'uso appropriato di oggetti che sono progettati per impedire queste manipolazioni del modello di memoria sfruttabile.

Metodi di iniezione di entropia

La randomizzazione del layout dello spazio degli indirizzi (ASLR) è una caratteristica del sistema operativo che fornisce una resistenza aggiuntiva all'attacco. Non aggiungi ASLR al tuo programma. Ogni sistema operativo che fornisce il modello ha un meccanismo in cui è possibile eseguire programmi specifici senza fornire un granché di un suggerimento attraverso l'ispezione del processo da cui i byte di istruzioni eseguibili vengono caricati nella CPU.

Eseguibile indipendente dalla posizione (PIE) è un meccanismo che supporta la randomizzazione assicurando che tutti gli indirizzi nell'eseguibile siano relativi o si comportino (in gruppi di istruzioni) come se fossero.

Dovrai esaminare in che modo l'aggiunta di entropia al posizionamento del modello di memoria può essere applicata al tuo particolare sistema operativo di destinazione. Potrebbero esserci dei vincoli associati sul codice, sulla compilazione o sui flag di collegamento da utilizzare e sull'esecuzione del contenitore che esegue la randomizzazione necessaria. Ci possono essere velocità e impatto sulle risorse, quindi potresti voler identificare i tuoi livelli di rischio eseguibili ed essere selettivo.

Come funzionano? Introdurre l'entropia nella determinazione della posizione di memoria rende difficile per gli attaccanti indovinare dove risiedono le istruzioni della CPU in memoria in modo che la sorgente di salto e la destinazione desiderata siano più difficili da determinare in tempo reale da un'altra porzione temporale in uno scenario multitasking.

Strategie di stratificazione per la forza di sicurezza cumulativa

Ricorda che queste sono guardie e non garanzie di sicurezza. Poche strategie economicamente efficaci sono efficaci quanto la combinazione tradizionale di amministrazione di sistemi di livello mondiale, l'attento accesso alla memoria all'interno dei programmi e un'eccellente igiene dei dati in arrivo. Aggiunte più recenti a questo elenco sono l'aggiunta di livelli a queste strategie efficaci per aumentare la resilienza del sistema agli attacchi.

[1] Il layout della memoria è deterministico a meno che l'OS non entri nel reale dal movimento del mouse, dall'ingresso audio o da qualche altro trasduttore e poi impieghi per posizionare la memoria in modo casuale (al contrario di pseudo-casuale).

    
risposta data 20.01.2017 - 06:14
fonte