A proposito dell'autore

System Administrator, appassionato di sicurezza e networking, lavora come consulente esterno presso varie aziende nazionali; ha lavorato ultimamente su cluster HA di CentOS ed apparati di videosorveglianza ed al momento svolge consulenza presso aziende e studi privati, combinando l'attivita' lavorativa a quella di ricerca nel campo della sicurezza informatica ed hardening di sistemi e reti.

Introduzione

La sicurezza è sempre stato un tema scottante fin dall’inizio delle prime reti di computer ed è anche uno dei primi fattori ad essere calcolato nello sviluppo di qualsiasi soluzione software.

Con l’andare avanti del tempo e dello sviluppo tecnologico, l’accessibilita’ alla rete di (quasi) tutti ha portato il tema della sicurezza a livelli ancora maggiori poiche’ ad essere tutelata doveva essere una larga base di utenza mai vista prima. Si sono andati sviluppando parecchi layer di sicurezza, protocolli, algoritmi, tutti validi e robusti, ma, come si dice, non e’ mai abbastanza. Punteremo la nostra attenzione su uno di questi sistemi poco conosciuto ma che se ben implementato puo’ portare ad un livello di sicurezza ragguardevole senza troppi sforzi: questo sistema e’ il Port Knocking (“bussata di porta”).

Le caratteristiche peculiari di questo sistema lo mettono al primo posto come tecnica difficilmente individuabile da un attacker e allo stesso tempo relativamente semplice, a seconda dello scenario da proteggere; inoltre, il concetto di base e’ sviluppato e implementato in vari modi per meglio adattarsi al sistema da proteggere. Qui tratteremo l’implementazione teorica apparsa su Linux Journal il 16 Giugno 2003 ad opera di Martin Krzywinski e quella pratica del SIG^2 G-TECH Lab; per le altre implementazioni e documentazione completa basta visitare www.portknocking.org (i link li trovate alla fine nella Bibliografia).

Funzionamento

Facciamo una panoramica generale sul Port Knocking (PK da ora) per poi andare piu’ a fondo e carpirne i segreti, i vantaggi e i difetti.
Di fatto, il PK e’ un sistema di sicurezza molto dinamico, capace di adattarsi a vari sistemi operativi e aperto a diverse soluzioni. Tutto si basa su un sistema formato da un demone che interagisce con il firewall in modo da cambiare al volo le regole di accesso dalla rete alla macchina, come vedremo fra poco.
In generale abbiamo un server protetto da un firewall che, ad esempio, blocca gli accessi verso porta 22, e sul quale gira il PK daemon. Il demone controlla i log del firewall alla ricerca di una determinata “bussata” (knock), ovvero pacchetti inviati al server a porte diverse secondo un preciso ordine settato nel suo file di configurazione; controllata e verificata questa sequenza (knock start sequence), il demone cambia al volo le regole del firewall e permette l’accesso all’user che ha eseguito la knock sequence per un tot di tempo e/o solo per quel determinato IP (a seconda delle esigenze dell’admin). Finito il lavoro dell’user remoto, con una sequenza di chiusura (knock end sequence), l’utente dice al demone di richiudere la porta 22 e rimettersi in ascolto per un’altra knock start sequence.

Con questo metodo abbiamo utilizzato un servizio invisibile per gestire da remoto il nostro server senza esporlo troppo al rischio di un attacco bruteforce o qualsivoglia attacco diretto alla porta 22. Abbiamo oscurato un servizio di cui solo noi siamo a conoscenza poiche’ la presenza del demone non invia nessun pacchetto o notifica via rete o al client ma analizza solo i file di log del firewall ed interviene per modificarne le regole.

Interroghiamoci su questi knock: che tipo di pacchetti sono? Nelle implementazioni standard sono pacchetti TCP/SYN, che non stabiliscono una vera e propria connessione ma controllano solo se una porta e’ aperta o meno; questi pacchetti vengono comunque intercettati dal firewall che li logga e quindi rende a pieno il lavoro del demone; inoltre, si confondono facilmente nella rete e possono passare inosservati agli occhi di un attaccker…alle prime armi.
Tutti gli sniffer catturano i pacchetti TCP/SYN e, notando un eccessivo traffico verso un determinato host diretto ad una porta chiusa e, conseguentemente, un traffico diretto alla suddetta porta, puo’ far nascere dei sospetti sul tipo di sistema di sicurezza adottato dal server. A questo punto basta solo mettersi in ascolto, pazientare, riflettere.

Martin Krzywinski nell’articolo su Linux Journal descrive una knock start sequence dinamica, ovvero mai fissa e quindi difficilmente riproducibile. L’esempio che fa e’ molto semplice.

Consideriamo la seguente sequenza di knock:

102,100,110  10a,10b,10c,10d  10(a+b+c+d mod 10)        110,100,102
header          payload             checksum                                 footer

L’header ed il footer identificano rispettivamente l’inizio e la fine della sessione, ovvero le porte da bussare per aprire e chiudere la porta; da bussare le porte sono esattamente la 102,100 e 103, per la chiusura l’inverso. Il playload e’ un parte della sequenza in grado di chiedere l’apertura della porta scelta in modo piu’ o meno sicura poiche’ ad a,b,c e d vanno sostituiti i valori della porta suddetta e cioe’ (sempre nell’esempio di Krzywinski): se la porta da aprire e’ la 143 allora avremo a=0, b=1, c=4, d=3 che andranno a creare anche il checksum per verificarne la vericidita’ ottenendo come valore 8 poiche’ 10(0+1+4+3 mod 10) = 10(8) = 108. La sequenza per questo esempio sara’ dunque:

102,100,103  100,101,104,103          108                 103,100,102
 header           playload                 checksum                 footer

Cosi’ facendo si apre la porta 143 per accettare connessioni in ingresso dall’user che esegue la knock sequence.

Sempre nello stesso articolo, l’autore ci consiglia di usare una qualche chiave crittografica per aggiungere altra sicurezza e pubblica due listati in Perl che sono il Knockclient ed il Knockdaemon. Per scaricarli e usarli vi rimando al link nella Bibliografia.

Implementazione

Sul sito www.portknocking.org e’ possibile vedere tutte le varie implementazioni fin ora riuscite, tra le quali segnaliamo il PK over Cerberus, COK e il barricade, le piu’ usate in questo settore.
Come in queste implementazioni, e come in altre, la semplicita’ del concetto e la flessibilita’, unita alla vasta varieta’ di scenari esistenti, ha dato vita a soluzioni originali, piu’ o meno sicure, ma tutte interessanti e degne di studio.
Per esempio, tramite Cerberus i pacchetti vengono inviati tramite ICMP, quindi connectionless e senza garanzia di riuscita, tuttavia molto sicuro poiche’ difficilmente intercettabile e mascherabile in un semplice ping.

Ovviamente, le porte usate dal demone per identificare la sessione di start devono essere usate solo per lui e quindi non utilizzate da nessun altro servizio; inoltre, un demone che modifichi le rules di un firewall va usato con cautela poiche’ puo’ rivelarsi un’arma a doppio taglio, prestando il fianco a vari flaw di sicurezza. Inoltre, come gia’ detto precedentemente, il PK non e’ esente da sniffing, tutto sta’ all’abilita’ dell’attacker di individuare questo sistema ma solo a patto che riesca a sniffare la rete nel momento di una sequenza di knock , altrimenti e’ impossibile determinare con sicurezza che il servizio sta girando ma resta tuttavia l’impossibilita’ di determinare le porte per la knock start sequence rendendo un bruteforce del tutto inutile e improduttivo.

Vediamo ora di implementare uno di questi sistemi tanto descritti qui sopra in un ambiente misto Microsoft Windows – GNU/Linux, e piu’ precisamente il progetto del SIG^2 G-TEC Lab che offre soluzioni gratuite e opensource per sistemi Windows e Unix.

Come riportato sul sito del progetto ), la loro implementazione segue i seguenti 7 passaggi:

  • Il client genera una sequenza di knock casuale, criptandola con l’hash della password dell’user e sendando il tutto al server in un singolo pacchetto UDP protetto in MD5 HMAC (http://it.wikipedia.org/wiki/HMAC). Questo pacchetto serve per dichiarare al server la sequenza di knock che verra’ poi effettuata nel terzo punto.
  • Il server riceve il pacchetto UDP, lo decripta, controlla la validita’ dell’hash e aspetta la sequenza di knock.
  • Il client esegue la sequenza di knock precedentemente dichiarata al server.
  • Sempre il client invia un altro pacchetto UDP criptato in MD5 HMAC al server per controllare lo stato del port knocking.
  • Il server, dopo aver ricevuto la giusta sequenza di knock, manda al client un pacchetto criptato con l’hash della password dell’utente contenente la porta assegnata.
  • Dopo aver ricevuto questo pacchetto, il client puo’ connettersi alla porta assegnata dal server.
  • Il server accetta SOLO connessioni provenienti dalla macchina che ha eseguito la sequenza di knock alla porta prestabilita. Prevede inoltre a forwardare la richiesta alla porta specifica richiesta dall’user.

Detto cio’, passiamo all’implementazione pratica tramite il client ed il server messi a disposizione dal team del SIG^2 Lab.

Da Windows a Windows

Prima di tutto scarichiamo sia il server che il client al seguente indirizzo selezionando ovviamente il download per piattaforma Win32. Si scaricheranno due archivi .zip uno contenente il server (sig2knockd.zip) e l’altro il client (sig2knockc.zip). Unzippando l’archivio del server si creeranno due sottocartelle, sig2knockd e sig2knockd_useradd che serviranno per far partire il sistema. La prima cosa da fare e’ creare un user da autenticare per avere accesso al server. Per fare cio’, e’ disponibile l’eseguibile sig2knockd_useradd.exe nella cartella “Release” dove sono presenti tutti i sorgenti compilati. Aprendo una shell, posizioniamoci nella cartella e digitiamo sig2knockd_useradd.exe ed avremo:

C:Program Filessig2knocksig2knockdRelease>sig2knockd_useradd.exe
SIG^2 KnockC Version 0.1 Copyright (c) 2004 SIG^2 (www.security.org.s
Win32 Coding by Chew Keong TAN

New User Name: anathema
New Password:

Add the following line to the user account file.

anathema:UbGJ2/RBT/wiri1KMwA/Hg==:0

C:Program Filessig2knocksig2knockdRelease>

Ovviamente la password non e’ printata a schermo e la riga anathema:UbGJ2/RBT/wiri1KMwA/Hg==:0 rappresenta la riga da inserire nel file user.txt nella stessa cartella del server (e’ presente un user.sample da sostituire). La conf e’ del tipo userid:password hash:timestamp ed e’ importante tenere il file sicuro per evitare il crack dell’account.
Creato l’utente ed inserita la riga in user.txt, bisogna modificare il file sig2knockd.conf che si presenta cosi’:

# Configuration file for sig2knockd

UDP_PORT			= 1001	  
FORWARD_TO_IP		= 127.0.0.1
FORWARD_TO_PORT		= 22
SINGLECONN_PORTOPEN_TIME	= 30

# leave this blank if you do not have pktfilter installed
# make sure you have setup the default rules for pktfilter correctly
PKTFILTER_INTERFACE	=

L’UDP_PORT segna la porta su cui mettersi in ascolto per le sequenze di knock nascoste garantendo un primo layer di sicurezza; il FORWARD_TO_IP specifica l’IP al quale forwardare l’accesso avvenuto e il FORWARD_TO_PORT indica la porta alla quale indirizzare l’user con accesso autorizzato. Il SINGLECONN_PORTOPEN_TIME garantisce il tempo in secondi in cui una porta dedicata dal portknocking server resta accessibile senza accessi.
A questo punto, facciamo partire il server:

C:Program Filessig2knocksig2knockdRelease>sig2knockd.exe -i 2
SIG^2 KnockD Version 0.2 Copyright (c) 2004 SIG^2 (www.security.org.sg)
Win32 Coding by Chew Keong TAN

IP Address = 192.168.1.2

UDP_PORT                  = 1001
FORWARD_TO_IP         = 127.0.0.1
FORWARD_TO_PORT    = 22
SINGLECONN_PORTOPEN_TIME  = 30
PKTFILTER_INTERFACE       =

Opening DeviceNPF_{05428055-6B76-4147-9323-8682B25045D6}

2006-06-02 18:19.03 Server started.

Ora il server e’ in ascolto per una giusta sequenza di knock. Passiamo ora al client, sig2knockc. Per iniziare la sequenza basta fare

sig2knockc.exe <server IP> <server Port>

quindi:

C:Program Filessig2knocksig2knockcRelease>sig2knockc.exe 192.168.1.2 1001
SIG^2 KnockC Version 0.2 Copyright (c) 2004 SIG^2 (www.security.org.sg)
Win32 Coding by Chew Keong TAN

User Name: anathema
Password:

Sending knock sequences with source address 192.168.1.2
Using timestamp value 1147901486

Knock? (1 - Port = 18553, ISN = 14A577B1)
Knock? (2 - Port = 60152, ISN = F4CF9EBD)
Knock? (3 - Port =  9031, ISN = 24FD0F70)

Can I come in?  Waiting for response.

Door is open at 192.168.1.2 Port 1965 for 30 seconds.
30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, ...

Il client ha mandato la richiesta al server ed, accettata l’autenticazione, ha avuto la porta 1965 aperta per 30 secondi per eseguire il login alla porta 22 o una qualsiasi porta specificata nel file di conf del server.

Lato server abbiamo il seguente output:

2006-06-02 18:19.03 Server started.
2006-06-02 18:19.54 Port request received from anathema. (192.168.1.3, 192.168.1
.3)
2006-06-02 18:19.58 Correct knock sequence received from anathema (192.168.1.3,
192.168.1.3).
2006-06-02 18:19.59 Binded port 1965 for anathema. (192.168.1.3, 192.168.1.3)

Questo nel caso di una autenticazione andata a buon fine. Nel caso l’autenticazione fallisse abbiamo il seguente responso lato client:

Can I come in?  Waiting for response.
Sorry, the door is still closed.

Da Windows a Linux (e viceversa)

Ora vedremo come connettersi da un client su OS Microsoft Windows ad un server Linux, precisamente su Debian GNU/Linux.

Sempre sul sito del SIG^2 Lab possiamo scaricare il server per sistemi Linux. Si tratta di un archivio .tar.gz. Dopo averlo wgettato e untarrato (per chi se lo fosse dimenticato tar xzvf sig2knockd-0.2.1.tar.gz), procediamo con la configurazione del server.

Nel file README.linux c’e’ scritto piu’ o meno tutto, ciononostante vi mostrero’ i miei passaggi per mettere su’ il demone.

Dopo aver untarrato il pacchetto, viene creata la cartella sig2knockd, entriamo e compiliamo il tutto:

pk:~# cd sig2knockd-0.2.1/
pk:~/sig2knockd-0.2.1# make all
g++ -O   -c -o sig2knockd.o sig2knockd.cpp
g++ -O   -c -o serverProcessPkt.o serverProcessPkt.cpp
g++ -O   -c -o portForward.o portForward.cpp
g++ -O   -c -o portSeqReqList.o portSeqReqList.cpp
g++ -O   -c -o serverConfig.o serverConfig.cpp
g++ -O   -c -o serverLog.o serverLog.cpp
g++ -O   -c -o base64.o base64.cpp
g++ -O   -c -o userRecord.o userRecord.cpp
g++ -O   -c -o aesCBC.o aesCBC.cpp
cc -O   -c -o aescrypt.o aescrypt.c
cc -O   -c -o aeskey.o aeskey.c
cc -O   -c -o aestab.o aestab.c
cc -O   -c -o md5.o md5.c
g++ -O   -c -o randomGen.o randomGen.cpp
g++ -O   -c -o firewallSupport.o firewallSupport.cpp
g++ -O   -c -o privProcSupport.o privProcSupport.cpp
g++ -lpcap -lpthread -O -o sig2knockd sig2knockd.o serverProcessPkt.o portForward.o portSeqReqList.o serverConfig.o 
serverLog.o base64.o userRecord.o aesCBC.o aescrypt.o aeskey.o aestab.o md5.o randomGen.o firewallSupport.o privProcSupport.o
g++ -O   -c -o sig2knockd_useradd.o sig2knockd_useradd.cpp
g++ -o sig2knockd_useradd sig2knockd_useradd.o base64.o md5.o
pk:~/sig2knockd-0.2.1#

Ora abbiamo i due eseguibili sig2knockd e sig2knockd_useradd. Fatto cio’, creiamo una cartella dove poter tenere tutti i file sotto controllo, per una questione di ordine piu’ che altro.

pk:~/sig2knockd-0.2.1# mkdir bin
pk:~/sig2knockd-0.2.1# mv user.sample sig2knockd.conf sig2knockd sig2knockd_useradd bin/
pk:~/sig2knockd-0.2.1# cd bin/
pk:~/sig2knockd-0.2.1/bin#

Come per Windows, andiamo a creare l’user e inseriamo la riga nel file user.sample rinominandolo poi in user.txt. Per il file di conf (sig2knockd.conf) va benissimo la configurazione adottata per il sistema Windows.
A questo punto conviene settare i permessi per i file di conf e per il file contenente la lista degli user; conviene renderlo leggibile e scrivibile SOLO dall’utente root, indi per cui:

pk:~/sig2knockd-0.2.1/bin# chown root.root user.txt (opzionale)
pk:~/sig2knockd-0.2.1/bin# chmod g= user.txt
pk:~/sig2knockd-0.2.1/bin# chmod o= user.txt
pk:~/sig2knockd-0.2.1/bin# chmod u=rw user.txt

pk:~/sig2knockd-0.2.1/bin# chown root.root sig2knockd.conf(opzionale)
pk:~/sig2knockd-0.2.1/bin# chmod g= sig2knockd.conf
pk:~/sig2knockd-0.2.1/bin# chmod o= sig2knockd.conf
pk:~/sig2knockd-0.2.1/bin# chmod u=rw sig2knockd.conf

pk:~/sig2knockd-0.2.1/bin# ls -al
total 132
drwxr-xr-x  2 root root   4096 2006-06-04 18:47 .
drwxr-xr-x  4 root root   4096 2006-06-04 20:06 ..
-rwxr-xr-x  1 root root  91497 2006-06-04 18:46 sig2knockd
-rw-------   1 root root     393 2004-05-02 09:46 sig2knockd.conf
-rwxr-xr-x  1 root root  16958 2006-06-04 18:46 sig2knockd_useradd
-rw-------   1 root root      467 2006-06-04 18:47 user.txt
pk:~/sig2knockd-0.2.1/bin#

Cosi’ facendo un qualsiasi user non potra’ ne vedere ne modificare i due file di conf del sistema di port knocking.

Prima di far partire il tutto dobbiamo impostare e giocare un po’ con iptables. A seconda delle esigenze si possono avere varie configurazioni, noi tratteremo quella di base che e’ menzionata nel file README.linux:

pk:~# iptables -P INPUT DROP
pk:~# iptables -P OUTPUT DROP
pk:~# iptables -P FORWARD DROP

Cosi’ impostiamo la policy di default su DROP, ovvero sullo scarto di tutti i pacchetti.

pk:~# iptables -A OUTPUT -p udp -j ACCEPT

Con questa rule abbiamo consentito al demone del PK di sendare al di fuori del PC le richieste di reply.
Ora possiamo far partire il nostro servizio.
Contrariamente a Windows, possiamo scegliere di far girare il servizio come demone (in Windows e’ detto “servizio”) e di lasciar loggare a syslog entrando in silent mode o di lasciar partire solo in funzione demone o, come in Windows, far partire il server solo come programma standalone. Vedremo i primi due casi.

pk:~/sig2knockd-0.2.1/bin# ./sig2knockd
SIG^2 KnockD Version 0.2.1 Copyright (c) 2004 SIG^2 (www.security.org.sg)
Linux Coding by Chew Keong TAN

lo       - 127.0.0.1
eth0   - 192.168.1.2

Usage: ./sig2knockd -i <interface>
            ./sig2knockd -i <interface> -D    (to run as daemon)
            ./sig2knockd -i <interface> -D -S (to run as daemon and use syslog)

If syslog is not used, program logs to /var/log/sig2knockd.log when running as daemon.

Per far partire il server come demone e’ necessario aggiungere un user sig2kd al sistema poiche’ tutto il codice gira con la separazione dei privilegi e quindi tutto gira come user sig2kd. Per fare cio’ basta aggiungere una riga come la seguente nel vostro /etc/passwd:

sig2kd:x:31337:31337::/home/sig2kd:/bin/false

dove /home/sig2kd/ e’ una cartella vuota creata apposta per il demone come ambiente chroot.
Fatto cio’ possiamo far partire il demone:

pk:~/sig2knockd-0.2.1/bin#./sig2knockd -i eth0 -D
SIG^2 KnockD Version 0.2.1 Copyright (c) 2004 SIG^2 (www.security.org.sg)
Linux Coding by Chew Keong TAN

UDP_PORT                  = 1001
FORWARD_TO_IP             = 127.0.0.1
FORWARD_TO_PORT           = 22
SINGLECONN_PORTOPEN_TIME  = 30
PKTFILTER_INTERFACE       =

Opening eth0 (192.168.1.2)
Server started as daemon.

pk:~/sig2knockd-0.2.1/bin#ps aux | grep sig2knockd | grep -v grep

root      4757  0.0  0.1   3324   696 ?        Ss   13:08   0:00 ./sig2knockd -i eth0 -D
sig2kd    4758  0.0  0.1   3324   528 ?        S    13:08   0:00 ./sig2knockd -i eth0 -D

pk:/home/anathema/sig2knockd-0.2.1/bin#

Il log dei knocks si trova in /var/log/sig2knockd.log ed e’ lo stesso output senza l’opzione -D.

Con l’opzione -D -S utilizzeremo il syslog come monitor di rete. L’unica cosa da notare e’ che invece di cattare /var/log/sig2knockd.log basta cattare /var/log/syslog in modo da vedere gli ultimi eventi registrati da syslog.

Da Linux a Linux

L’implementazione del PK visto fin ora e’ applicabile anche a due sistemi GNU/Linux senza cambiamenti, visto che la parte piu’ “complessa”, quella del server, e’ stata spiegata nel paragrafo precedente. L’utilizzo del client su Linux e’ uguale a quello su Windows quindi non descrivero’ in questa sezione il funzionamento, basta infatti controllare la sezione sopra citata. Ho comunque voluto inserire un paragrafo con questo titolo per puntualizzare come sia possibile con lo stesso sistema comunicare tramite due pc Linux. La completezza, inoltre, e’ stata un altro motivo che mi ha spinto a scrivere questo mini-paragrafo.

Conclusioni

Arriviamo alle conclusioni facendo una panoramica generale dell’articolo. Abbiamo visto in cosa consiste il PortKnocking, come funziona, le varie implementazioni e, in particolare, quella del SIG^2 G-TEC Lab che a mio avviso e’ la piu’ flessibile e completa attualmente reperibile in rete. Tuttavia, la flessibilita’ del PortKnocking lascia aperte tantissime strade tutte da percorrere, l’unico limite e’ la vostra flessibilita’ mentale conbinata con la tipologia di rete a disposizione, ma questa seconda variabile puo’ essere anche irrilevante. La teoria generale e’ stata trattata (spero in modo soddifacente) e quindi ora tocca alle vostre capacita’ mettere su’ un sistema efficace. Come detto piu’ volte, infine, la sicurezza e’ sempre relativa; ogni sistema mostra il fianco a vulnerabilita’ e l’abilita’ di un sysadmin e’ quella di evitarne il piu’ possibili cercando di mixare flessibilita’ e rigidita’.
Bibliografia:
http://www.linuxjournal.com/article/6811 – Articolo di Krzywinski su Linux Journal.

http://www.portknocking.org – Sito di riferimento per il portknocking.

http://www.portknocking.org/view/implementations – Implementazioni PK.

http://www.areanetworking.it/wp-content/uploads/2011/05/yapki.tar.gz – Progetto in fase di sviluppo di portknocking in bash scriptato da me con tanto di file password in md5.

– Port Knocking Project by SIG^2 G-TEC Lab molto interessante.

Post correlati

Close
Entra in contatto con altri professionisti ICT, seguici su Facebook e Twitter: