Port Knocking : cacher son port SSH

knock 5 mars 2016

On est d’accord que la meilleure sécurité, si on doit laisser un port SSH d’ouvert, n’est ni de le changer ni de le masquer mais tout simplement d’utiliser une clé.

Car le changer ne fait que se prémunir contre pas mal de scripts/scanners qui par défaut ciblent le port 22. Le cacher, ce qu’on va voir ici, ne protège pas contre l’analyse du trafic de la machine (qui fera ressortir les commandes d’accès au “vrai” port SSH). Mais c’est mieux que rien et permet de se prémunir des brute forces basiques à partir de scripts.

Le port knocking consiste donc à masquer son port SSH et à y accéder par un enchainement de requêtes sur des ports précis (par exemple 1000 puis 124 puis 312 et enfin on tombe sur le port SSH). C’est le même principe que dans les vieux films d’espionnage avec une séquence particulière lorsqu’on frappe sur une porte, pour que l’autre comprenne le message et nous ouvre :)

Bref. C’est pas une révolution, c’est pas magique, mais plutôt simple à mettre en place et relativement efficace et ça se nomme Knock.

Précisons que cette méthode nécessite d’avoir de quoi faire ces commandes successives lors de la connexion SSH depuis le client vers le serveur. Je ne sais pas faire sous Windows aussi ce tutoriel ne concerne que les personnes sous Linux (et OSX je suppose). Le tutoriel est effectué sur un serveur Debian et un client Archlinux.

EDIT : bonne nouvelle pour les Windowsiens :)

 

Configuration du serveur

Knock va être chargé d’ouvrir les ports. Il convient donc de les fermer via IPtables. Cette manipulation comporte un risque majeur : celui de vous retrouver à la porte de votre machine si vous n’autorisez pas déjà les connexions établies.

En effet, fermer tous les ports entrants via IPtables revient à fermer aussi le port SSH et donc votre accès actuel. Il faut donc commencer par autoriser les accès en cours avant de fermer les ports.

On va s’assurer que le serveur n’aura pas de souci à se parler à lui-même (services internes) :

sudo iptables -A INPUT -i lo -j ACCEPT

On autorise ensuite les connexions entrantes déjà établies (dont le SSH en cours) :

sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

ATTENTION, sans cette règle vous n’aurez plus accès à votre machine !!! (Sauf via un Rescue Mod où vous pourrez virer les règles IPtables)

On ajoute ensuite une règle par service entrant qui doit rester visible. Pas le SSH évidemment, puisque lui on veut le cacher, mais par exemple le serveur Web (ports 80 et/ou 443), le serveur FTP (port 21) etc.

La règle est la même pour tous, il faut juste changer le port (PORT) et éventuellement le protocole TCP par UDP, selon vos configurations (souvent pour OpenVPN par exemple) :

sudo iptables -A INPUT -p tcp --dport PORT -j ACCEPT

Exemple avec un serveur Web HTTP classique, donc port 80

sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT

Exemple pour SickRage qui tournerait sur le port 8081

sudo iptables -A INPUT -p tcp --dport 8081 -j ACCEPT

Exemple pour OpenVPN Server qui tournerait sur le port 913, en UDP

sudo iptables -A INPUT -p udp --dport 913 -j ACCEPT

Et pour terminer on ferme tous les ports (pour les connexions entrantes), sereinement, maintenant qu’on a sécurisé notre accès SSH en cours.

sudo iptables -A INPUT -j DROP

 Et pour sauvegarder ces règles, on peut le faire à la main ou :

sudo apt-get install iptables-persistent

 

 

Installation et configuration de knock

Knock, enfin son daemon knockd précisément, va se charger d’ouvrir et fermer les ports “intéressants” et le SSH selon votre configuration.

On installe donc knock

sudo apt-get install knockd

Et on le configure. Ce qui se fera via le fichier /etc/knockd.conf

sudo nano /etc/knockd.conf

Ce qui nous donne ce fichier, que nous allons remplir :

[options]
        UseSyslog

[openSSH]
        sequence    = 7000,8000,9000
        seq_timeout = 5
        command     = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
        tcpflags    = syn

[closeSSH]
        sequence    = 9000,8000,7000
        seq_timeout = 5
        command     = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
        tcpflags    = syn
  • sequence : l’ordre des ports à “frapper” avant d’arriver au port SSH
  • seq_timeout : durée d’ouverture des ports, qui sont ensuite refermés par knockd
  • commande : autorisation de l’accès au port SSH pour notre IP dans IPtables
  • tcpflags : SYN = demande de synchronisation ou établissement de connexion

Et bien entendu démarche effectuée une 1ère fois en entrée puis en sens inverse en sortie. Comme quand on ouvre et ferme une porte. Ainsi depuis la machine cliente vous devrez lancer la commande knock 2 fois : la 1ère pour ouvrir les accès et la seconde pour les fermer. Chronophage mais aussi un tantinet risqué si vous oubliez de les refermer.

Nous allons par conséquent modifier légèrement la configuration de knockd sur le serveur afin qu’il referme tout lui-même automatiquement.

[SSH]
sequence = 7000,8000,9000
seq_timeout = 5 tcpflags = syn
start_command = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
cmd_timeout = 5
stop_command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
  • start_command : autorisation de l’accès au port SSH pour notre IP dans IPtables
  • cmd_timeout : délai de fermeture des ports par knock
  • stop_command : annulation de l’autorisation de l’accès au port SSH pour notre IP dans IPtables

Pour l’exemple je vais utiliser le port SSH 2016 et les ports 1978, 2000 et 2015 pour y accéder. Je vous recommande de mettre un timeout un peu plus long que 5 secondes pour parer à d’éventuels souci de latence entre le serveur et vous. Disons que 20 secondes est plutôt sécurisant.

Mon fichier de configuration ressemble de fait à ceci :

[SSH]
sequence = 1978,2000,2015
seq_timeout = 20 tcpflags = syn
start_command = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 2016 -j ACCEPT
cmd_timeout = 20
stop_command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 2016 -j ACCEPT

Et pour tester nous lançons ensuite knock

sudo knockd

Ne fermez pas, ne faites pas ctrl + C. Ce n’est pas lancé en fond mais directement, juste pour tester. Si vous fermez, ça l’arrête.

 

 

Configuration côté client

Pour se connecter en SSH nous avons maintenant besoin de knock sur la machine cliente. Et ça se trouve normalement dans les paquets de chaque distribution. Dans mon cas Archlinux.

Une fois installé, nous pouvons alors l’utiliser pour nous connecter en SSH, en précisant la combinaison de ports paramétrée sur le serveur. Donc sous la forme suivante :

knock IP -v PORT1 PORT2 PORT3 & SSH -p PORT_SSH user@IP

Ce qui donne

knock IP -v 1978 2000 2015 & SSH -p 2016 aerya@IP

Cette commande remplace donc la commande SSH classique qui aurait été ssh user@IP -p PORT_SSH.

Et nous pouvons alors voir que knock va bien “frapper” aux différentes portes, dans le bon ordre, afin d’autoriser ensuite SSH à établir une connexion  avec le serveur.

┬─[ayx@Aerya:~]─[19:29:13]                                                      
╰─>$ knock xxx.xxx.xxx.xxx -v 1978 2000 2015 & ssh -p 2016 [email protected]

hitting tcp xxx.xxx.xxx.xxx:1978
hitting tcp xxx.xxx.xxx.xxx:2000
hitting tcp xxx.xxx.xxx.xxx:2015
[email protected]'s password: 

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sat Mar  5 19:28:11 2016 from xxx.xxx.xxx.xxx
aerya@nawak:~$ 

Et voilou :)

Bien entendu ça fonctionne tout aussi bien avec une clé SSH en lieu et place d’un mot de passe.

 

 

Lancement du service côté serveur

sudo knockd -d

 

 

Mots clés