domenica 5 dicembre 2010

Sfruttare i punti vulnerabili del software - Stack overflow

Prendiamo in esame il programma in C dell' articolo precedente,nel momento in cui si richiama la funzione copia() lo stack ha piu o meno  l'aspetto della figura.Quando la funzione cerca di scrivere 100 byte di dati nel buffer da 20 byte, i dati invadono il segmento di memoria adiacente  sovrascrivendo  puntatore dello stack frame , indirizzo di ritorno e l 'argomento della funzione.Dopo l 'esecuzione della funzione il programma cerca di ritornare all' istruzione successiva, ma trova un indirizzo diverso da quello memorizzato nello stack in origine, in questo caso, visto che abbiamo usato la lettera T(esadecimale 0x54), EIP punterà al valore 0x54545454, esso è un indirizzo di memoria scelto a caso che può contenere istruzioni non valide o essere inesistente, questo è il motivo per cui il programma è andato in crash.Ora se al posto dell' indirizzo 0x54545454 usato per sovrascrivere EIP si fosse utilizzato qualche indirizzo corrispondente a un codice eseguibile, il programma non si sarebbe bloccato ma avrebbe eseguito l' istruzione modificando il flusso di esecuzione del programma. Visto che è possibile modificare un indirizzo di ritorno, per prendere il controllo completo del software manca solo il codice da eseguire, qui entra in gioco l'iniezione di un "bytecode".Il bytecode è un pezzo di codice autonomo che può essere messo all' interno di un buffer, esso è soggetto ad alcune restrizioni in particolare non deve contenere caratteri speciali poichè deve sembrare un buffer di dati,il bytecode più comune è lo "shellcode" che genera una shell. Facciamo un esempio in linux, se si riesce a manomettere un programma "suid root" con uno shellcode allora l' aggressore disporrà dei privilegi di root, mentre il sistema è convinto che il programma suid root stia ancora assolvendo ai sui compiti  previsti.
Supponiamo che  il codice seguente sia un  programma suid root:

int main(int argc, char* argv[]){
char buff[500];
strcpy(buff,argv[]);
return 0;
}

Il buffer dovrà contenere lo shellcode e sovrascrivere l'indirizzo di ritorno, questo presuppone che l'indirizzo dello shellcode sia noto a priori, cosa non facile visto che lo stack cambia, vi è poi un'ulteriore complicazione i quattro byte dell' indirizzo di ritorno devono essere sovrascritti con l indirizzo dello shellcode.Per fare tutto ciò può essere utilizzata una tecnica nota come "NOP",si tratta di un'istruzione di un singolo byte che non fa assolutamente nulla,creando un grande array di istruzioni NOP e inserendole prima dello shellcode, se il puntatore EIP torna a qualunque indirizzo presente nel NOP viene incrementato di una unità fino al raggiungimento dello shellcode.

Nessun commento:

Posta un commento