Port knocking ou comment dissimuler un service
Ce n'est pas la première fois que vous le lisez sur vos logs et ce ne sera sûrement pas la dernière.
Et oui, le port scanning fait partie intégrante d'une attaque dans la mesure où il permet d'identifier exactement ce qui tourne sur la machine victime et beaucoup d'autres informations relatives aux équipements en amont de celle-ci. Le port scanning ne débouche pas nécessairement sur un exploit, néanmoins, il le précède toujours.
Pour vous prémunir un minimum de ce mapping, une des solutions consiste à implémenter le port knocking.
Le port knocking est une technique complémentaire de sécurisation des serveurs qui permet d'identifier une séquence bien précise et de la lier à une commande.
La plus évidente des commandes est d'ajouter ou de supprimer une règle sur le firewall afin d'ouvrir ou de fermer un port, mais il peut en être tout autrement.
Cela signifie entre autre que tant que la séquence secrète n'a pas été produite, et ce dans un temps donné, le port restera fermé et donc opaque vu de l'extérieur.
Par extension, si un jour le daemon de port knocking est dans les choux, vous ne pourrez plus ouvrir dynamiquement vos ports (donc plus de SSH par exemple). Mieux vaut donc avoir son serveur sous la main...
Fonctionnement
Le port knocking est réalisé par un daemon qui se situe sous le firewall. De cette façon, il peut monitorer toutes les tentatives de connexion et détecter si une séquence bien définie a été initialisée dans un temps donné, suite à quoi il modifie les règles du firewall en conséquence. Durant toute la séquence, le comportement du firewall reste inchangé (aucun ACK), tout se fait sous silence, en submersible afin d'être le moins suspicieux possible.Sequence
Une séquence est une tentative de connexion sur une suite de port, associé chacun à son protocole et avec un ou plusieurs flags en particulier. Une séquence peut également être sur une seule tentative, mais encapsulant le knock dans le payload du paquet. Il est possible de définir une séquence encryptée. Pour vous y essayer, vous pouvez tout aussi bien passer par knock lab.Implementations
Le port knocking est avant tout une technique, il existe donc beaucoup d'implémentations qui l'illustrent. Comme c'est un package que nous avons retrouvé sur les dépôts de la distribution, nous allons travailler sur knockd.Knockd est un trousseau d'outil qui contient le serveur de port knocking mais aussi un client rudimentaire qui permettra à un utilisateur de réaliser la séquence de knock.
Installation et tests
On va partir des sources, afin que la mise en oeuvre soit le plus plateforme independant possible. Les sources iront direct dans /usr/local/src/. Au jour où j'écris ces lignes, la dernière version est la 0.5.$ cd /usr/local/src/ $ wget http://www.zeroflux.org/proj/knock/files/knock-0.5.tar.gz $ tar zxf knock-0.5.tar.gz $ cd knock-0.5Le README nous fournit plus d'info concernant le projet mais aussi des liens concernant d'autres implémentations et d'autres clients.
$ cat README knock :: A port-knocking implementation ======================================= Copyright (c) 2004-2005, Judd Vinet <jvinet@zeroflux.org> ========= ABOUT ========= This is a port-knocking server/client. Port-knocking is a method where a server can sniff one of its interfaces for a special "knock" sequence of port-hits. When detected, it will run a specified event bound to that port knock sequence. These port-hits need not be on open ports, since we use libpcap to sniff the raw interface traffic. =========== EXAMPLE =========== The example below could be used to run a strict (DENY policy) firewall that can only be accessed after a successful knock sequence. 1) Client sends four TCP SYN packets to Server, at the following ports: 38281, 29374, 4921, 54918 2) Server detects this and runs an iptables command to open port 22 to Client. 3) Client connects to Server via SSH and does whatever it needs to do. 4) Client sends four more TCP SYN packets to Server: 37281, 8529, 40127, 10100 5) Server detects this and runs another iptables to close port 22 to Client. ==================== KNOCKING CLIENTS ==================== The accompanying knock client is very basic. If you want to more advanced knocks (eg, setting specific tcp flags) then you should take look at hping, sendip or packit. http://freshmeat.net/projects/hping/ http://freshmeat.net/projects/sendip/ http://freshmeat.net/projects/packit/ ========================= OTHER IMPLEMENTATIONS ========================= Here are some other implementations of port-knocking: http://sourceforge.net/projects/pasmal/ http://doorman.sourceforge.net/En dehors de ce README, aucune indication sur l'install, mais la présence d'un configure et d'un Makefile.in est suffisamment explicite sur la marche à suivre.
$ ./configure --help `configure' configures FULL-PACKAGE-NAME VERSION to adapt to many kinds of systems. Usage: ./configure [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print `checking...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for `--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or `..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [/usr/local] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, `make install' will install all the files in `/usr/local/bin', `/usr/local/lib' etc. You can specify an installation prefix other than `/usr/local' using `--prefix', for instance `--prefix=$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --datadir=DIR read-only architecture-independent data [PREFIX/share] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --infodir=DIR info documentation [PREFIX/info] --mandir=DIR man documentation [PREFIX/man] Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a nonstandard directory <lib dir> CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have headers in a nonstandard directory <include dir> CXX C++ compiler command CXXFLAGS C++ compiler flags CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to <BUG-REPORT-ADDRESS>.Si les paramétrages par défaut vous conviennent, ce qui est mon cas, il suffit d'invoquer un :
$ ./configure $ makePremier souci de la manip', une erreur de compilation arrête net le make :
$ make gcc -g -O2 -g -Wall -pedantic -fno-exceptions -D_GNU_SOURCE -I. -o src/knockd.o -c src/knockd.c src/knockd.c:134: erreur: ‘PATH_MAX’ undeclared here (not in a function) src/knockd.c: In function ‘parseconfig’: src/knockd.c:438: attention : unused variable ‘line’ src/knockd.c: In function ‘get_next_one_time_sequence’: src/knockd.c:695: attention : unused variable ‘line’ src/knockd.c: In function ‘sniff’: src/knockd.c:1386: attention : unused variable ‘parsed_stop_cmd’ src/knockd.c:1385: attention : unused variable ‘parsed_start_cmd’ make: *** [src/knockd.o] Erreur 1L'erreur se situe sur les lignes 134 et 135 de src/knockd.c :
char o_cfg[PATH_MAX] = "/etc/knockd.conf"; char o_pidfile[PATH_MAX] = "/var/run/knockd.pid";Il suffit pour débloquer d'ajouter en tête du fichier un #define qui contiendra par exemple :
#define PATH_MAX 2048Et on relance !
$ make gcc -g -O2 -g -Wall -pedantic -fno-exceptions -D_GNU_SOURCE -I. -o src/knockd.o -c src/knockd.c src/knockd.c: In function ‘get_ip’: src/knockd.c:1077: attention : dereferencing pointer ‘({anonymous})’ does break strict-aliasing rules src/knockd.c:1077: note: initialized from here gcc -g -O2 -g -Wall -pedantic -fno-exceptions -D_GNU_SOURCE -I. -o src/list.o -c src/list.c gcc ./src/knockd.o ./src/list.o -o knockd -lpcap gcc -g -O2 -g -Wall -pedantic -fno-exceptions -D_GNU_SOURCE -I. -o src/knock.o -c src/knock.c gcc ./src/knock.o -o knock sed -e "s/#VERSION#/0.5/" doc/knockd.1.in > doc/knockd.1 sed -e "s/#VERSION#/0.5/" doc/knock.1.in > doc/knock.1 $ make install /usr/bin/install -c -D -m0755 knockd /usr/local/sbin/knockd /usr/bin/install -c -D -m0755 knock /usr/local/bin/knock /usr/bin/install -c -D -m0644 ./doc/knockd.1 /usr/local/man/man1/knockd.1 /usr/bin/install -c -D -m0644 ./doc/knock.1 /usr/local/man/man1/knock.1 /usr/bin/install -c -D -m0644 knockd.conf /etc/knockd.conf
Installation completed ! Jetons un oeil sur la conf !
La configuration se trouve sous /etc, dans un fichier bien nommé knockd.conf.$ cat /etc/knockd.conf [options] logfile = /var/log/knockd.log [openSSH] sequence = 7000,8000,9000 seq_timeout = 5 command = /usr/sbin/iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT tcpflags = syn [closeSSH] sequence = 9000,8000,7000 seq_timeout = 5 command = /usr/sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT tcpflags = synOn peut vite se rendre compte que la syntaxe de la conf est tout ce qu'il y a de plus limpide. Le second point est que la configuration par défaut invoque des règles iptables pour les 2 comportements décrits : une pour ajouter une règle à la table INPUT qui ouvre le port 22, et l'autre qui la supprime. Par exemple, pour la section openSSH, la lecture est la suivante : Si l'on tape en tcp, avec le flag syn armé sur les ports 7000, 8000 et 9000, le tout maximum 5 secondes, la séquence est identifiée comme valide et déclenche /usr/sbin/iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT, avec %IP% correspondant à l'IP du knocker. En clair, seule l'IP du knocker est autorisée sur le port 22 à la validation de la séquence. Et si vous voulez taper par udp, rien ne vous empêche de le formuler dans la séquence : 7000:tcp,8000:udp,9000:tcp Pour les flags à utiliser, vous avez le choix entre fin, syn, rst, psh, ack et urg. Enfin, si vous souhaitez moduler en terme de temps d'ouverture de port plutôt qu'en ouverture tout court, il vous faut restructurer la section comme suit :
[opencloseSSH] sequence = 2222:udp,3333:tcp,4444:udp seq_timeout = 15 tcpflags = syn,ack start_command = /usr/sbin/iptables -A INPUT -s %IP% -p tcp --syn -j ACCEPT cmd_timeout = 5 stop_command = /usr/sbin/iptables -D INPUT -s %IP% -p tcp --syn -j ACCEPTPetit détail, au bout de 15 secondes, le port est fermé, mais comme votre firewall est à état (statefull), la connexion établie perdure. Allez, un petit dernier pour la route ! Ici, nous ne voulons pas spécifier une séquence unique et fixe, mais un ensemble de séquence, que nous définirons dans le fichier /etc/knockd/smtp_sequences. Ces séquences déclencheront l'ouverture du port 25 (oui, oui, le smtp) pour une durée de 5 secondes. Détail intéressant, knockd va se charger de commenter la séquence précédemment utilisée, ce qui protègera contre les attaque de rejeu dans le cas où votre séquence a été sniffée.
[opencloseSMTP] one_time_sequences = /etc/knockd/smtp_sequences seq_timeout = 15 tcpflags = fin,!ack start_command = /usr/sbin/iptables -A INPUT -s %IP% -p tcp --dport 25 -j ACCEPT cmd_timeout = 5 stop_command = /usr/sbin/iptables -D INPUT -s %IP% -p tcp --dport 25 -j ACCEPTBien entendu, il faut vraiment éviter de trifouiller dans notre /etc/knockd/smtp_sequences pendant que knockd tourne. Egalement intéressant dans le cadre d'une centralisation de log, vous avez la possibilité de paramétrer knockd afin qu'il stocke ses infos via syslog grâce à l'option UseSyslog qui est à renseigner dans la section [options]. Pour pouvoir être opérationnel, knockd a besoin de rechercher dans les logs du firewall les éléments concernant une éventuelle combinaison gagnante. Cet élément implique que la machine supportant knockd ait accès à ces logs, et de façon réactive. En clair, si vous centraliser ces logs, mieux vaut avoir de bons équipements réseau, dédiés et une liaison qui envoie... Une règle d'or lors de l'installation d'outil de ce genre sur des machines exposées au World Wild Web, ne jamais laisser la configuration par défaut. Pour vous en convaincre, pensez que n'importe qui peut installer ce soft, et si ça ne suffit pas, vous pouvez toujours taper sur http://defaultpassword.com/. Donc première chose à faire, trouver une bonne séquence et paramétrer la commande qu'elle déclenchera. Il ne vous reste plus qu'à le lancer, mode daemon, s'il vous plait !
$ /usr/local/sbin/knockd -d $ tail -f /var/log/knockd.log [2010-08-25 16:14] starting up, listening on eth0 [2010-08-25 16:14] 192.168.20.3: openSSH: Stage 1 [2010-08-25 16:14] 192.168.20.3: openSSH: Stage 2 [2010-08-25 16:16] 192.168.20.3: openSSH: Stage 3 [2010-08-25 16:17] 192.168.20.3: openSSH: Stage 4 [2010-08-25 16:19] 192.168.20.3: openSSH: OPEN SESAME [2010-08-25 16:20] openSSH: running command: /sbin/iptables -I INPUT -s 192.168.20.3 -p tcp --dport 22316 -j ACCEPT [2010-08-25 16:25] 192.168.20.3: openSSH: command timeout [2010-08-25 16:25] openSSH: running command: /sbin/iptables -D INPUT -s 192.168.20.3 -p tcp --dport 22316 -j ACCEPT