Knockd: la sicurezza bussa alle porte

Per chi gestisce un server e ha la necessità che questo sia raggiungibile per il management anche da rete pubblica, un grosso problema è sicuramente la possibilità di essere vittima di attacchi bruteforce, che per quanto siano innocui quando si usano password molto complesse, impegnano banda e risorse. I firewall perimetrali e la macchina stessa, infatti, sono costretti a gestire migliaia di richieste occupando molto spazio nei log e moltissimo tempo per chi poi questi log li deve analizzare.

Non in tutti casi, infatti, è possibile configurare un servizio VPN evitando a priori la pubblicazione del servizio RDP su Windows o SSH su Linux.

Una buona norma è sicuramente quella di modificare la porta di ascolto sull’indirizzo pubblico; in questo modo si evita di essere individuati da tutti gli scan massivi effettuati su un particolare servizio, ma nel caso siamo vittima di un attacco mirato, un eventuale malintenzionato impiegherebbe in ogni caso pochissimi minuti per rilevare comunque il servizio.

Nel caso di un sistema Linux ci viene in aiuto un servizio conosciuto come “Port Knocking”, che interagisce con il firewall di sistema applicando delle regole temporizzate nel momento in cui ne abbiamo bisogno.

Il principio è talmente semplice da far sorridere; immaginiamo di imporre una policy che obblighi a tenere chiuso “dall’interno” tramite firewall l’accesso al servizio ssh, cosa potremmo fare per richiamare l’attenzione del sistema e chiedere di aprirci la porta solo quando necessario? Facilissimo, bussiamo!

Il servizio knockd si occupa proprio di questo, rimane in ascolto su alcune porte scelte da noi (non esistono in realtà delle porte di default) aspettando l’arrivo di una serie di pacchetti TCP o UDP inviati in un preciso ordine. Una volta ricevuti i pacchetti in un ordine preciso e con il protocollo da noi definito vengono attivate delle regole di firewall per un tempo predefinito. L’invio di questi pacchetti avviene da remoto attraverso un semplice client.

Guardiamo subito tutto da vicino, perché questo è il tipico caso in cui la pratica è più semplice della teoria, ed iniziamo con installare il servizio sulla nostra macchina Linux remota; per questo esempio stiamo utilizzando CentOS 6, ma il servizio è utilizzabile su tutte le maggiori distribuzioni e versioni.

Utilizziamo quindi yum, ed avviamo l’installazione di libpcap, prerequisito per knock service con:

yum install libpcap*

Per installare il servizio, invece, scarichiamo il pacchetto relativo alla distribuzione in uso, nel mio caso eseguo i comandi:

wget http://li.nux.ro/download/nux/misc/el6/i386/knock-server-0.5-7.el6.nux.i686.rpm

rpm -ivh knock-server-0.5-7.el6.nux.i686.rpm

Gli utilizzatori di Debian e Ubuntu troveranno il pacchetto direttamente nei repository predefiniti quindi per loro sarà sufficiente un semplice:

apt-get install knockd


A questo punto, assumiamo che il servizio ssh giri sulla porta di default 22, e creiamo una regola di firewall per ignorare tutte le richieste in arrivo su questa porta. Per questa funzione utilizziamo iptables, il firewall di sistema di linux, per l’utilizzo del quale rimando i meno esperti ad analizzarne almeno le funzionalità di base su questa pagina http://www.html.it/pag/18678/iptables-configurare-il-firewall/

Per bloccare i tentativi di connessione sulla porta 22 eseguiamo (da console):

iptables -A INPUT -p tcp --dport 22 -j DROP

service iptables save

Facciamo ovviamente attenzione a non eseguire il commando all’interno una sessione SSH perchè non solo perderemo la connessione in corso ma non riusciremo più ad accedere alla macchina remota.

Apriamo una piccola parentesi sull’uso dell’azione DROP che abbiamo utilizzato nel comando precendente. Possiamo imporre ad iptables di ignorare le connessioni (DROP) oppure bloccarle (REJECT), la differenza risulterà nella risposta che desideriamo dare al client. Nel caso del drop la connessione non riceve alcuna risposta e viene letteralmente lasciata cadere; il client quindi restituisce un errore di timeout; impostando reject, invece, la connessione viene esplicitamente rifiutata e ne risulterà un connection refused. Personalmente preferisco il DROP perché in questo modo la connessione alla nostra macchina avrà lo stesso comportamento di un tentativo di connessione su un ip non utilizzato.

La sintassi del comando iptables non cambia da distribuzione a distribuzione, ma ogni installazione potrebbe avere dei tool aggiuntivi per la configurazione.

Verifichiamo infatti che dal nostro client Windows 10, utilizzando la bash messa a disposizione da Windows Subsystem for Linux non riusciamo più ad accedere alla macchina remota.

A questo punto proviamo sul nostro server a configurare il servizio knockd, modificando il file /etc/knockd.conf

[options]

logfile = /var/log/knockd.log

[opencloseSSH]

sequence = 5000: tcp,5001:tcp,5010: tcp
seq_timeout = 15
tcpflags = syn
start_command = /sbin/iptables -A INPUT -s %IP% -p tcp –dport ssh -j ACCEPT
cmd_timeout = 10
stop_command = /sbin/iptables -D INPUT -s %IP% -p tcp –dport ssh -j ACCEPT

Ci accertiamo quindi che eventuali firewall perimetrali forwardino le porte sulla nostra macchina con il protocollo corretto.

Stiamo quindi configurando il servizio per salvare i log nel file /var/log/knockd.log, e definiamo il comando opencloseSSH che eseguirà questa sequenza di operazioni:

Nel caso in cui qualcuno “bussi” sulla porta udp 5000, poi tcp 5001 e successivamente udp 5010 (senza che trascorrano 15 secondi tra la prima porta e l’ultima) verrà eseguito il comando start_command che “aprirà” la porta 22 eseguendo un’azione ACCEPT dall’ip che sta “bussando”, e la richiuderà dopo 10 secondi eliminando la regola. In questo arco di tempo sarà possibile connettersi al server tramite un client ssh.

Per utilizzare questa configurazione è necessario che il firewall sul server sia configurato per accettare le connessioni “established” e “related”, perché consente di mantenere la connessione aperta anche dopo aver chiuso la porta.

In alternativa possiamo creare due comandi separati chiamandoli ad esempio openSSH e closeSSH che si attivino bussando a due serie differenti di porte, in quel caso il nostro file di conf avrà questa forma:

[options]

logfile = /var/log/knockd.log

[openSSH]

sequence = 5000, 5001, 5010
seq_timeout = 30
tcpflags = syn
command = /sbin/iptables -A INPUT -s %IP% -p tcp –dport ssh -j ACCEPT

[closeSSH]

sequence = 6000, 6001, 6010
seq_timeout = 30
tcpflags = syn
command = /sbin/iptables -D INPUT -s %IP% -p tcp –dport ssh -j ACCEPT

Avviamo quindi il servizio con:

service knockd start

se vogliamo che il servizio si avvii con la macchina eseguiamo:

chkconfig knockd on

A questo punto vediamo come interagire dal nostro client con la macchina remota.

Per “bussare” possiamo utilizzare nmap, netcat (nc) o più semplicemente il client di knockd, che dovremo però installare perché non presente di default sulle maggiori distribuzioni. Nel nostro caso utilizziamo Windows Subsystem for Linux, quindi la distribuzione Ubuntu inclusa in Windows 10, quindi installiamo il pacchetto knockd con

apt-get install knockd

Ora possiamo inviare il nostro knock al server remoto con il comando knock, la cui sintassi è

knock ip porta1:proto porta2:proto porta3:proto

il protocollo predefinito è tcp, quindi nel nostro caso eseguiamo:

knock test.remotelinux.com 5000 5001 5010

Con l’opzione -v il client ci mostra la sequenza dei pacchetti in console:

La macchina remota eseguirà lo script di configurazione del firewall indicato nel file di configurazione e sarà possibile connetterci in ssh dal nostro client:

Automaticamente dopo 10 secondi l’accesso sarà nuovamente bloccato.

Esiste anche un client knock per Windows (http://www.zeroflux.org/knock/files/knock.exe) e per OSX (http://www.zeroflux.org/cgi-bin/cvstrac.cgi/knock/wiki)

E’ molto interessante notare che il servizio knockd ascolta a livello link-layer quindi rimane in attesa di pacchetti senza aprire le relative porte. Questa caratteristica permette al servizio di rimanere invisibile a portscan dall’esterno ed è quindi praticamente impossibile individuarlo.

Non sarà certo la soluzione definitiva per la sicurezza mondiale, ma considerando il tempo necessario per la configurazione rispetto al vantaggio che offre questo servizio, consiglio vivamente di provare ad utilizzarlo dove necessario.