Buffer Overflow - Dipartimento di Informatica
Transcript
Buffer Overflow - Dipartimento di Informatica
Argomenti trattati Internet I servizi di rete Buffer Overflow: teoria, esempi Tecniche di protezione Aggirare StackGuard Buffer Overflow Attacchi ai servizi di rete Avella Gianluigi Cerqua Pasquale Crucil Sergio D’Alessandro Oreste Sicurezza su reti A.A. 2004/2005 Prof. Masucci Barbara In principio era….Arpanet ……e poi venne Internet Internet è una suite di servizi Tutti basati sul protocollo TCP/IP I più importanti attualmente http: web (es. Apache, Tomcat, IIS) ftp: trasferimento file (es. wu-ftp) smtp, pop, imap: posta elettronica (es. sendmail, postfix) Lo sviluppo di Internet Tecnologie di sicurezza Tecnologie di sicurezza utilizzate 300.000.000 250.000.000 Biometria Chiave pubblica Smart cards - e-token Crittografia dei files Prevenzione intrusioni Accounting utenti Crittografia dati trasmessi IDS ACL Firewall Antivirus 200.000.000 150.000.000 100.000.000 50.000.000 0 Dicembre 1994 Dicembre 1996 Dicembre 1998 Dicembre 2000 Dicembre 2002 0% 20% 40% 60% 80% 100% Danni economici Sicurezza Informatica Problemi dovuti alla “insicurezza” dei servizi informatici Perdite per tipo di attacco (2004) Acquisizione illecita di dati. Accesso indebito a un sistema per l’elaborazione di dati. Danneggiamento di dati, inclusa la fabbricazione e la messa in circolazione di virus informatici. Conseguimento fraudolento di una prestazione informatica. Attacchi a sistemi informatici di tipo “denial of service“. Danneggiamento grave delle reti di comunicazione: perturbamento di pubblici servizi Sabotaggio Violazione del sistema Sito w eb "defacciato" Abuso di applicazioni w eb Frode informatica Accesso non autorizzato Furto di componenti Frode finanziaria Abuso della rete w ireless Abuso della rete interna Furto di informazioni Denial of Service Virus $0 $10 $20 $30 $40 $50 $60 Milioni Milioni di dollari. Introduzione al Buffer overflow Errori nelle configurazioni Le principali cause della vulnerabilità del software Configurazioni errate Allocazione di tipi differenti di variabili Errata deallocazione della memoria Cicli infiniti Assenza di controllo sulle operazioni e sui puntatori Buffer overflow Conoscenze necessarie Linguaggio Assembler. Registri CPU. Funzionamento a basso livello di un sistema operativo. Funzionamento (in genere) dei linguaggi di programmazione. Conoscenza di un debugger. Nello specifico: Un sistema GNU/Linux Gnu Debugger Linguaggio C Architettura x86 Intel Teoria ed esempio di un attacco Il buffer overflow è un errore di programmazione dovuto all’errata gestione dei dati all’interno di un programma. In C un buffer viene normalmente associato ad un array. L’overflow di un buffer consiste nel riempire oltre il limite tale buffer. Un attacker è in grado di sfruttare questo errore per causare il crash di un servizio remoto o penetrare all'interno di un sistema. Tipi di attacchi dovuti a questo errore: Modifica del flusso di un programma. Iniezione ed esecuzione di codice arbitrario. Modifica di un puntatore a funzione. Modifica dei dati passati ad una funzione. Scenario “domestico” Scenari Attacco a client di servizi remoti. Internet Explorer è probabilmente il client più buggato che si ricordi. Server Attacco locale Web FTP SSH Un processo in memoria Ogni processo caricato in memoria, viene diviso in tre parti. Segmento testo Segmento dati Stack Lo stack è una struttura dati cruciale per il funzionamento di un processo. Funzionamento di tipo LIFO PUSH e POP ( Operazioni ) Indirizzi di memoria bassi Segmento testo Segmento dati Stack Funzionamento dello stack main(){ //codice foo(buffer); //codice } ESP call 0x80483a9 <foo> foo(char *buffer){ char a [ 5 ]; strcpy(a,buffer); } push mov sub sub Record di %ebp attivazione %esp,%ebp $0x18,%esp $0x8,%esp a[0] a[1] a[2] a[3] a[4] SFP RET Registri del processore EIP = Indirizzo dell’istruzione successiva Indirizzi di memoria alti EBP = Base pointer ESP = Top dello Stack BP Smashing the stack Funzionamento dello stack main(){ //codice foo(buffer); //codice } ESP a[0] a[1] a[2] a[3] a[4] SFP RET add $0x10,%esp leave ret foo(char *buffer){ char a [ 5 ]; strcpy(a,buffer); } EBP EIP Se il buffer passato alla funzione foo() è più di 5 caratteri…. Es: “bbbbbbbbbbbbbbb” a[0] a[1] a[2] foo(char *buffer){ a[ 5 ]; strcpy(a,buffer); } a[3] a[4] SFP RET Registri del processore EIP = Indirizzo dell’istruzione successiva EBP = Base pointer BP ESP = Top dello Stack I caratteri che eccedono il buffer hanno sovrascritto l’indirizzo di ritorno. EIP adesso punta ad una locazione di memoria non valida. Ghost in the shell Nop Nop No operation \x8b \x1f “Shellcode” Codice esempio (\bin/sh) 0x0809ff34 Codice arbitrario Fault Un esempio A questo punto il programma è andato in crash! Ma un attacker potrebbe “confezionare” un array da passare alla funzione foo() in modo tale che venga dirottata l’esecuzione del programma stesso. Ma nella maggior parte dei casi questo bug viene sfruttato per costringere il programma ad eseguire codice arbitrario! \xeb Segmentation Puntatore Inizio del buffer Codice exploit #include <stdio.h> #include <stdio.h> main(int argc, char **argv){ main() { char buffer[10]; int i; char buffer[33]; if(argc!=2){ printf("Usage:./esempio qualcosa\n"); exit(0); } strcpy(buffer,argv[1]); } foo(){ printf("Corso di sicurezza su reti\n"); exit(0); } for(i=0;i<28;i++) buffer[i]=0x61; *(long *)&buffer[28] =0x0804843d; execl("./esempio","esempio",buffer,NULL); } Analisi del problema - 1 Analisi del problema - 2 Modifica del flusso di un programma. Firewall ed antivirus sono impotenti! “Iniezione” di codice arbitrario. Danni economici elevati. Un attacker può prendere pieno possesso della macchina “vittima”. Metà degli advisory del Cert, sono su problemi legati al Buffer Overflow. Difesa dal Buffer Overflow Come difendersi Programmi modulari e facili da debuggare. Testing. Stack non eseguibile. Controllo della dimensione degli array. Utilizzo di linguaggi “tipizzati”. Controllo dell’integrità sui puntatori. Utilizzo di tool specifici. Pregare…. Tool di difesa StackGuard, StackShield, FlawFinder automatizzano alcuni dei suddetti metodi di prevenzione. Sono programmi open source. Disponibili unicamente per il mondo Unix. StackGuard e StackShield non richiedono aggiunte al codice esistente, ma non tutti i programmi possono essere ricompilati. StackGuard StackGuard è una “patch” per gcc. La prima versione prevedeva la protezione da scrittura della word RET. (Memguard) Interviene nel prologo e nell’epilogo di ogni funzione. Canary Utilizza una “canary” word nel record di attivazione. Un tentativo di sovrascrivere il RET provocherebbe “il canto” del canarino. Metodi difensivi di StackGuard L’attacker potrebbe leggere la word canary Quindi tre metodi di difesa Terminator ¾ La word è scelta come combinazione di caratteri nulli, ritorno a capo e fine linea. Random ¾ ¾ ¾ Canary La word è scelta in modo random a run-time. Esiste una variante chiamata XOR random canary. Null ¾ Canary Canary La word e una serie di caratteri nulli Es. 0x00000000 SFP RET StackShield StackShield è un software simile a StackGuard. Protegge il valore RET da attacchi ti tipo Buffer Overflow. Aggiunge codice assembly al prologo ed all’epilogo di ogni funzione. Utilizza tre metodi di funzionamento ¾Global Ret Stack ¾Ret range check. ¾Modalità speciale ( attacchi contro puntatori a funzione ). Non richiede al programmatore di aggiungere codice. Global Ret Stack Funzionamento del Global Ret Stack La prima tecnica di protezione prevede l’utilizzo di un array di 256 elementi (Retarray) da trattare come uno stack dove verranno salvati gli indirizzi di ritorno. Si utilizzano due puntatori speciali Retptr ( puntatore alla prima locazione libera di Retarray). Rettop ( puntatore all’ultimo elemento dell’array.) Nel prologo di ogni funzione, Retptr viene confrontato con Rettop. ¾ Se Retptr è <= di Rettop, l’indirizzo viene memorizzato nell’array e Retptr viene incrementato. ¾ Altrimenti l’indirizzo di ritorno non viene salvato ma Retptr viene incrementato comunque per “sincronizzazione”. Nell’epilogo avviene nuovamente il controllo e se Retptr è <= di Rettop l’indirizzo salvato viene ripristinato e Retptr decrementato. 0x00 0x01 …………………………… Retarray Retptr Global Ret Stack Esempio di funzionamento main(){ foo(); //codice ……….. foo(){ Retarray foo2(); //codice } foo2(){ 0x02 //codice } Retptr In questo modo anche se un buffer overflow sovrascrive il RET, questo viene ripristinato all’epilogo. La dimensione di Retarray può essere aumentata. L’attacco viene inibito ma non segnalato. Esiste una modalità alternativa in cui il RET viene confrontato con il suo “clone” nel Retarray. Rettop //codice } 0x01 Rettop Modalità Speciale Ret Range check Gli attacchi basati sul buffer overflow, tentano di dirottare A N G E il flusso del programma verso il buffer contenete lo shellcode V Segmento testo A L I e quindi verso lo stack. D O Il Ret range check rende lo Segmento dati stack non eseguibile. Stack Flaw Finder Un puntatore a funzione viene allocato in una zona di memoria in modo casuale. ( stack, heap, segmento dati). Se viene allocato nello stack, l’attacker cerca di corrompere il puntatore tramite l’overflow di un buffer. StackShield inizializza un variabile casuale e controlla che non si trovi al di fuori del segmento dati, poiché anche il puntatore verrà allocato nei pressi della variabile. R E’ un tool di sviluppo a supporto dei programmatori. È capace di analizzare codice sorgente C/C++. È un semplice parser. Produce in output solo una lista con un grado di potenziale pericolosità delle funzioni. Il database del programma (ruleset) contiene informazioni su operazioni comuni che possono manifestare problemi concernenti la sicurezza. La Ruleset è aggiornabile. Ogni elemento è costituito dalla tupla (Hook, Level, Warning, Suggestion, Category, URL, Other). Per ogni match si propone al programmatore una soluzione. Flaw Finder Analisi dei metodi di difesa Attacchi a StackGuard Stackguard e StackShield aggiungono codice e soprattutto “controlli” ai programmi aumentando sensibilmente l’overhead. Ma attenzione….non sono infallibili! Falle di StackGuard Inefficienze Vantaggio offerto da StackGuard: ¾ ¾ Falle di StackGuard Protezione dell’indirizzo di ritorno (RET) … Un overflow su un buffer situato prima di una o più variabili locali permette di sovrascrivere anche queste ultime. Se vi è la possibilità di manipolare un puntatore si possono alterare importanti sezioni di memoria (fnlist, GOT, frame pointer). Non basta. Infatti: ¾ ¾ ¾ L’overflow viene scoperto al termine della funzione Non protegge nessun altro indirizzo (saved frame pointer…) canary può essere aggirato Attacchi a StackGuard - 1 Attacco Emsi: sostituzioni nella fnlist fnlist contiene gli indirizzi delle funzioni registrate attraverso atexit() (gdb) b main Breakpoint 1 at 0x8048790 (gdb) r Starting program: /root/StackGuard/c/StackGuard/vul Breakpoint 1, 0x8048790 in main () (gdb) x/10x &fnlist 0x400eed78 <fnlist>: 0x00000000 0x00000002 0x00000003 0x4000b8c0 0x400eed88 <fnlist+16>: 0x00000000 0x00000003 0x08048c20 0x00000000 0x400eed98 <fnlist+32>: 0x00000000 0x00000000 Attacchi a StackGuard - 2 Sostituzioni nella Global Offset Table (GOT) Simile al precendente attacco: l’obiettivo è alterare l’ordine dell’invocazione delle funzioni. GOT contiene la corrispondenza indirizzo – funzione. Avendo la possibilità di manipolare un puntatore è possibile cambiare l’indirizzo associato a una funzione utilizzata. Attacchi a StackGuard - 1 È possibile con un debugger scoprirne l’indirizzo e, avendo un puntatore a disposizione nel programma, alterare la registrazione delle funzioni da eseguire all’invocazione di exit(). Nemmeno StackShield è immune a questo attacco Attacchi a StackGuard - 2 oredal@Homer:~/src/sg/tests$ cc -o sg1 sg1.c oredal@Homer:~/src/sg/tests$ readelf –S sg1|grep got [ 8] .rel.got REL 08048358 etc... [20] .got PROGBITS 08049888 etc... Come risultato una printf() invocare invece una system(). potrebbe L’attacco riesce anche se SG è utilizzato in combinazione con StackPatch (rende lo stack non eseguibile). That’s all folk! Attacchi a StackGuard - 3 Buffer Overflow: attacco ai servizi di rete Alterazione del frame pointer La combinazione d’uso di SG con un terminator canary (valore fisso 0x000aff0d) permette di arrivare alla sovrascrittura del frame pointer (e di non sovrascrivere il canary) attraverso le comuni funzioni di manipolazione delle stringhe. In questo modo è possibile ottenere il controllo completo delle variabili locali e degli argomenti delle funzioni. Il frame pointer non è utilizzato nei programmi compilati con l’opzione –fomit-frame-pointer Progetto realizzato da: Avella Gianluigi Cerqua Pasquale Crucil Sergio D’Alessandro Oreste