Buffer%20overflow%20attack%20and%20defense - PowerPoint PPT Presentation

About This Presentation
Title:

Buffer%20overflow%20attack%20and%20defense

Description:

Title: PowerPoint Presentation Last modified by: Stefano Bistarelli Created Date: 1/1/1601 12:00:00 AM Document presentation format: Presentazione su schermo – PowerPoint PPT presentation

Number of Views:158
Avg rating:3.0/5.0
Slides: 92
Provided by: unip235
Category:

less

Transcript and Presenter's Notes

Title: Buffer%20overflow%20attack%20and%20defense


1
Buffer overflow attack and defense
  • Prof. Stefano Bistarelli

C Consiglio Nazionale delle Ricerche Iit
Istituto di Informatica e Telematica - Pisa
Università G. dAnnunzioDipartimento di
Scienze, Pescara
2
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.

3
(No Transcript)
4
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).

5
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
Indirizzi di memoria bassi
Indirizzi di memoria alti
0xFFFFFFFF
6
Organizzazione della memoria di un processo

7
a volte considereremo il disegno opposto
8
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.

xpop
push(x)
Stack
1) xa, 2) xb, 3) xc
1) xc, 2) xb, 3) xa
9
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).

10
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.

11
Lo Stack e i registri di sistema
  • Quando viene richiamata una funzione (call) il
    sistema inserisce nello stack l'indirizzo
    dell'istruzione successiva, push(EIP4) dove 4
    indica 4 byte (4byte1dword), 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.

12
  • EIP, EBP, ESP
  • EIP va in stack
  • EBP va in stack (chiamato SFP)
  • EBP ESP
  • Settato nuovo ESP (lunghezza della procedura
    chiamata)

13
Un esempio in C
Analizziamo quest'esempio di codice in C per
capire meglio l'allocazione dello stack
framevoid test_function (int a, int b)
char flag char buffer10 int main()
test_function (1,2) exit(0)
EIP
Stato dello stack frame
Indirizzo di ritorno (ret) EIP 4 byte
SFP Saved Frame Pointer, valore utilizzato per
rispristinare lo stato originale di EBP (prima
della chiamata di test_function())
14
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.
  • 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).

15
Esempio di overflow
Analizziamo quest'esempio di codice in C che
provoca un overflowvoid overflow_function
(char str) char buffer20
strcpy(buffer, str) // Funzione che copia str
nel buffer int main() char
big_string128 int i for(i0 i lt 128
i) big_stringi 'A'
overflow_function(big_string) exit(0)
Questa istruzioneprovoca un overflow!
16
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!)
memoriabassa
memoriabassa

AA...A
buffer
20 byte

SFP
A
Indirizzo di ritorno (ret)
A
108 byte
str (argomento)
A
memoriaalta
A
17
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
  • modificare tale istruzione di ritorno ed
  • inserire arbitrariamente del codice in un
    processo?

18
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

19
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
20
I buffer overrun dell'heap
  • Sovrascrivono i dati memorizzati nell'heap
  • Sono più difficili da sfruttare di un buffer
    overrun

xxxxxxxxxxxxxx
strcpy
21
I buffer overrun dell'heap example 1
  • class CustomerRecord
  • private
  • char szName20
  • char szAddress10
  • char szPassword20
  • char szCreditHistory200
  • char szBankDetails25

22
  • void ChangeAddress (char a)
  • strcpy (szAddress, a)
  • bool ChangePassword (char newpwd, char oldpwd)
  • bool resfalse
  • if (strcmp (oldpwd, szPassword)0)
  • strcpy (szPassword, newpwd)
  • restrue
  • return res

23
  • char GetSensitiveData (char pwd)
  • if (strcmp (pwd, szPassword)0)
  • // return all the personal info!
  • return "Here's all the personal info...\n"
  • else
  • return ""

24
  • Eseguire procedura
  • Come faccio ad ottenere
  • GetSensitiveData password
  • Se non conosco la passwordsecret??
  • Trucco
  • ChangeAddress ?
  • Buffer overflow su ?? Heap!! ?
  • char szAddress10
  • char szPassword20

25
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(argv1)
  • return 0
  • Attacco lanciare bar
  • senza che codice lanci bar

26
  • void foo(const char input)
  • char buf10
  • //What? No extra arguments supplied to
    printf?
  • //It is a cheap trick to view the stack
  • printf("My stack looks like\np\np\np\np\n
    p\np\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\np\np\np\np\np\np\n\n")
  • void bar(void)
  • printf("The attack!\n")

27
  • 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 lindirizzo di bar

28
Eseguiamo codice
  • 00000000
  • 00000A28
  • 7FFDC000
  • 0012FEE4
  • 0040108A
  • 0032116F

buf
SFP
ret
29
Dopo chiamata procedura e input 12345
  • 34333231
  • 00000035
  • 7FFDF000
  • 0012FEE4
  • 0040108A
  • 0032116F
  • Dove ho scritto su buffer 12345 ???
  • Conosciamo cygnus HexEditor
  • Little-big endian

buf
SFP
ret
30
  • Conosciamo cygnus HexEditor
  • 12345
  • In esadecimale
  • 31 32 33 34 35

31
  • 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).

32
  • 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

33
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.

34
esempi
Nel caso di una DWORD, il numero esadecimale
0x01234567 verrà immagazzinato rispettivamente
Little endian Big endian
----------------
---------------- 0x670x450x230x01
0x010x230x450x67
---------------- ----------------
byte 0 1 2 3 0 1 2
3 (Negli esempi il valore in grassetto è il
byte più significativo)
35
Dopo chiamata procedura e input 12345
  • 34333231
  • 00000035
  • 7FFDF000
  • 0012FEE4
  • 0040108A
  • 0032116F
  • Dove ho scritto su buffer 12345 ???
  • Conosciamo cygnus HexEditor
  • Little-big endian

buf
SFP
ret
Allora che input devo dare ?? per ottenere cosa
???
36
  • 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!! ?

37
Weird example!!! LAB!
38
  • the goal is to enter a serial and to get the good
    boy message
  • Using a buffer overflow of the stack!!
  • Tools
  • Debugger
  • odbg110.zip
  • Disassembler
  • freeida43.exe
  • Hexeditor
  • cygnusfe.zip

39
  • Run the program

-- The analyst's weird crackme -- ----------------
----------------- enter your serial please
40
!Run ida disassembler!
  • No way to go to the
  • CODE00401177 push offset
    aWooCongrats format

41
The source ?
int main() int i,len,temp unsigned
char name75 unsigned long check0
printf("-- The analyst's weird crackme --\n")
printf("---------------------------------\n")
printf("enter your serial please\n")
gets(name) asm nop
lenstrlen(name)
42
//cout ltlt len if (len lt 25) goto theend
if (len gt 120 ) goto theend for (i1 i lt
len i) temp namei
if (temp 31337) goto theend if
(temp lt 5000) goto theend if (temp gt 15000)
goto theend goto theend
printf("wOO! congrats )\n")
theend getch() return 0
43
  • Analisi dellassembler
  • Push (per mettere su stack parametri della gets,
    )
  • CODE0040112E pop ecx
  • CODE0040112F lea eax,
    ebps buffer
  • CODE00401132 push eax
    s
  • CODE00401133 call _gets
    get entered serial
  • CODE00401138 pop ecx
  • CODE00401139 nop
  • CODE0040113A lea edx,
    ebps
  • CODE0040113D push edx
    s

44
  • Quanto è grande buffer in memoria?

45
Vediamo struttura stack!!
  • Pulsante open stack variables (CTRL-K)
  • FFFFFFB4 s db ?
  • FFFFFFB5 db ? undefined
  • FFFFFFFD db ? undefined
  • FFFFFFFE db ? undefined
  • FFFFFFFF db ? undefined
  • 00000000 s db 4 dup(?)
  • 00000004 r db 4 dup(?)
  • 00000008 argc dd ?
  • 0000000C argv dd ?
    offset (FFFFFFFF)
  • 00000010 envp dd ?
    offset (FFFFFFFF)
  • 00000014


Buf di quante word?
46
  • 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_at_

47
n.b
  • Finora abbiamo solo modificato puntatore ..
  • Non abbiamo iniettato noi codice (lo faremo
    nellesercitazione linux)

48
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.

49
  • 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.

50
The buffer part
  • how the attack code is placed in the victim
    programs 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

51
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 programs state (adjacent pointers)

52
Le vie di ingresso!!
53
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.

54
  • 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.

55
  • 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)

56
  • 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.

57
  • 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

58
  • 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\x
    c9\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 retstack 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))

59
Heap!!
60
  • 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().

61
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 gt 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)
  • Ad esempio un overflow sulla
  • variabile userinput provoca la
  • sovrascrittura della variabile outputfile.

Heap
userinput
20
outputfile
20
62
  • Proviamo ad eseguire il programma heap.c
  • ./heap prova
  • ---DEBUG--
  • userinput _at_ 0x80499d8 prova
  • outputfile _at_ 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 _at_ 0x80499d8 12345678901234567890123
    4test
  • outputfile _at_ 0x80499f0 test
  • distance between 24
  • -----------------
  • Writing to 123456789012345678901234test to the
    end of test...

63
BSS
64
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 buffer20
    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!!!

65
Come evitare buffer overflow
66
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

67
  • 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 Cstrlcpy()
    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/p
    rojects/immunix/StackGuard/

68
Defenses
  • Writing correct code
  • Code auditing
  • Non executable buffer
  • Data segment non executable
  • Code pointer integrity checking
  • 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)

69
Defenses
  • Array bounds checking
  • The Compaq C compiler for the Alpha CPU
    (-check_bounds)
  • only explicit array references are checked, i.e.
    a3 is checked, while (a3) 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
  • 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.
  • 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

70
Safe and unsafe functions
71
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.

72
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.

73
strncpy
  • if the length of the src string is gt n, you end
    up without null termination
  • char destLEN
  • char src ... / src is set to point to a source
    string of unknown length /
  • strncpy(dest,src,LEN)
  • destLEN-1'\0' / null terminate for safety /

74
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

75
strnlcpy
  • Look on the web!!
  • Problemi di compatibilità!!

76
  • Fail solo se input o buf e un illegal pointer
  • Se input troppo lungo verrà troncato ?

77
  • Non si tronca il buffer, se troppo lungo si
    ottiene errore GESTITO!!

78
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.

79
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.

80
_snprintf
  • In w32 environment
  • Non setta il \0 finale!!! ?

81
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.

82
  • 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

83
Use strsafe.h!!
84
Secure Programming open-source software
85
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, OReilly Assoc., 1999.
  • And the contrary
  • K. Brown, Opening the Open Source Debate, Alexis
    de Tocqueville Inst., 2002 www.adti.net/cgi-loca
    l/SoftCart.100.exe/online-store/scstore/p-
    brown_1.html?Lscstorellfs8476ff0a810a104202762
    2
  • !!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!)

86
Toward a perfect software!
  • Software auditing
  • which prevents vulnerabilities by searching for
    them ahead of time, with or without automatic
    analysis
  • Vulnerability mitigation
  • 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

87
SW auditing tools
88
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

89
Sardonix resource
  • Static analyzers
  • Sintactically check the code
  • Ok for strongly typed languages (Java, ML, )
  • But some false positive/negative
  • Undecidable for for weakly typed languages (C,
    Perl, )
  • Use some heuristics
  • Dynamic debuggers
  • Run the program under test loads

90
2. Vulnerability mitigation tools
91
3. Behaviour management
Write a Comment
User Comments (0)
About PowerShow.com