In che modo i compilatori rilevano l'overflow del buffer?

7

Ho appena iniziato le ricerche sulla sicurezza a livello di sistemi e le sfide, in particolare rispetto ai linguaggi di basso livello come C / C ++ e Objective-C. Ho capito overflow del buffer e come funziona. Stavo giocando con OS X e Ubuntu. Naturalmente questi sistemi hanno implementato ASLR e stack guard, che possiamo disabilitare in fase di compilazione. Quindi ho un paio di domande riguardo a questo:

  1. Come fa un compilatore a rilevare un overflow in fase di compilazione? Capisco che durante la compilazione aggiungerà un canarino e se qualche istruzione tenta di sovrascriverlo, genererà un errore. Ma qual è l'algoritmo esatto? Se qualcuno può puntare le funzioni del codice gcc per questo, sarebbe fantastico.

  2. Sta disabilitando lo stack guard e rendendo eseguibile stack / heap su Ubuntu sufficiente? Oppure ASLR può ancora renderlo difficile da sfruttare?

  3. Se ho un binario (nessun codice sorgente) e so che si blocca a causa dell'overflow del buffer, come lo rilevo?

posta user775093 03.04.2015 - 05:37
fonte

2 risposte

6

I buffer overflow non vengono rilevati al momento della compilazione. Ci sono strumenti di analisi del codice, come href="http://kernelnewbies.org/Sparse"> Sparse o Lint ( cpplint , pc-lint ) che eseguirà ulteriori analisi su entrambi i file di codice sorgente o binari compilati. Ogni strumento di analisi ha i propri algoritmi per determinare un overflow del buffer, ma si tratta di istruzioni note comuni che portano a buffer overflow.

È inoltre possibile aggiungere il controllo dei limiti al momento della compilazione che inserisce le informazioni sui limiti per ciascun blocco di memoria allocato. Queste informazioni sui limiti vengono quindi verificate in fase di esecuzione per garantire che i buffer rientrino nei loro limiti. Un'implementazione comune è usare i puntatori "grassi". Che contengono sia l'indirizzo del puntatore reale ai dati, sia ulteriori dati che descrivono la regione in cui si trova. Credo che Firefox lo faccia per le loro allocazioni di memoria, ma potrei sbagliarmi.

Le canarie vengono inserite in fase di compilazione per aiutare a rilevare i buffer overflow inserendo una word di dati tra un buffer e i dati di controllo nello stack. Ad un certo punto, prima del ritorno della funzione, il canarino viene verificato come intatto.

ASLR non ha nulla a che fare con la protezione dello stack. Rende casuale l'indirizzo che il tuo programma esegue in memoria. Ciò significa che non è possibile fare affidamento sulle funzioni per essere allo stesso indirizzo ogni volta che si esegue il programma. Ciò impedisce l'hardcoding degli indirizzi di librerie e funzioni. Rendere necessario lo stack o l'heap (o qualsiasi pezzo di memoria che si sta tentando di eseguire) eseguibile, ma ASLR causerà comunque problemi. Se stai solo sperimentando e cercando di capire il codice di exploit, farei quanto segue:

  1. Disabilita ASLR
  2. Disabilita le protezioni dello stack
  3. Attacca ogni problema individualmente e riattivalo uno alla volta finché l'exploit non sarà in grado di gestirlo entrambi.

Se hai un file binario che va in crash a causa di ... beh, qualsiasi cosa (non solo un buffer overflow) esegue il programma in un debugger. Il debugger prenderà l'arresto nel punto esatto in cui il programma fallisce. Probabilmente dovresti capire che questa potrebbe non essere la posizione esatta dell'overflow, ma una traccia dello stack dovrebbe aiutare a determinare la causa principale. Suggerirei di leggere questi post se non hai familiarità con gli strumenti di reverse engineering o con l'architettura del computer x86.

Perché i buffer di overflow eseguito nella direzione sono
Strumenti di progettazione inversa

    
risposta data 03.04.2015 - 13:50
fonte
1

Considera il seguente codice

void f1()
{
     char buf[20];
     strcpy(buf,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); // The buffer overrun
} 

void f2() 
{
    ....
    f1(); 
    (address of this place will be pushed onto to the stack 
     as the return address before calling f1)
    ...
}

Quando f2 chiama f1 , per impostazione predefinita, l'indirizzo di ritorno (cioè l'indirizzo a cui la chiamata deve tornare dopo che f1 ha terminato l'esecuzione) viene inserito nello stack.

Tipicamente quando buffer buf è sovraccarico in f1 , viene sfruttato sovrascrivendo l'indirizzo di ritorno nello stack, in modo che quando dopo che f1 è finito il codice ritorni in qualche posto dove l'attaccante ha controllato i dati che possono eseguire un script o qualcosa che fa l'exploit.

Microsoft Compilers implementa una protezione nel modo seguente.
Quando la funzione viene caricata, inserisce un cookie di sicurezza (un valore casuale) tra la fine del buffer e la posizione nello stack in cui è memorizzato l'indirizzo di ritorno. Il compilatore aggiunge anche del codice alla fine della funzione f1 per verificare se il cookie di sicurezza è uguale a quello che è stato inserito.
Quindi diciamo che c'è stato un sovraccarico del buffer e che è stato utilizzato il sovraccarico del buffer per modificare tutte le cose dopo la fine del buffer, incluso l'indirizzo di ritorno. Ciò significa che anche il cookie di sicurezza è stato sovrascritto. Quando la funzione f1 termina l'esecuzione, il codice aggiunto alla fine della funzione lo rileverà e spegnerà il programma, il che significa che l'exploit (esecuzione del codice che l'utente malintenzionato voleva accadere) non verrà eseguito.

Ecco una spiegazione più dettagliata

    
risposta data 03.04.2015 - 07:10
fonte

Leggi altre domande sui tag