Riconoscimento delle sequenze di knock
Le sequenze di knock inviate dal richiedente con l'apposito client, vengono riconosciute lato server tramite analisi real-time del traffico diretto al dispositivo di rete monitorato. Tale analisi viene effettuata ricorrendo alla libreria per la cattura dei pacchetti LibPcap, descritta nella sezione 3.4 .
Ogni pacchetto della sequenza catturato viene processato, effettuando le operazioni inverse a quelle svolte dal client ovvero “demappare “ e decrittare i numeri di porta di destinazione :
PORT_ENCRYPTED = demap(DESTINATION_PORT)
clear_port = decrypt(PORT_ENCRYPTED)
Catturato un pacchetto, si controlla la sua porta di destinazione (naturalmente solo nel caso di pacchetti TCP od UDP, non per quelli di tipo ICMP), leggendola dall'header del pacchetto stesso.
Se tale valore rientra nei range di porte monitorate da servknock, si procede nella fase di riconoscimento, altrimenti il pacchetto viene ignorato. Quindi, controllando che il numero di porta di destinazione sia compreso o meno in alcuno degli intervalli previsti, il portknocking server ha la possibilita' di distinguere i cosiddetti smoke packets, e di conseguenza ignorarli.
Come per il client, anche lato server, infatti, vengono definiti nel file di configurazione uno o piu' range di porte, per un totale di 256 elementi, che devono essere monitorate da servknock. Naturalmente perche' le sequenze possano essere riconosciute correttamente, gli intervalli definiti nei files di configurazione di client e server devono corrispondere.
Se la porta di destinazione del pacchetto catturato rientra nel range, tale valore viene “demappato”, ovvero trasformato tramite un'apposita funzione in un numero compreso tra 0 e 255, in modo da potere essere usato nella successiva operazione di decifratura.
Supponendo che gli intervalli monitorati siano 7000-7100 e 7500-7655 e la porta di destinazione di due pacchetti catturati 7055 e 7589, l'operazione di demappatura ritornerebbe rispettivamente i valori 55 e 189, come mostrato dallo schema successivo:
Una volta “demappato”, il valore ottenuto viene decifrato utilizzando l'algoritmo e la chiave simmetrica ricavata dalla password definita nel file di configurazione di servknock, e verificata la sua correttezza ai fini del riconoscimento della sequenza.
Se tale valore corrisponde con la porta di destinazione dell'elemento iniziale di una possibile sequenza di knock, allora viene allocata un'opportuna struttura dati (attempt_t) per tenere traccia del tentativo, ed inserita in una lista linkata che comprende tutti gli attempt allocati precedentemente ed in fase di riconoscimento, almeno uno per ogni indirizzo IP dei richiedenti.
Se anche i valori “demappati” e decifrati dalla porta di destinazione dei pacchetti successivi sono corretti si procede nel riconoscimento della sequenza, mentre in caso negativo la si invalida e si libera la memoria occupata dall'elemento attempt_t precedentemente allocato.
Perche' un attempt venga annullato e' sufficiente che la porta di destinazione di uno dei pacchetti non corrisponda al valore aspettato per la sequenza; non e' infatti necessario attendere che tutti i pacchetti inviati dal client del siano stati ricevuti ed analizzati per invalidare il tentativo di autenticazione in corso.
La fase di riconoscimento puo' essere divisa in due parti distinte: nella prima fase si verifica che i pacchetti catturati corrispondano ad almeno una delle sequenze definite nel file di configurazione di servknock, mentre nella seconda si controlla che la porta di destinazione degli ultimi quattro pacchetti validi sia uguale ai bit dell'indirizzo IP del richiedente.
E' opportuno ricordare che la sequenza di knock e' divisa idealmente in due parti: la prima costituita dai pacchetti della sequenza vera e propria definita nel file di configurazione, e la seconda da quattro pacchetti di tipo TCP oppure UDP, le cui porte di destinazione corrispondono ai singoli bytes dell'indirizzo IP del richiedente. Poiche' la porta di destinazione degli ultimi quattro pacchetti non e' statica, ma dipendente dall'indirizzo IP, nel file di configurazione di servknock viene definita esclusivamente la prima parte di una sequenza.
Includere l'indirizzo IP del richiedente nella sequenza di knock unito alla cifratura della stessa e' una caratteristica di importanza fondamentale ai fini della sicurezza del sistema, poiche' consente di rendere differenti le sequenze di knock inviate dai diversi richiedenti.
L'utilizzo della sola crittografia sarebbe stata una soluzione decisamente inadeguata. Per un attacker sarebbe stato sufficiente rilevare la sequenza crittata analizzando il traffico di rete diretto al portknocking server, e riprodurla per ottenere l'accesso al servizio protetto, anche senza conoscere la sequenza definita nei files di configurazione di servknock.
Includendo l'indirizzo IP, diventa invece inutile inviare una copia della sequenza, poiche' l'unico effetto ottenibile sarebbe quello di autenticare nuovamente il richiedente che l'aveva inviata in precedenza. Utilizzando questa soluzione, inoltre, la cifratura della sequenza presenta il vantaggio di impedire la semplice riproduzione dela sequenza di knock con un'indirizzo IP corretto da parte di un eventuale attacker, poiche' sarebbe comunque richiesta la conoscenza della password utilizzata per generare la chiave e della sequenza in chiaro definita nel file, oltre ad altri parametri di configurazione specifici, come i range di porte monitorati ed il vettore di inizializzazione.
L'idea di includere anche l'indirizzo IP del richiedente all'interno della sequenza di knock e l'utilizzo della crittografia per rendere il sistema piu' robusto ai replay attacks, e' stata ripresa da knockdaemon di Martin Krzywinski.
Si consideri ora, a scopo esemplificativo, la seguente serie di pacchetti inviata da un ipotetico richiedente, che voglia ottenere l'accesso al servizio ssh, per il quale e' stata definita la sequenza TCP:90, UDP:44, ICMP nel file di configurazione del server :
servknock controllando il numero di porta di destinazione e' in grado di discriminare i pacchetti della sequenza di knock (rappresentati con il carattere in grassetto) dagli smoke packets. Il primo pacchetto appartenente alla sequenza di knock e' quindi TCP:7055, che viene cosi' “demappato” e decifrato:
demap(7055) = 55
decrypt(55) = 90
Poiche' tra le sequenze definite nel file di configurazione esiste TCP:90, UDP:44, ICMP, il cui primo elemento e' appunto un pacchetto TCP diretto alla porta 90, viene allocata una struttura dati attempt_t, per memorizzare il nuovo tentativo di autenticazione.
A questo punto il riconoscimento procede eseguendo le stesse operazioni sul secondo pacchetto di knock ricevuto, ovvero UDP:7005 :
demap(7005) = 5
decrypt(5) = 44
La sequenza associata alla struttura attempt_t precedentemente allocata, prevede come secondo elemento un pacchetto UDP diretto alla porta 44, e quindi si aggiorna la struttura dati che ne tiene traccia, modificandone un campo che indica lo stadio raggiunto nel riconoscimento.
Come si puo' facilmente intuire, le stesse operazioni venrranno svolte per tutti i successivi pacchetti della sequenza catturati.
Nello specifico esempio, una volta analizzato il terzo pacchetto di knock il sistema ha rilevato la sequenza TCP:90, UDP:44, ICMP e quindi completata la prima fase del riconoscimento.
A questo punto deve essere verificato che la porta di destinazione dei successivi quattro pacchetti corrisponda ai bytes dell'indirizzo IP del richiedente. Nell'esempio riportato tale indirizzo era 151.6.139.46, quindi perche' il riconoscimento sia portato a termine correttamente, i risultati delle operazioni demap e decrypt sul numero di porta di destinazione estratto dagli ultimi quattro knock packet inviati dal richiedente (TCP:7089, TCP:7072, TCP:7588 e TCP:7595) dovranno essere rispettivamente 151, 6, 139 e 46.
Si ricorda che anche questa serie di operazioni viene svolta sui singoli pacchetti al momento della loro cattura, esattamente come per la prima fase del riconoscimento.
Infine, se anche i risultati delle operazioni di “demappatura” e decifratura sul numero di porta di destinazione ultimi quattro pacchetti corrispondono ai valori corretti (come nell'esempio riportato), la sequenza inviata dal richiedente e' stata riconosciuta correttamente, e quindi in risposta all'avvenuta autenticazione e' possibile passare all'esecuzione delle azioni previste.
Ad ogni sequenza sono infatti associate due liste di comandi distinti : start command list e stop command list. Esse rappresentano le azioni da eseguire al momento del riconoscimento della sequenza ed una volta trascorso un timeout specificato nel file di configurazione del programma.
Per l'esecuzione di questi comandi il processo di servknock compie un'operazione di fork, creando un processo figlio. Il padre ritornera' subito a svolgere le sue funzionalita', mentre il processo figlio eseguira' i comandi contenuti nella start command list. A questo punto puo' eventualmente restare in attesa per la durata del timeout specificato, ed al suo scadere eseguire i comandi definiti dalla stop command list.
Maggiori esempi e chiarimenti sull'esecuzione dei comandi saranno esposte mostrando alcune dimostrazioni di funzionamento del sistema nella sezione 4.7.