buffer-overrun - Dipartimento di Matematica e Informatica
by user
Comments
Transcript
buffer-overrun - Dipartimento di Matematica e Informatica
UNIVERSITÀ DI PERUGIA DIPARTIMENTO DI MATEMATICA E INFORMATICA Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Buffer overflow attack and defense Prof. Stefano Bistarelli Università “G. d’Annunzio” Dipartimento di Scienze, Pescara C Consiglio Nazionale delle Ricerche Iit Istituto di Informatica e Telematica - Pisa Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Errori del codice Un errore del codice può influire sulla sicurezza del software (in alcuni casi con conseguenze catastrofiche). Ad esempio nel giugno 1996 il satellite europeo Ariane 5 è esploso subito dopo il lancio a causa di un errore nel software; il programma tentò di inserire un numero di 64 bit in uno spazio di 16 bit, provocando un overflow. S. Bistarelli - Metodologie di Secure Programming 2 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione S. Bistarelli - Metodologie di Secure Programming 3 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Buffer overflow Il problema dei buffer overflow è sicuramente quello più comune tra tutti i tipi di insicurezza nel codice C, mentre è praticamente assente in linguaggi di più alto livello che non lasciano al programmatore la gestione della memoria. I problemi di buffer overflow sono stati la principale causa dei problemi di sicurezza riscontrati negli utlimi 10 anni. La tecnica del buffer overflow consiste nel forzare la scrittura in memoria con una quantità di informazioni superiore a quella accettabile. Se il software è privo di controlli è possibile inserire del codice eseguibile (bytecode) in queste stringhe di overflow che consentono ad esempio di eseguire comandi su shell (shellcode). Inoltre se il software viene eseguito in modalità root un attacco di questo tipo può garantire il pieno possesso di tutte le funzionalità del sistema. I buffer overflow possono essere eseguiti sulle seguenti zone di memoria: stack, heap e bss (block started by symbol). S. Bistarelli - Metodologie di Secure Programming 4 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Organizzazione della memoria di un processo Per capire la tecnica del buffer overflow è necessario studiare l'organizzazione della memoria di un processo (programma). I processi sono divisi, in memoria, in tre regioni: testo, dati e stack. La regione testo è fissata, contiene il codice del programma ed è a sola lettura. Qualsiasi tentativo di scrittura provoca una violazione di segmento. La regione dati contiene i dati inizializzati e non (variabili statiche e globali) relativi al processo mentre la regione stack contiene i dati dinamici (utilizzati nella chiamata di funzioni). 0x00000000 Segmento testo Indirizzi di memoria bassi Segmento dati 0xFFFFFFFF Stack Indirizzi di memoria alti S. Bistarelli - Metodologie di Secure Programming 5 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Organizzazione della memoria di un processo Indirizzi di memoria bassi codice Segmento testo costanti Dati variabili globali e statiche BSS variabili allocate dinamicamente Heap variabili locali, chiamate di funzioni Stack S. Bistarelli - Metodologie di Secure Programming Indirizzi di memoria alti 6 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione … a volte considereremo il disegno opposto … S. Bistarelli - Metodologie di Secure Programming 7 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Lo Stack Lo stack (pila) è una struttura dati di tipo LIFO (Last In First Out) che consente di memorizzare un numero variabile di informazioni. Questa struttura dati viene utilizzata all'interno dell'architettura degli elaboratori per gestire le chiamate di funzioni (call in assembly). La zona di memoria destinata alla gestione dello stack viene suddivisa logicamente in aree (stack frame) per ogni chiamata di funzione. x=pop push(x) Stack 1) x=a, 2) x=b, 3) x=c 1) x=c, 2) x=b, 3) x=a c b a S. Bistarelli - Metodologie di Secure Programming 8 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Lo Stack e i registri di sistema Ogni processo viene eseguito step-by-step tramite l'elaborazione di istruzioni successive. L'indirizzo di memoria dell'istruzione da eseguire, in un preciso istante, è contenuto nel registro di sistema EIP (Extended Instruction Pointer) a 32 bit (1dword). S. Bistarelli - Metodologie di Secure Programming 9 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Lo Stack e i registri di sistema Oltre a questo registro di sistema esistono altri registri utili per la gestione di chiamate di funzioni (call). Il registro EBP (Extended Base Pointer) che punta alla base di uno stack frame ed il registro ESP (Extended Stack Pointer) che punta alla cima dello stack frame. S. Bistarelli - Metodologie di Secure Programming 10 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Lo Stack e i registri di sistema Quando viene richiamata una funzione (call) il sistema inserisce nello stack l'indirizzo dell'istruzione successiva, push(EIP+4) dove 4 indica 4 byte (4byte=1dword), successivamente inserisce nello stack il puntatore alla base dello stack frame corrente, push (EBP) ed infine copia l'ESP attuale sull'EBP inizializzando così il nuovo stack frame. S. Bistarelli - Metodologie di Secure Programming 11 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione EIP, EBP, ESP EIP va in stack EBP va in stack (chiamato SFP) EBP’ = ESP Settato nuovo ESP’ (lunghezza della procedura chiamata) S. Bistarelli - Metodologie di Secure Programming 12 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Un esempio in C Analizziamo quest'esempio di codice in C per capire meglio l'allocazione dello stack frame: void test_function (int a, int b) { char flag; char buffer[10]; } buffer flag SFP* EBP' nuovo EBP Indirizzo di ritorno (ret) EIP int main() { test_function (1,2); exit(0); } memoria bassa Stato dello stack frame a b Indirizzo di ritorno (ret) = EIP + 4 byte memoria alta *SFP= Saved Frame Pointer, valore utilizzato per rispristinare lo stato originale di EBP (prima della chiamata di test_function();) S. Bistarelli - Metodologie di Secure Programming 13 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Lo stack frame Alle variabili locali della funzione test_function si fa riferimento mediante sottrazione del valore del frame pointer EBP e gli argomenti della funzione mediante addizione a tale valore. Quando una funzione viene richiamata, il puntatore EIP diventa l'indirizzo di inizio del codice della funzione. memoria bassa buffer flag SFP* EBP Indirizzo di ritorno (ret) La memoria dello stack è utilizzata per le variabili locali e gli argomenti della funzione. Dopo il termine dell'esecuzione della funzione, l'intero stack frame viene estratto dallo stack in modo da riprendere l'esecuzione sull'istruzione di ritorno (ret). S. Bistarelli - Metodologie di Secure Programming a b memoria alta 14 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Esempio di overflow Analizziamo quest'esempio di codice in C che provoca un overflow: void overflow_function (char *str) { char buffer[20]; strcpy(buffer, str); // Funzione che copia str nel buffer } Questa istruzione provoca un overflow! int main() { char big_string[128]; int i; for(i=0; i < 128; i++) { big_string[i] = 'A'; } overflow_function(big_string); exit(0); } S. Bistarelli - Metodologie di Secure Programming 15 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Segmentation fault Perchè il codice precedente provoca un Segmentation fault? 1) La prima chiamata di overflow_function inizializza correttamente lo stack frame: 2) Al momento del termine dell'esecuzione della funzione overflow_function, l'istruzione di ritorno è stata sovrascritta con il carattere A (segmentation fault!) memoria bassa memoria bassa buffer A A ... A } SFP A Indirizzo di ritorno (ret) A *str (argomento) A } memoria alta S. Bistarelli - Metodologie di Secure Programming A 20 byte 108 byte 16 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Buffer overflow (basati sullo stack) Cosa succede se l'istruzione di ritorno (ret) contiene un indirizzo di memoria valido? ● ● ● In questo caso il processo continuerebbe indisturbato eseguendo l'istruzione successiva contenuta in ret. Il buffer overflow basato sullo stack consiste proprio nello sfruttare tale possibilità sostituendo l'istruzione di ritorno ret con un nuovo puntatore ad una porzione di codice inserita manualmente da un intruso. Come è possibile 1. modificare tale istruzione di ritorno ed 2. inserire arbitrariamente del codice in un processo? S. Bistarelli - Metodologie di Secure Programming 17 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Cos'è un Buffer Overrun Si verifica quando i dati superano la dimensione prevista e sovrascrivono altri valori È frequente soprattutto nel codice C/C++ non gestito Può essere di quattro tipi: buffer overrun basato sullo stack buffer overrun dell'heap Sovrascrittura della v-table e del puntatore a funzione Sovrascrittura del gestore eccezioni Può essere sfruttato dai worm S. Bistarelli - Metodologie di Secure Programming 18 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Possibili conseguenze dei sovraccarichi buffer Possibile conseguenza Obiettivo dell'hacker Violazione dell'accesso Realizzare gli attacchi DoS (denial of service) contro i server Instabilità Interferire con il normale funzionamento del software Inserimento di codice Ottenere privilegi per il proprio codice Sfruttare dati aziendali di vitale importanza Eseguire azioni distruttive S. Bistarelli - Metodologie di Secure Programming 19 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione I buffer overrun dell'heap Sovrascrivono i dati memorizzati nell'heap Sono più difficili da sfruttare di un buffer overrun Dati Puntatore Dati strcpy Dati xxxxxxx Puntatore xxxxxxx Puntatore S. Bistarelli - Metodologie di Secure Programming 20 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione I buffer overrun dell'heap: example 1 class CustomerRecord { private: char szName[20]; char szAddress[10]; char szPassword[20]; char szCreditHistory[200]; char szBankDetails[25]; S. Bistarelli - Metodologie di Secure Programming 21 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione void ChangeAddress (char *a) { strcpy (szAddress, a); } bool ChangePassword (char *newpwd, char *oldpwd) { bool res=false; if (strcmp (oldpwd, szPassword)==0) { strcpy (szPassword, newpwd); res=true; } return res; } S. Bistarelli - Metodologie di Secure Programming 22 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione char * GetSensitiveData (char *pwd) { if (strcmp (pwd, szPassword)==0) { // return all the personal info! return "Here's all the personal info...\n"; } else return ""; } S. Bistarelli - Metodologie di Secure Programming 23 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Eseguire procedura Come faccio ad ottenere GetSensitiveData password Se non conosco la password=secret?? Trucco: ChangeAddress … Buffer overflow su ?? Heap!! char szAddress[10]; char szPassword[20]; S. Bistarelli - Metodologie di Secure Programming 24 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Esempio di sovraccarico buffer basato sullo stack int main(int argc, char* argv[]) { //A blatant shortcut printf("Address of foo = %p\n", foo); printf("Address of bar = %p\n", bar); foo(argv[1]); return 0; } Attacco: lanciare bar … senza che codice lanci bar S. Bistarelli - Metodologie di Secure Programming 25 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione void foo(const char* input) { char buf[10]; //What? No extra arguments supplied to printf? //It is a cheap trick to view the stack printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n\n"); //Pass the user input straight to secure code public enemy #1. strcpy(buf, input); printf("%s\n", buf); printf("Now the stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n\n"); } void bar(void) { printf("The attack!\n"); } S. Bistarelli - Metodologie di Secure Programming 26 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Devo passare dei parametri a foo, in modo tale che AL RITORNO mi vada prima ad eseguire bar!!! Quindi devo far scrivere a foo sul suo indirizzo di ritorno l’indirizzo di bar S. Bistarelli - Metodologie di Secure Programming 27 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Eseguiamo codice 00000000 buf 00000A28 7FFDC000 0012FEE4 SFP 0040108A ret 0032116F } S. Bistarelli - Metodologie di Secure Programming 28 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Dopo chiamata procedura e input 12345 34333231 buf 00000035 7FFDF000 0012FEE4 SFP 0040108A ret 0032116F } Dove ho scritto su buffer 12345 ??? Conosciamo cygnus HexEditor Little-big endian S. Bistarelli - Metodologie di Secure Programming 29 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Conosciamo cygnus HexEditor 12345 In esadecimale 31 32 33 34 35 S. Bistarelli - Metodologie di Secure Programming 30 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Big-endian e little-endian sono due metodi differenti usati dai calcolatori per immagazzinare in memoria dati di dimensione superiore al byte (es. word, dword, qword). S. Bistarelli - Metodologie di Secure Programming 31 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione big-endian è la memorizzazione che inizia dal byte più significativo per finire col meno significativo; è utilizzata dai processori Motorola, IBM e Sun e nei protocolli usati in Internet viene anche chiamato network byte order. little-endian è la memorizzazione che inizia dal byte meno significativo per finire col più significativo; è utilizzata dai processori Intel e Digital S. Bistarelli - Metodologie di Secure Programming 32 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Etimologia Big-endian e little-endian sono tratti dal nome dei due gruppi di persone incontrati dal personaggio fantastico Gulliver durante i suoi viaggi, in continuo litigio su quale lato fosse il migliore da rompere nelle uova. S. Bistarelli - Metodologie di Secure Programming 33 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione esempi Nel caso di una DWORD, il numero esadecimale 0x01234567 verrà immagazzinato rispettivamente: Little endian +----+----+----+----+ |0x67|0x45|0x23|0x01| +----+----+----+----+ byte: 0 1 2 3 Big endian +----+----+----+----+ |0x01|0x23|0x45|0x67| +----+----+----+----+ 0 1 2 3 (Negli esempi il valore in grassetto è il byte più significativo) S. Bistarelli - Metodologie di Secure Programming 34 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Dopo chiamata procedura e input 12345 34333231 buf 00000035 7FFDF000 0012FEE4 SFP 0040108A ret 0032116F } Dove ho scritto su buffer 12345 ??? Conosciamo cygnus HexEditor Little-big endian Allora che input devo dare ?? per ottenere cosa ??? S. Bistarelli - Metodologie di Secure Programming 35 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Provare input 1234 12341234 1234123412 (10 byte) per buff 123412341234 (posso facilmente salvarne di piu’ perche’ allocate multipli di dword) Poi sovrascrivo indirizzo EBP e indirizzo di ritorno!! Uso di editor esadecimale FINE!! S. Bistarelli - Metodologie di Secure Programming 36 UNIVERSITÀ DI PERUGIA DIPARTIMENTO DI MATEMATICA E INFORMATICA Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Weird example!!! LAB! Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione the goal is to enter a serial and to get the good boy message Using a buffer overflow of the stack!! Tools: Debugger Disassembler odbg110.zip freeida43.exe Hexeditor cygnusfe.zip S. Bistarelli - Metodologie di Secure Programming 38 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Run the program: -- The analyst's weird crackme ---------------------------------enter your serial please: S. Bistarelli - Metodologie di Secure Programming 39 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione !Run ida disassembler! No way to go to the CODE:00401177 push offset aWooCongrats ; format S. Bistarelli - Metodologie di Secure Programming 40 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione The source int main(){ int i,len,temp; unsigned char name[75]; unsigned long check=0; printf("-- The analyst's weird crackme --\n"); printf("---------------------------------\n"); printf("enter your serial please:\n"); gets(name); asm{ nop}; len=strlen(name); S. Bistarelli - Metodologie di Secure Programming 41 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione //cout << len; if (len < 25) goto theend; if (len > 120 ) goto theend; for (i=1; i <= len ; i++) { temp += name[i] ; } if (temp = 31337) goto theend; if (temp < 5000) goto theend; if (temp > 15000) goto theend; goto theend; printf("wOO! congrats ;)\n"); theend: getch(); return 0; } S. Bistarelli - Metodologie di Secure Programming 42 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Analisi dell’assembler: Push (per mettere su stack parametri della gets, ) CODE:0040112E CODE:0040112F CODE:00401132 CODE:00401133 CODE:00401138 CODE:00401139 CODE:0040113A CODE:0040113D pop ecx lea eax, [ebp+s] ; buffer push eax ;s call _gets ; get entered serial pop ecx nop lea edx, [ebp+s] push edx ;s S. Bistarelli - Metodologie di Secure Programming 43 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Quanto è grande buffer in memoria? S. Bistarelli - Metodologie di Secure Programming 44 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Vediamo struttura stack!! Pulsante “open stack variables” (CTRL-K) FFFFFFB4 s db ? FFFFFFB5 db ? ; undefined :: :: Buf di quante FFFFFFFD db ? ; undefined word? FFFFFFFE db ? ; undefined FFFFFFFF db ? ; undefined EBP 00000000 s db 4 dup(?) RET 00000004 r db 4 dup(?) 00000008 argc dd ? 0000000C argv dd ? ; offset (FFFFFFFF) 00000010 envp dd ? ; offset (FFFFFFFF) 00000014 } S. Bistarelli - Metodologie di Secure Programming 45 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Siccome indirizzo delle istruzioni di successo è 00401177 dovremo provocare un buffer overflow in una procedura e inserire come codice di ritorno quello Tramite editor esadecimale 00401177 w @ S. Bistarelli - Metodologie di Secure Programming 46 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione n.b Finora abbiamo solo modificato puntatore .. Non abbiamo iniettato noi codice (lo faremo nell’esercitazione linux) S. Bistarelli - Metodologie di Secure Programming 47 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Di solito, Lo scopo di un buffer overflow attack è di modificare il funzionamento di un programma privilegiato in modo da prenderne il controllo e, nel caso il programma abbia sufficienti privilegi, prendere il controllo dell’ host. Typically the attacker is attacking a root program, and immediately executes code similar to “exec(sh)” to get a root shell. S. Bistarelli - Metodologie di Secure Programming 48 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione 1. 2. To achieve this goal, the attacker must achieve two sub-goals: Arrange for suitable code to be available in the program's address space. Get the program to jump to that code, with suitable parameters loaded into registers & memory. S. Bistarelli - Metodologie di Secure Programming 49 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione The “buffer” part how the attack code is placed in the victim program’s address space Inject it! It is already there For instance, if the attack code needs to execute “exec(“/bin/sh”)”, and there exists code in libc that executes “exec(arg)” where “arg” is a string pointer argument, then the attacker need only change a pointer to point to “/bin/sh” and jump to the appropriate instructions in the libc library S. Bistarelli - Metodologie di Secure Programming 50 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione The “overflow” part how the attacker overflows a program buffer to alter adjacent program state Overflow a buffer with weak bound check, with the goal of corrupting the state of an adjacent part of the program’s state (adjacent pointers) S. Bistarelli - Metodologie di Secure Programming 51 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Le vie di ingresso!! S. Bistarelli - Metodologie di Secure Programming 52 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Buffer overflow (basati sullo stack) Ovviamente il processo deve avere delle "vie d'ingresso". Ad esempio dei parametri che l'utente può specificare nella linea di comando, dei pacchetti da inviare ad una porta in ascolto del processo (quest'ultimo caso è quello più pericoloso perchè consente di effettuari attachi da remoto). In questa sede consideriamo l'esempio classico di attacco basato sul buffer overflow dello stack su di un parametro del processo a linea di comando. Che tipo di codice è possibile inserire in un attacco basato su buffer overflow? Si deve utilizzare un bytecode, ossia un codice autonomo, scritto in linguaggio macchina, che non deve contenere determinati caratteri speciali nelle sue istruzioni perchè deve sembrare un buffer di dati. S. Bistarelli - Metodologie di Secure Programming 53 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Un tipico esempio di bytecode è il cosiddetto shellcode. Ossia un bytecode che genera una shell. Se si riesce a manomettere un programma suid root in maniera che esegua una shellcode è possibile prendere il possesso di un sistema, avendo privilegi da root, mentre il sistema è convinto che il programma suid root stia ancora assolvendo i suoi compiti previsti. S. Bistarelli - Metodologie di Secure Programming 54 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione A questo punto sorgono due problemi: (1) Dal momento che dobbiamo inserire del codice di tipo bytecode nello stack, che è una struttura dinamica, come possiamo determinare la posizione assoluta in memoria della nostra prima istruzione bytecode? (2) Una volta determinata questa posizione come possiamo modificare l'istruzione di ritorno ret dello stack frame? Non è possibile determinare la posizione assoluta del bytecode nello stack, per questo motivo è necessario utilizzare un espediente, il NOP sled (NOP = nessuna operazione, sled è la traduzione di slitta) S. Bistarelli - Metodologie di Secure Programming 55 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione NOP è un istruzione assembler vuota, non esegue niente. Viene utilizzata per gestire sincronizzazioni su cicli di calcolo... La tecnica del NOP sled consiste nell'inserire prima del nostro bytecode un grande array di istruzioni NOP (una slitta di NOP). Così facendo anche se l'istruzione di ritorno (ret) dovesse saltare su una posizione qualsiasi della slitta di NOP alla fine il bytecode verrebbe comunque eseguito. Ciò non toglie che per risolvere il primo problema dobbiamo comunque avere una stima dell'indirizzo del bytecode. S. Bistarelli - Metodologie di Secure Programming 56 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Una volta che abbiamo stimato la possibile posizione del nostro bytecode possiamo utilizzare un'altra tecnica per risolvere il secondo problema che consiste nel riempire la fine del nostro buffer, dopo il bytecode, con l'indirizzo di ritorno stimato. In questa maniera, purchè uno di questi indirizzi di ritorno sovrascriva l'indirizzo di ritorno reale, l'espediente darà il risultato desiderato. Utilizzando queste tecniche il nostro buffer avrà una forma del genere: NOP sled bytecode Indirizzo di ritorno ripetuto S. Bistarelli - Metodologie di Secure Programming 57 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Di seguito è riportato il codice assembly (memorizzato in una variabile definita in C) di una shellcode (si veda il file exploit.c in allegato): char shellcode[] = "\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0" "\x88\x43\x07\x89\x5b\x08\x89\x43\x0c\xb0\x0b\x8d\x4b\x08\x8d" "\x53\x0c\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73" "\x68"; Gli step per l'esecuzione del ns. buffer overflow: 1) stima dell'indirizzo di ritorno (ret), nel ns. caso ret=stack pointer; 2) buffer= NOP sled + shellcode + indirizzo ret ripetuto; 3) esecuzione del programma vuln.c che ha vulnerabilità passandogli come parametro buffer il buffer costruito in exploit.c (tramite l'istruzione exec(“./vuln”,”vuln”,buffer,0)); S. Bistarelli - Metodologie di Secure Programming 58 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Heap!! S. Bistarelli - Metodologie di Secure Programming 59 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Un tipo di vulerabilità simile allo stack-based buffer overflow è lo heap-based buffer overflow che segue lo stesso principio ma partendo da variabili allocate nello heap, quindi non staticamente ma dinamicamente con funzioni della famiglia malloc(). Lo heap ("mucchio") è una zona di memoria allocata dinamicamente durante l'esecuzione (runtime) di un processo. Un array di caratteri, allocato dinamicamente attraverso una chiamata malloc/calloc fara' parte dello heap. In generale qualunque assegnazione dinamica di memoria contigua farà parte dello heap. Viceversa, quando la porzione di memoria non e' piu' utile, viene chiamata una funzione che libera tale zona di memoria: free(). S. Bistarelli - Metodologie di Secure Programming 60 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Un semplice overflow basato su heap Consideriamo l'esempio contenuto nel file heap.c (in allegato). In questo caso si allocano due variabili userinput e outputfile nello heap con dimensioni fisse e pari a 20 byte. Cosa succede se si inserisce un valore > di 20 byte in una delle due variabili? Si ha un overflow. E se le due variabili vengono allocate in memoria in zone contigue l'overflow su una di esse può sovrascrivere il contenuto dell'altra. char *userinput = malloc(20); char *outputfile = malloc(20); 20 Ad esempio un overflow sulla variabile userinput provoca la 20 sovrascrittura della variabile outputfile. S. Bistarelli - Metodologie di Secure Programming Heap userinput outputfile 61 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Proviamo ad eseguire il programma heap.c $ ./heap prova ---DEBUG-[*] userinput @ 0x80499d8: prova [*] outputfile @ 0x80499f0: /tmp/notes [*] distance between: 24 ----------------Writing to “prova” to the end of /tmp/notes... Cosa succede se utilizziamo un parametro con più di 24 byte? $ ./heap 123456789012345678901234test ---DEBUG-[*] userinput @ 0x80499d8: 123456789012345678901234test [*] outputfile @ 0x80499f0: test [*] distance between: 24 ----------------Writing to “123456789012345678901234test” to the end of test... S. Bistarelli - Metodologie di Secure Programming 62 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione BSS S. Bistarelli - Metodologie di Secure Programming 63 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Buffer overflow (basati su BSS, Block Started by Symbol) I buffer overflow basati su BSS sfruttano lo stesso principio dei buffer overflow basati su heap. Le variabili globali e statiche di un programma vengono allocate nella zona di memoria BSS in maniera contigua. Un overflow di una di queste variabili provoca la sovrascrittura di altre variabili. Consideriamo l'esempio (bss_game.c, in allegato). In questo programma si utilizzano due variabili statiche: static char buffer[20]; static int (*function_ptr) (int user_pick); Come per l'esempio sullo heap è possibile provocare un overflow della variabile buffer (parametro del programma) sovrascrivendo il contenuto del puntatore a funzione function_ptr! In questo caso posso far eseguire un bytecode come per il buffer overflow basato sullo stack!!! S. Bistarelli - Metodologie di Secure Programming 64 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Come evitare buffer overflow S. Bistarelli - Metodologie di Secure Programming 65 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Come difendersi dai buffer overrun Utilizzare con particolare cautela le seguenti funzioni: strcpy strncpy CopyMemory MultiByteToWideChar Utilizzare l'opzione di compilazione /GS in Visual C++ per individuare i sovraccarichi buffer Utilizzare strsafe.h per un gestione del buffer più sicura S. Bistarelli - Metodologie di Secure Programming 66 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione La soluzione più immediata e sicura consiste nell'inserire controlli sulle dimensioni dei parametri inseriti dall'utente, in modo da assicurarsi che non si verifichino overflow. Molte volte, soprattutto in programmi complessi, l'utilizzo di controlli sulle dimensioni delle variabili può risultare pesante. Si possono così utilizzare funzioni che non provocano overflow anche in presenza di parametri sovradimensionati. Ad esempio l'utilizzo delle funzioni C strlcpy() e strlcat() al posto di strcpy(). Un alternativa è l'utilizzo di librerie considerate "sicure” progettate proprio per evitare buffer overflow. Ad esempio LibSafe (http://www.research.avayalabs.com/project/libsafe/). Altre possibilità di prevenire buffer overflow sono fornite da strumenti in grado di rilevare tali bug, come StackGuard (per i buffer overflow basati sullo stack). http://www.cse.ogi.edu/DISC/projects/immunix/StackGuard/ S. Bistarelli - Metodologie di Secure Programming 67 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Defenses Writing correct code 1. Code auditing Non executable buffer 2. Data segment non executable Code pointer integrity checking 3. detect that a code pointer has been corrupted before it is dereferenced. Stack Introspection by Snarskii Create a new libc Stackguard (Activation Record Integrity Checking) Pointguard (function pointer integrity checking) S. Bistarelli - Metodologie di Secure Programming 68 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Defenses 4. Array bounds checking The Compaq C compiler for the Alpha CPU (“-check_bounds”) : Richard Jones and Paul Kelly developed a gcc patch that does full array bounds checking for C programs. The performance costs are substantial Purify: is a memory usage debugging tool for C programs. only explicit array references are checked, i.e. “a[3]” is checked, while “*(a+3)” is not since all C arrays are converted to pointers when passed as arguments, no bounds checking is performed on accesses made by subroutines dangerous library functions (i.e. strcpy()) are not normally compiled with bounds checking, and remain dangerous even with bounds checking enabled Purify uses “object code insertion” to instrument all memory accesses. After linking with the Purify linker and libraries, one gets a standard native executable program that checks all of its array references to ensure that they are legitimate. imposes a 3 to 5 times slowdown. Type-Safe Languages S. Bistarelli - Metodologie di Secure Programming 69 UNIVERSITÀ DI PERUGIA DIPARTIMENTO DI MATEMATICA E INFORMATICA Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Safe and unsafe functions Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Strcpy vs strncpy char * strcpy ( char * destination, const char * source ); Copies the C string pointed by source into the array pointed by destination, including the terminating null character. To avoid overflows, the size of the array pointed by destination shall be long enough to contain the same C string as source (including the terminating null character), and should not overlap in memory with source. S. Bistarelli - Metodologie di Secure Programming 71 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Strcpy vs strncpy char * strncpy ( char * destination, const char * source, size_t num ); •Copies the first num characters of source to destination. •If the end of the source C string (which is signaled by a null-character) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it. •No null-character is implicitly appended to the end of destination, so destination will only be null-terminated if the length of the C string in source is less than num. S. Bistarelli - Metodologie di Secure Programming 72 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione strncpy if the length of the src string is >= n, you end up without null termination char dest[LEN]; char *src; ... /* src is set to point to a source string of unknown length */ strncpy(dest,src,LEN); dest[LEN-1]='\0'; /* null terminate for safety */ S. Bistarelli - Metodologie di Secure Programming 73 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione strncpy Using strncpy() has performance implications, because it zero-fills all the available space in the target buffer after the ’\0’ terminator. a strncpy() of a 13-byte buffer into a 2048-byte buffer overwrites the entire 2048-byte buffer S. Bistarelli - Metodologie di Secure Programming 74 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione strnlcpy Look on the web!! Problemi di compatibilità!! S. Bistarelli - Metodologie di Secure Programming 75 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Fail solo se input o buf e’ un illegal pointer Se input troppo lungo verrà troncato S. Bistarelli - Metodologie di Secure Programming 76 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Non si tronca il buffer, se troppo lungo si ottiene errore GESTITO!! S. Bistarelli - Metodologie di Secure Programming 77 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Sprintf vs snprintf int sprintf (String, Format, [Value, ...]) char *String; const char *Format; The sprintf subroutine converts, formats, and stores the Value parameter values, under control of the Format parameter, into consecutive bytes, starting at the address specified by the String parameter. The sprintf subroutine places a null character (\0) at the end. You must ensure that enough storage space is available to contain the formatted string. S. Bistarelli - Metodologie di Secure Programming 78 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Sprintf vs snprintf int snprintf (String, Number, Format, [Value, . . .]) char *String; int Number; const char *Format; The snprintf subroutine is identical to the sprintf subroutine with the addition of the Number parameter, which states the size of the buffer referred to by the String parameter. S. Bistarelli - Metodologie di Secure Programming 79 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione _snprintf In w32 environment Non setta il \0 finale!!! S. Bistarelli - Metodologie di Secure Programming 80 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Gets vs fgets char *gets(char *s); read a line of data from STDIN. gets continues to read characters until NEWLINE or EOF is seen The NEWLINE character is NOT placed in the buffer gets does NOT check the size of the buffer and overflow on the stack can occour. S. Bistarelli - Metodologie di Secure Programming 81 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione char *fgets(char *s, int n, FILE *stream); fgets is used to read a line of data from an external source. If fgets is reading STDIN, the NEWLINE character is placed into the buffer. it checks that the incoming data does not exceed the buffer size S. Bistarelli - Metodologie di Secure Programming 82 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Use strsafe.h!! S. Bistarelli - Metodologie di Secure Programming 83 UNIVERSITÀ DI PERUGIA DIPARTIMENTO DI MATEMATICA E INFORMATICA Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Secure Programming opensource software Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Open vs closed source Open-source software is more secure than closed software E.S. Raymond, The Cathedral & the Bazaar: Musings on Linux and Open Source by an Accidental Revolutionary, O’Reilly & Assoc., 1999. And the contrary K. Brown, Opening the Open Source Debate, Alexis de Tocqueville Inst., 2002; www.adti.net/cgi-local/SoftCart.100.exe/online-store/scstore/pbrown_%1.html?L+scstore+llfs8476ff0a810a+1042027622 !!The defender can install and configure the SW with high security concerns!! !!The attacker know the source code!! (if the defender just install it wothout any personal configuration!) S. Bistarelli - Metodologie di Secure Programming 85 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Toward a perfect software! 1. Software auditing 2. Vulnerability mitigation 3. which prevents vulnerabilities by searching for them ahead of time, with or without automatic analysis which are compile-time techniques that stop bugs at runtime Behavior management which are operating system features that either limit potential damage or block specific behaviors known to be dangerous S. Bistarelli - Metodologie di Secure Programming 86 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione SW auditing tools S. Bistarelli - Metodologie di Secure Programming 87 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione 1. Software auditing Auditing source code for correctness!! Good practice!! Difficult and time-consuming Sardonix project (2003) Record which code has been audited and by whom Provide rank for people partecipating to the project (to be used in the resume) Help novice auditors with a lot of resources and FAQ Static analyzers Dynamic debuggers S. Bistarelli - Metodologie di Secure Programming 88 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione Sardonix resource Static analyzers Sintactically check the code Ok for strongly typed languages (Java, ML, …) Undecidable for for weakly typed languages (C, Perl, …) But some false positive/negative Use some heuristics Dynamic debuggers Run the program under test loads S. Bistarelli - Metodologie di Secure Programming 89 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione 2. Vulnerability mitigation tools S. Bistarelli - Metodologie di Secure Programming 90 Master di I° livello in Sistemi e Tecnologie per la sicurezza dell'Informazione e della Comunicazione 3. Behaviour management S. Bistarelli - Metodologie di Secure Programming 91