giovedì 2 dicembre 2010

Sfruttare i punti vulnerabili del software - La Memoria

Prima di procedere con degli esempi pratici sulla scrittura degli exploit, bisogna necessariamente avere un'idea di come funziona un computer, mi rendo conto che per afferrare a pieno alcuni concetti bisognerebbe conoscere almeno le basi della programmazione a basso livello,  ci sono degli ottimi tutorial in internet su questo argomento basta avere la buona volontà di leggerli.Ora parliamo della memoria, essa consiste essenzialmente di byte destinati all' immagazzinamento dei dati che sono associati a indirizzi numerici.A questa memoria si può accedere mediante questi indirizzi leggendo o scrivendo,lo schema di indirizzamento a 32 bit, quello utilizzato dai processori x86, consente 2^32(4.294.967.296) indirizzi possibili.Oltre alla memoria RAM,il processore ha una sua memoria propria, di dimensioni modeste, le porzioni di memoria del processore vengono chiamate "registri" i più importanti sono:
-EIP ,puntatore all' istruzione successiva a 32 bit.
-EBP ,puntatore alla base del record di attivazione.
-ESP ,puntatore alla parte superiore dello stack.
Quando si programma ad alto livello ,ad esempio con il C ,le variabili devono essere dichiarate con un "tipo", questi "tipi" possono essere numeri interi, caratteri o anche strutture definite dall' utente, a seconda del "tipo" in fase di esecuzione viene allocata la giusta porzione di memoria.Dei particolari tipi di variabili sono i "vettori" o "buffer",che sono degli elenchi di un particolare tipo di dati, generalmente l'indirizzo del primo elemento del buffer viene memorizzato in un puntatore.Una particolarità della gestione della memoria dei processori x86 è il sistema di ordinamento detto "little endian" in cui il byte meno significativo è il primo,in pratica i byte sono posti in memoria in ordine inverso, anche se i compilatori ad alto livello tengono conto automaticamente dell' ordinamento dei byte, lavorando in assembler questo è un particolare da tenere presente.A volte per un vettore(supponiamo uno di caratteri) vengono allocati N byte di memoria ma ne vengono effettivamente utilizzati meno,ci saranno ovviamente dei byte superflui,Lo zero è utilizzato come delimitatore per terminare la stringa ad esempio:
 
byte         0 1 2 3 4 5 6 7 8 9 10 11 12 ....
caratteri  c i a o 0 x x x x x   x   x  x ....


La parola ciao in un buffer di N byte, nel quinto byte è presente lo zero che indica la fine della stringa di caratteri.La memoria di un programma è divisa in cinque segmenti chiamati:

-text
-data
-bss
-heap
-stack


In text sono memorizzate tutte le istruzioni in linguaggio macchina, è da notare che le istruzioni non sempre si susseguono in modo lineare, in quanto eventuali istruzioni come jump o call trasferiscono nel registro EIP un diverso indirizzo di memoria. Durante l' esecuzione del programma , l'autorizzazione a scrivere su questo segmento di memoria è disabilitata e questo segmento di memoria ha dimensione fissa.In data e in bss sono memorizzate le variabili globali e statiche, questi segmenti di memoria pur essendo modificabili in fase di esecuzione,hanno anche loro dimensione fissa. In heap sono memorizzate le altre variabili del programma, la dimensione di heap può variare in fase di esecuzione, a seconda delle necessità l' heap si espande o si contrae , quando si espande lo fa verso indirizzi di memoria più alti. Lo stack è sostanzialmente un "blocco note" utilizzato per immagazzinare temporaneamente i dati durante l' esecuzione di funzioni, quando un programma chiama una funzione essa avrà un proprio insieme di variabili che le vengono trasferite, e il codice della funzione sarà collocato in una diversa posizione dal segmento text.Visto che il registro EIP deve cambiare quando si esegue la funzione, lo stack serve per ricordare le variabili trasferite e l' indirizzo a cui EIP deve ritornare alla fine della funzione.Lo stack funziona con uno schema "frist in - last out" nel senso che il primo dato immesso sarà l' ultimo ad essere estratto, quando si inserisce un dato nello stack si usa il termine push, quando lo si estrae si usa pop. Il registro del processore ESP, serve per contenere l' indirizzo dell' ultimo dato in questo segmento di memoria.Lo stack , come   l' heap ha dimensione variabile, ma a differenza di heap quando si espande lo fa verso indirizzi di memoria più bassi.

Nessun commento:

Posta un commento