next   previous   contents

Struttura delle sequenze di knock

 Per potere comprendere al meglio strutture dati e dettagli implementativi del programma, che verranno esposti in seguito, e' necessario fornire prima alcune brevi spiegazioni sulla struttura delle sequenze e come vengono costruite.
 Una corretta sequenza di knock deve essere strutturata come nel seguente esempio, idealmente divisa in due parti :

port_1, port_2, ... , port_N, byteIP_1, byteIP_2, byteIP_3, byteIP_4

 port_1, port_2, port_n rappresentano i pacchetti della sequenza vera e propria definita nel file di configurazione del client.
 byteIP_1, byte_IP2, byteIP_3 e byteIP_4 sono invece pacchetti (di tipo TCP oppure UDP) il cui numero di porta di destinazione e' costitutito dall' n-esimo byte dell'indirizzo IP del richiedente. Quindi il pacchetto byteIP_1 avra' come porta di destinazione il primo byte dell'indirizzo IP, byteIP_2 il secondo e cosi' via.
 La porta di destinazione dei pacchetti della sequenza definita nel file di configurazione deve essere compreso tra 0 e 255, poiche' l'intervallo delle porte monitorate da servknock e' appunto composto da 256 elementi. Tali intervalli, specificati sia all'interno de file di configurazione del server che del client, ovviamente non devono utilizzare solo le prime 255 porte, ma possono comprendere qualsiasi range si desideri, purche' il numero totale degli elementi che li costituiscano sia esattamente 256. Negli esempi mostrati in queste pagine, gli intervalli saranno i successivi: 7000-7100 e 7500-7655.
 Si vuole porre l'attenzione su come la scelta di un range cosi' costituito non sia casuale: essa e' infatti giustificata dalla necessita' di sfruttare nelle operazioni di cifratura e decifratura delle sequenze la corrispondenza tra gli elementi di questi intervalli ed i corrispondenti del set ASCII.
 Per favorire la comprensione dei concetti appena esposti, si consideri l'ipotetica situazione ove nel file di configurazione del client sia prevista la sequenza TCP:90, UDP:44, ICMP e l'indirizzo IP del richiedente sia 151.6.139.46 . Gli elementi della sequenza di knock “in chiaro” saranno qundi i seguenti, ove gli ultimi quattro pacchetti potrebbero essere indifferentemente di tipo TCP od UDP :

TCP:90, UDP:44, ICMP, TCP:151, TCP:6, TCP:139, TCP:46

 Ovviamente questa sequenza non e' quella che sara' inviata al server. Utilizzare un meccanismo “in chiaro” sarebbe infatti una pessima scelta, poiche' esso risulterebbe particolarmente vulnerabile ai replay attack. Prima dell'invio vengono quindi eseguite due ulteriori operazioni: la cifratura e la mappatura degli elementi della sequenza stessa.
 Tale sequenza non viene qundi inviata al portkocking server, ma esclusivamente memorizzata, per essere utilizzata nelle successive operazioni, ricorrendo a due array presenti in una opportuna struttura dati, che rappresentano rispettivamente la porta di destinazione ed il protocollo dei pacchetti che la costitusicono.
 Ogni singolo elemento di questi array definisce quindi un pacchetto della sequenza, e la cifratura viene eseguita elemento per elemento, scandendo il primo vettore, ed impiegando un opportuno algoritmo a chiave simmetrica: attualmente servknock e' stato testato con blowfish, twofish, rijndael, serpent e xtea.
 Poiche' si utilizzano ad algoritmi di tipo simmetrico, di conseguenza si ha la necessità di una password condivisa tra client e server, utilizzata per la generazione della chiave simmetrica e definita nei rispettivi files di configurazione. Oltre a tale chiave viene condivisa anche una seconda stringa, utilizzata come vettore di inizializzazione. Tutte le operazioni legate alla crittografia, sono state implementate facendo ricorso alla libreria LibMcrypt, descritta nella sezione 3.4 .
 Crittato il numero di porta di destinazione di un pacchetto, tale valore viene “mappato” tramite un'apposita funzione all'interno dei range di porte controllati lato server da servknock, e definiti anche nel file di configurazione del client. Tale operazione consiste semplicemente nell'utilizzare il numero cifrato precedentemente come offset e trasformarlo in un valore compreso negli intervalli monitorati lato server.
 Supponendo che tali intervalli siano 7000-7100 e 7500-7655, i valori 55 e 189 nell'operazione di mappatura verrebbero trasformati in 7055 e 7589, come riportato dal seguente schema :

 A questo punto viene costruito il pacchetto di rete, utilizzando il valore “mappato” come porta di destinazione, ed inviato al portknocking server.
 La costruzione e l'invio della sequenza di knock avviene quindi pacchetto per pacchetto, partendo dalla sequenza in chiaro memorizzata nelle strutture dati del client, crittando e mappando i singoli valori da assegnare alla porta di destinazione :

crypt(clear_port) = PORT_ENCRYPTED
map(PORT_ENCRYPTED) = PORT_ENCRYPTED_MAPPED
send(PROTOCOL:PORT_ENCRYPTED_MAPPED)

 Partendo dal primo elemento della sequenza usata precedentemente come sempio, si svolgono quindi le seguenti operazioni :

crypt(90) = 55
map(55)= 7055
send(TCP:7055)

 Le stesse operazioni vengono in seguito ripetute per ogni singolo elemento della sequenza memorizzata, come schematizzato nell'immagine successiva, dove i numeri accanto alle frecce indicano l'ordine con cui esse sono eseguite :

 Prendendo spunto dall'idea dello “smoke screen generator” utilizzato da pasmal, si e' pensato, di implementare una feature del client, che consentisse di inviare una sequenza casuale di pacchetti UDP e TCP, detti smoke packets, prima e dopo ogni singolo elemento della sequenza di knock (knock packets). Scopo di tali pacchetti e' quello di confondere gli elementi della sequenza con altro traffico, per rendere piu' complicato il riconoscimento delle sequenze da parte di un eventuale attacker; da qui appunto la definizione di smoke packets.
 Il massimo numero di questi pacchetti e la probabilita' con la quale possono essere inseriti tra due elementi consecutivi della sequenza di knock dipendono dal valore alcune costanti definite nell'header file knock.h. E' infine possibile specificare anche i valori minimo e massimo che il numero di porta di destinazione puo' assumere in uno smoke packet.
 Una simile soluzione, ha purtroppo il difetto di generare una maggiore quantita' di traffico diretta verso il portknocking server, con conseguente aumento del tempo necessario per l'invio di una sequenza di knock. Tale scelta implemntativa e' comunque giustificata dalla maggiore difficolta' per eventuali attacker nel riconoscere i pacchetti che costituiscono le sequenze di knock.
 L'intera serie di pacchetti inviata dal richiedente dell'esempio precedebte, non sarebbe quindi quella rappresentata dallo schema, ma la successiva :

[UDP] 6924 Smoke packet
[TCP] 7055 Knock packet
[TCP] 13147 Smoke packet
[UDP] 2196 Smoke packet
[UDP] 7005 Knock packet
[UDP] 5986 Smoke packet
[ICMP] Knock packet
[UDP] 5660 Smoke packet
[TCP] 12071 Smoke packet
[UDP] 13048 Smoke packet
[TCP] 7089 Knock packet
[UDP] 5780 Smoke packet
[TCP] 11723 Smoke packet
[TCP] 11999 Smoke packet
[TCP] 7072 Knock packet
[UDP] 10272 Smoke packet
[UDP] 6816 Smoke packet
[TCP] 9633 Smoke packet
[TCP] 7588 Knock packet
[TCP] 5715 Smoke packet
[TCP] 7595 Knock packet
[UDP] 6124 Smoke packet

 Per la costruzione e l'invio dei pacchetti da parte del client e' stata utilizzata la libreria LibNet, descritta nella sezione 3.4 .

next   previous   contents