[Torna al Programma di Venerdi']-[Torna al Programma di Sabato]

The Blindfold Project

Sabato 17 giugno - 1800:2000 - Cattedrale

il Bindfold Project: si tratta di provare dei pacchetti IP, un po "alla cieca", fino a trovarne alcuni che fanno crashare una macchina target... ...e quindi si puo' "rinforzare" lo stack tcp/ip di linux...

Blindfold Project - Overview

L'obiettivo del Blinfold Project e' di trovare dei pacchetti IP (provando quasi tutti quelli possibili) che fanno andare in crash un computer "target" con Linux.
Una volta trovati questi pacchetti, sara' possibile rinforzare lo stack TCP/IP di Linux. Il sistema e' formato da tre parti: l'executor (cioe' l'host dove gira il programma che manda il pacchetti), il target (quello che riceve e pacchetti ed ogni tanti crasha :-) ed il packet server (quello che da i pacchetti da provare e riceve quelli gia' provati o "interessanti").
I pacchetti interessanti sono quelli che fanno crashare l'host target.

Mappatura dei pacchetti IP.

Un pacchetto IP, senza dati e senza opzioni, e' lungo 160 bit; escludendo i campi "destination address" e checksum che dovranno essere necessariamente validi, rimangono 112 bit. 2^112 = 10^33 (10^34). Un pacchetto IP e' lungo 160 bit (circa 10^2 bit), quindi ho 10^34 (pacchetti) * 10^2 (bit) = 10^36 bit. Con un flusso di 10Mbit/s (quindi 10^7 bit/s) per provare tutti i pacchetti (10^36 bit) mi servirebbero 10^29 secondi. In un anno di sono circa 10^7 secondi => 10^29 / 10^7 = 10^22 anni, sicuramente fuori dalla nostra portata.... Bisogna quindi fare delle semplificazioni, sapendo che ogni semplificazione puo' tenere fuori dai risultati un certo numero di pacchetti "interessanti".

Vediamo quindi le semplificazioni nel nostro progetto:

Di ogni pacchetto IP ci saranno alcuni campi che non saranno utilizzati per il testing:

altri campi assumeranno pochi valori (limite):

Per questi campi servono in totale 21 bit. Gli altri campi assumeranno tutti i valori possibili => 4 (ver) + 4 (header len) + 8 (TOS) + 3 (flags) + 8 (protocol) = 27 bit. In totale ci servono 21 + 27 = 48 bit (x pacchetto). (2^48 * 160) / 10^7 / 10^7 = 10^3 anni (cioe' con 1000 macchine in parallelo basta un anno per provarli tutti). Se invece di "portarci dietro" tutto il pacchetto IP, ci portiamo solo la parte che cambia, abbiamo circa 48 bit che possiamo mappare come se fossero sequenziali. L'importante e' che l'executor sappia come rimappare il pacchetto "ridotto" in quello completo.

Il Packet Server.

Il server e' un demone che passa ai richiedenti, un "chunk" alla volta e ritira i pacchetti controllati e interessanti. Un chunk e' formato da 10^10 pacchetti (di 48 bit), cioe' quelli controllabili in circa 30 ore. (10^12 bit / 10^7 bit/s = 10^5 secondi = 28 ore (circa) ).
Un chunk viene rappresentato come un valore a 48 bit (lunghezza del pacchetto) ed e' il valore del primo pacchetto da controllare.
Per trovare il primo pacchetto da controllare, si moltiplica il munero del chunk per 10^10. Volendo controllare 10^15 pacchetti (2^48), avremo 10^5 chunk di 10^10 pacchetti l'uno. Rappresentando con una matrice di bit (booleana) i chunk controllati e da controllare, avremo una matrice di 10^5 bit, cioe' 100KByte.
Quindi possiamo anche scandirla sequenzialmente senza fare alcuna struttura dati di supporto (indice). Ci servono N matrici (matrixC), una per ogni versione del kernel da testare. Inizialmente (e forse definitivamente) supportera' i kernel 2.2 e 2.4 Ovviamente queste saranno serializzate su disco (trattati come file binari). Ci saranno dei metodi che lavorano su queste strutture:

Ci sara' anche una matrice (per ogni ver del kernel) (matrixR) per tenere traccia dei chunk richiesti ed un metodo per lavorarci:

Quando tutti i pacchetti sono stati prenotati, si rifa' la matrice matrixR copiando matrixC. Ci saranno poi N file (sempre uno per ogni ver del kernel) (matrixI) con i pacchetti "interessanti". Ci sara' un metodo per lavorare su questi file:

Protocollo tra Executor e Packet Server.

I comandi che il Packet Server puo' ricevere sono formati da tre parti: Azione (gime, take, done) - pacchetto - Ver (kernel) L'azione e' lunga 4 byte, il pacchetto e' lungo 15 byte, e ver e' un byte. I 48 bit del pacchetto vengono codificati con i valori decimali ascii e quindi per rappresentare 2^48 valori ci servono 15 cifre (byte). Il valore del chunk e' codificato con 5 char (arriva fino a 99999). Per richiedere dei pacchetti da controllare (un chunk):

Per passare al Packet Server un pacchetto interessante:

Per dire al packet server che ha finito di controllare dei pacchetti:

L'executor.

L'executor si appoggia a tre file: go.in, go.out e go.check. go.in contiene il numero del chunk da controllare (stringa di 5 char). go.out contiene i pacchetti interessanti (stringhe di 15 char). go.check contiene l'ultimo blocco controllato (in caso di break del programma) (stringhe di 8 char). Il chunk ha 10^10 pacchetti. Questo si puo' dividere in 10^8 blocchi da 100 pacchetti l'uno. L'executor prova i 100 pacchetti di ogni blocco e poi pinga l'host (target) per vedere se e' crashato. In caso positivo, continua a pingarlo (ogni 60 secondi) finche' non torna su. Inoltre salva il numero del blocco nel file go.check. Quando l'host target e' tornato su, si riprovano tutti i pacchetti di quel blocco pingando dopo ogni pacchetto finche' non si trova quello che lo fa crashare.
Si appende quel pacchetto in un file (go.out) e si continua a provare gli altri pacchetti finche' non finisce il blocco. Finito il blocco, si ricomincia col ping solo alla fine del blocco. Quando sono finiti tutti i pacchetti, il programma esce, e con "nomeprogramma" --update (dopo essersi connessi ad internet) si flushano i buffer (go.out e go.in) e si riempiono quelli di input (go.in). (si cancellano inoltre i file go.check e go.out). I gestori per il SIGINT (ctrl-c o kill -9), il SIGTERM e il SIGQUIT salveranno in go.check il valore delll'ultimo blocco controllato e termineranno il programma.

 

powered by [Shine; Jaromil]

[Torna all'inizio della pagina]