Ce document est le support écrit d'un atelier / TP ( Travaux Pratiques) que j'ai présenté le 1er avril 2004 dans le cadre de l'association Linux Guilde. Il s'agit d'une succession d'exercices et de leurs réponses afin d'étudier le comportement et la mise en oeuvre de Netfilter, le firewall de Linux. Vous trouverez les notions théoriques de cet atelier dans cette autre documentation que j'ai écris.
Vous trouverez la dernière version de ce document :
Pour les personnes désirant reproduire cet atelier chez eux, vous aurez besoin :
De télécharger le fichier de la présentation au format OpenOffice.org. Vous pourrez alors suivre la présentation tout en faisant les exercices, en vous y référant à chaque fois que vous verrez la balise :
D'une machine sur laquelle sera installée un serveur web (Apache par exemple).
Dans la suite de la documentation, cette machine sera appelée "machine du présentateur" ou "serveur".
D'une seconde machine, reliée en réseau avec la précédente, sur laquelle vous allez travailler.
Enfin, pour certains tests et démonstrations de l'atelier, vous aurez besoin d'une troisième machine configurée comme la 2nd machine. Cependant, c'est optionnel. Aussi si vous n'avez pas de 3ème machine disponible, vous ne ferez pas certains exercices et passerez aux exercices suivants.
Dans cet atelier, nous allons revoir quelques rapides rappels sur Netfilter, et quelles bases des techniques de firewall sous Linux. Puis nous mettrons en oeuvre des techniques simples de filtrages. Dans une 3ème partie, nous aborderons des filtrages plus évolués à usage tant personnels que professionnels. Nous aborderons enfin la mise en oeuvre de protections destinés aux serveurs.
Le contenu théorique de cet atelier se base sur une documentation que j'ai écris, et que vous pouvez retrouver sur http://olivieraj.free.fr/fr/linux/information/firewall/.
Netfilter est une couche logiciel intégrée dans le kernel de Linux, c'est à dire le coeur même du système d'exploitation Linux. Elle se situe plus particulièrement au niveau des couches réseaux IP (du protocole réseau IP, appelé aussi par abus de langage "TCP/IP"), et se caractérise sous la forme de 5 hooks ("crochets" en Français) placés à 5 endroits stratégiques du système réseau du kernel.
Lorsque qu'un paquet IP arrive à un de ces hook, il va subit un certain nombre de vérifications (règles) que constituent la chaîne associé au hook en question. En fonction du résultat de ces vérifications, une action (appelée "cible" par la suite) sera décidé pour lui : suppression du paquet, acceptation, modification, etc...
Illustration : Vue générale et hooks
Comme leur nom l'indiquent, les règles sont des critères sur le contenu des paquets.
Les critères peuvent être multiples :
Suivant si le paquet répond ou non aux critères, le paquet sera dirigé vers une cible ou un autre.
Exemple de cible :
Illustration : Règles
Les chaînes sont de deux types : pré-définie ou utilisateur. Dans les deux cas, les chaînes sont des empilements de règles, que le paquet IP va parcourir. Une fois que toutes les règles ont été appliquées sur le paquet, et que celui-ci ne correspond à aucune règle, la cible par défaut de la chaîne sera utilisée. En général, il s'agira de DROP ou de ACCEPT.
Les chaînes pré-défines sont au nombre de 5, et sont toutes associées à un hook particulier :
Hook | Chaîne | Description |
---|---|---|
NF_IP_PRE_ROUTING | PREROUTING | A ce stade, le paquet est "brut de forme", c'est à dire qu'il n'a subit aucune modification par rapport à ce que l'interface réseau a reçu. |
NF_IP_LOCAL_IN | INPUT | Ce "hook" est très intéressant, car à ce stade, le paquet est prêt à être envoyé aux couches applicatives, c'est à dire aux serveurs et aux clients qui tournent sur la machine. C'est un des points principaux sur lequel nous allons travailler. |
NF_IP_FORWARD | FORWARD | "Forward" ("faire suivre" en français) est assez particulier. Ce "hook" voit passer des paquets IP qui vont transiter d'une interface réseau à une autre, sans passer par la couche applicative. Pourquoi diantre faire suivre un paquet entre 2 interfaces réseaux, comme par exemple entre "eth0" et "ppp0" ? En fait, c'est afin de permettre à Linux de se transformer en passerelle, une sorte de connexion entre diverses interfaces réseaux. |
NF_IP_LOCAL_OUT | OUPUT | Ce "hook" est l'équivalent du "NF_IP_LOCAL_IN", sauf qu'il est exécuté après que les couches applicatives aient traités, ou générés, un paquet IP. Tout comme "NF_IP_LOCAL_IN", c'est un point que nous allons voir en détail. |
NF_IP_POSTROUTING | POSTROUTING | C'est l'équivalent du "NF_IP_PRE_ROUTING" pour les paquets IP sortants de la couche IP. A ce stade, les paquets sont prêt à être envoyés sur l'interface réseau. |
Les chaînes utilisateurs sont une particularité intéressante de Netfilter. Elles peuvent être appelées en temps que cible d'une règle (d'une chaîne dite "appelante"), et contenant elles-mêmes des règles. A la fin de la chaîne utilisateur, si aucun traitement n'a été effectué sur le paquet IP, celui-ci continuera son traitement dans la chaîne appelante.
Illustration : Chaînes
Comme son nom ne l'indique pas, Netfilter ne s'occupe pas qu'uniquement du filtrage des paquets IP. C'est une de ses tache, mais ce n'est pas la seule. Ainsi, Netfilter est conçue pour gérer 3 taches. Et à chaque tache, une table a été définie. Les 3 taches sont :
Une table est composée d'un ensemble de chaînes pré-défines, et d'un comportement particulier. Ainsi :
La table FILTER est composée des chaînes :
Son but est d'assurer le filtrage des paquets IP, c'est à dire d'autoriser ou non un paquet IP à accéder à une application, ou à en sortir. La table FILTER est aussi responsable de l'autorisation du transfert des paquets IP d'une interface réseau à l'autre, dans le cas du NAT.
La table NAT est composée des chaînes :
Elle est spécifiquement destinée à assurer le NAT. Alors que dans la table FILTER, la chaîne FORWARD permet de définir quelles sont les paquets autorisés à être NATé, la table NAT sera chargée de la modification des paquets, afin qu'ils soient correctement utilisable sur l'interface de destination.
La table MANGLE est composée des chaînes :
Cette table est très particulière. Elle permet de modifier les paquets, en leur rajoutant ou supprimant certaines informations. Cette table est pour l'instant utilisé dans le cadre de la QoS (Quality Of Service), permettant de rendre le traitement de certains paquets plus prioritaires que d'autres.
Illustration : Tables
Lorsque l'on parle de firewall sous Linux, iptables est LA commande à connaître. Ce programme est la 2nd partie principale de Netfilter. Contrairement au code de Netfilter inclus dans le noyau Linux, "iptables" est un programme "classique" (i.e : il fonctionne dans l'espace utilisateur) que l'on lance manuellement. Bien entendu, seul le root a les droits suffisant pour l'utiliser.
Iptables permet au root de configurer Netfilter, en lui indiquant quelles sont les règles à utiliser pour les différentes tables et chaînes. Il se lance plusieurs fois de suite, chaque lancement permettant de créer/supprimer/visualiser une règles de Netfilter.
Un descriptif complet des paramètres d'iptables serait inutile. La commande "man iptables" étant LA référence de toute documentation sur cette commande. Cependant, en voici un bref résumé des principaux paramètres :
iptables [table] [action] [critères] [cible]
Pour plus d'informations sur ces paramètres ou pour avoir plus d'explications sur les exemples, vous pouvez consulter ce chapitre de ma documentation de Netfilter.
[table]
Ce paramètre permet de définir sur quelle table la configuration va s'effectuer. Comme vu précédemment, il y a 3 tables : FILTER, NAT et MANGLE.
Paramètre | Description |
---|---|
-t [le nom de la table : filter, nat, mangle] | Spécifie la table sur lequel on va travailler. |
Exemple : iptables -t filter -X |
Remarque :Ce paramètre "[table]" est optionnel. Si aucune table n'est définie (i.e : il n'y a pas de "[table]", "iptables" utilisera l'option par défaut "-t filter").
[action]
Ici, on va indiquer à "iptables" ce que l'on va faire :
Paramètre | Description |
---|---|
-Z | Réinitialise les compteurs des paquets d'octets passant par la table. |
Exemple : iptables -t mangle -Z | |
-F [PREROUTING, INPUT, FORWARD, OUTPUT, POSTROUTING] | Suppression de toutes les règles pré-défines de la chaîne indiquée. Ou, si aucune chaîne pré-définie n'est indiquée, de toutes les règles pré-défines de la table. |
Exemple : iptables -t filter -F FORWARD | |
-X [Chaîne utilisateur] | Suppression de toutes les règles de la chaîne utilisateur indiqué. Ou, si aucune chaîne utilisateur n'est indiquée, de toutes les chaînes utilisateurs de la table. |
Exemple : iptables -t nat -X | |
-L [Nom de table : filter, nat, mangle] | Affiche la liste des chaînes et règles de la table spécifiée. Les paramètres "-n" et "-v" sont très utiles avec ce paramètre. |
Exemple : iptables -t nat -L -n -v | |
-N Nouvelle_chaîne_utilisateur | Crée une nouvelle chaîne utilisateur. Par la suite, des règles peuvent êtres ajoutées à ces chaînes, grâce au paramètre "-A" |
Exemple : iptables | |
-A Nom_chaîne | Rajoute une nouvelle règle à la fin de la chaîne "Nom_chaîne". "Nom_chaîne" peut être une chaîne pré-définie ou une chaîne utilisateur. |
Exemple : iptables -A INPUT -i lo -j ACCEPT | |
-D PREROUTING, INPUT, FORWARD, OUTPUT, POSTROUTING Numéro_de_chaîne | Supprime la chaîne indiquée par "Numéro_de_chaîne". |
Exemple : iptables -D OUTPUT 5 | |
-P Nom_chaîne Cible | Définie à "Cible" la cible par défaut de la chaîne "Nom_chaîne". |
Exemple : iptables -t filter -P INPUT DROP |
[critères]
Cette partie permet de définir sur quels critères du paquet IP la règle va s'appuyer, afin de déterminer si oui ou non le paquet répond à la règle. On peut utiliser plusieurs critères en même temps, afin d'affiner au mieux l'application de la règle.
Paramètre | Description |
---|---|
-i Interface_réseau | Indique l'interface réseau par laquelle le paquet arrive. |
Exemple : iptables -A INPUT -i eth0 -j ACCEPT | |
-o Interface_réseau | Indique sur quelle interface réseau le paquet va sortir. |
Exemple : iptables -A OUTPUT -o eth0 -j DENY | |
-s Adresse_ou_plage_IP | Définie l'adresse ou la plage d'adresses IP dont sont issues le paquet. |
Exemple : iptables -A INPUT -s 192.168.0.100 -j ACCEPT | |
-d Adresse_ou_plage_IP | Définie l'adresse ou la plage d'adresses IP a qui sont destinée le paquet. |
Exemple : iptables -A FORWARD -d 10.0.0.0/255.0.0.0 -j REJECT | |
-p Protocole | Précise sur quel protocole la règles s'applique. |
Exemple : iptables -A INPUT -p icmp -j DROP | |
--sport Port(s) | S'utilise avec le paramètre "-p". Cette option définie le port source dont est issus le paquet IP. Le paramètre "Port(s)" peut être un chiffre ("80"), une suite de chiffres séparés par des virgules ("21,53,100") ou un nom de service ("ssh"). |
Exemple : iptables -A INPUT -p tcp --sport 80 -j ACCEPT | |
--dport Port(s) | S'utilise avec le paramètre "-p". Cette option définie le port cible a qui est destiné le paquet IP. Le paramètre "Port(s)" peut être un chiffre ("80"), une suite de chiffres séparés par des virgules ("21,53,100") ou un nom de service ("ssh"). |
Exemple : iptables -O OUTPUT -p tcp --dport 21,53,80 -j ACCEPT | |
-m Nom_module | Indique à Netfilter qu'il faut utiliser le module "Nom_module" afin d'analyser cette règle. Un module tout particulièrement intéressant est le module "state", qui permet le suivi de connexion (conntrack). |
Exemple : iptables -A OUTPUT -p tcp -m state --state ! INVALID -j ACCEPT | |
--state [!] NEW, ESTABLISHED, RELATED, INVALID | Dans le cas de l'utilisation du module "state", indique quel(s) statut la trame doit avoir afin d'appliquer la règle. |
Exemple : iptables -I INPUT -p udp -m state --state ESTABLISHED,RELATED -j ACCEPT |
[cible] Ce dernier paramètre est important, car il permet d'indiquer à Netfilter ce qu'il doit faire lorsque les critères de la règle s'appliquent au paquet IP.
Paramètre | Description |
---|---|
-j ACCEPT, DROP, REJECT, LOG, ULOG, etc... | Spécifie la cible lorsque la règle s'applique. |
Exemple : iptables -A OUTPUT -o eth0 -j ACCEPT |
Illustration : Iptables
Dans cette partie, nous verrons comment mettre en oeuvre des filtrages assez simples.
La technique de firewall la plus efficace se résume en 3 phrases:
Sous Linux, la configuration du firewall va consister à lancer la commande "iptables" autant de fois que nécessaire pour construire une à une les différentes règles dont nous aurons besoin. Voyons maintenant comment construire un tel script.
Illustration : Principes généraux de filtrage
La première chose à faire pour construite notre script de firewall sera d'initialiser le firewall. Comme le script que nous allons écrire ne sait à priori pas dans quel état se trouve Netfilter (si des règles n'ont pas été déjà définies par exemple), il nous faudra commencer par supprimer toutes les précédentes règles (pré-définies et utilisateur). Et ce, pour toutes les tables de Netfilter.
Illustration : Initialisation des chaînes
L'ordre d'initialisation des tables n'a pas d'importance ici.
Comme vu précédemment, il est nécessaire de configurer Netfilter afin de tout interdire par défaut.
La logique voudrait donc que l'on place à "DROP" la cible par défaut (ou politique par défaut) de chaque chaîne. Et ce, quelque soit la table. Cependant, comme nous désirons avant tout filtrer nos connexions, seul les cibles par défaut de la table FILTER sont à restreindre. Pour les tables NAT et MANGLE, il n'est donc pas nécessaire de mettre à DROP les cibles par défaut. Même si c'est techniquement faisable de restreindre les cibles par défaut des autres tables, cela alourdit considérablement le script de firewall, et entraîne une chute des performances réseau.
Illustration : Cibles/politique de filtrage par défaut
Améliorations : Penser à optimiser au mieux la sécurité, en plaçant les restrictions dans l'ordre de priorité décroissante.
A partir de maintenant, nous pourrons utiliser ce script comme base de travail pour nos autres scripts.
Où en sommes nous ? Nous avons actuellement verrouillé notre Linux, en filtrant systématiquement ses communications réseaux.
Illustration : Filtrage de ports 1/2
Bien, notre machine étant complètement verrouillée, nous allons voir maintenant comment lui laisser un peu communiquer avec les autres machines mises en réseau.
Illustration : Filtrage de ports 2/2
Améliorations : Recopier le script "filter1.sh" en "filter1a.sh". Dans ce nouveau script, restreindre encore plus le firewall en rajoutant au filtrage du serveur HTTP du présentateur, le filtrage par votre propre adresses IP.
Maintenant nous allons travailler un peu avec les logs. Netfilter peut stocker ("logger" ou plus français "noter") des informations sur l'état du firewall, via le démon "syslogd". Ceci est particulièrement intéressant afin de rechercher une activité réseau suspecte (tentative d'intrusion), ou de rechercher la cause d'un mauvais fonctionnement du firewall
Illustration : Log
Améliorations : Recopier le script "log1.sh" en "log1a.sh". Rajouter un préfixe afin de différencier les logs entrants et sortants.
Lancer un xterm en pleine largeur d'écran, avec si possible une police assez petite. Puis taper, en temps que root, la commande "tail -f /var/log/messages".
Ou si possible (présence du paquetage "rxvt" sur la machine), télécharger rxvt_log depuis la machine du présentateur et en temps que root, taper "rxvt_log messages".
Dans cette partie, nous allons étudier les défauts du filtrage part ports vu précédemment. Puis, nous mettrons en pratiques des techniques de filtrages plus fines et plus efficaces.
Nous allons utiliser "nmap", le scanneur de ports, afin de montrer les lacunes du filtrage par port.
Illustration : Insuffisances du filtrage par ports
La technique du suivi de connexion ("conntrack") rend inefficace la précédente astuce de port scanning. Elle permet aussi une sécurité très largement accrue, en restreignant au maximum les flux de connexions.
Le suivi de connexion se résume par les points suivants :
Le module "-m state", à passer en paramètre à "iptables".
Les états "--state Etat", à passer en paramètre à "iptables", après le "-m state". Les états possibles sont :
Les modules kernels associés au suivi de connexion : ip_conntrack, ip_conntrack_ftp, ip_conntrack_proto_gre, ip_conntrack_h323, ip_conntrack_irc, ip_conntrack_pptp, etc...
Illustration : Suivi de connexion
Améliorations : Recopier le script "filter2.sh" en "filter2a.sh". Dans ce nouveau script, rajouter les règles nécessaires afin que vous puissiez accéder aux serveurs FTP (port 21) de n'importe quelle autre machine. Attention, il y a un gros piège...
Les logs du firewall sont intéressants (voir même essentiels), mais il est dommage que l'on ne puisse pas les séparer des autres logs kernel. En effet, il arrive que le flots de logs de firewall soit très importants en volume, ce qui rend moins évident la lecture des autres logs du kernel (qui sont tout aussi important, si ce n'est plus).
ULOG est une solution très intéressante à ce problème. Il se décompose en :
Illustration : ULOG
Améliorations : Recopier le script "log2.sh" en "log2a.sh". Rajouter un préfixe afin de différencier les logs entrants et sortants.
Lancer un xterm en pleine largeur d'écran, avec si possible une police assez petite. Puis taper, en temps que root, la commande "tail -f /var/log/ulogd.syslogemu".
Ou si possible (présence du paquetage "rxvt" sur la machine), télécharger rxvt_log depuis la machine du présentateur et en temps que root, taper "rxvt_log netfilter".
Les chaînes utilisateurs ont le même rôle que les chaînes pré-défines, à savoir : Un conteneur à règles. L'intérêt des chaînes utilisateur n'est pas évident aux premiers abords, mais au final, elles sont très utiles.
Illustration : Chaînes utilisateurs 1/2
Le petit exercice précédent n'est pas très spectaculaire. Mais il est nécessaire afin de bien comprendre l'exercice suivant, qui sera bien plus intéressant.
Dans ce qui va suivre, nous allons considérer que nous voulons avoir des liens privilégiés avec :
Nous ne désirons communiquer qu'avec ces trois machines, toutes les paquets IP a destination ou partant vers les autres machines devront être détruits.
Illustration : Chaînes utilisateurs 2/2
Le problème de l'état NEW du suivi de connexion vient dans son mode de détection de ce qu'il considère comme étant une nouvelle connexion. Contrairement à ce que l'on peut penser, il ne se base tout simplement pas sur une handshake, ce qui peut l'amener à laisser des paquets se faisant passer pour une nouvelle connexion.
Illustration : Contraintes de l'état NEW 1/2
Si on ne veut pas utiliser l'état NEW, la technique de filtrage (pour des connexions initiées par notre machine) à utiliser peut être ceci :
Illustration : Contraintes de l'état NEW 2/2
Ce script peut vous servir d'exemple pour votre propre firewall. On notera qu'il utilise un nombre de règles minimales. Et que nous contrôlons parfaitement les protocoles que nous voulons laisser sortir.
Mettre en place un démon (logiciel de type "serveur") n'est pas en soit très compliqué. Mais le configurer de telle manière à ce qu'il ne soit pas piraté n'est pas aisé. Le firewall peut assurer une partie de sa sécurité, mais la plus grande partie sera la responsabilité du démon lui même, comme par exemple "Apache" dans le cas d'un serveur HTTP.
Un firewall ne peut pas assurer à lui seul la sécurité d'un démon / serveur publique ! La configuration du démon est l'élément le plus important !
Nous n'allons pas nous intéresser ici à la configuration du démon HTTP lui-même. Cela ferait l'objet d'un atelier complet... Mais seulement de ce que peut faire Netfilter afin de protéger un tel démon.
Illustration : Serveur HTTP (web)
Améliorations : Recopier le script "serveur1.sh" en "serveur1a.sh". Dans ce nouveau script, autoriser les autres machines du réseau à "pinger" notre machine, mais en limitant ce flux à 1 ping/s (module "limit").
Maintenant nous allons voir comment transcrire le travail précédent afin de protéger un serveur FTP.
Illustration : Serveur FTP (fichier)
Écouter les explications sur l'intérêt du module "ip_conntrack_ftp".
Dans cet atelier, nous avons abordé les principales techniques de Netfilter en terme de filtrage. Cependant, cet atelier ne peut résumer qu'une partie seulement des fonctionnalités de Netfilter. Aussi, vous êtes encouragé à fouiller la documentation que j'ai précédemment rédigé, les guides officiels de netfilter, le "man iptables", et bien évidement Google ou tout autre moteur de recherche, afin d'approfondir ce sujet.
Si vous devez retenir qu'une seul chose de cet atelier, c'est le principe général du filtrage : Initialisation du firewall / tout interdire par défaut / autoriser le strict minimum.
J'espère que cet atelier vous a intéressé, et que vous pourrez utiliser les notions abordées afin de configurer efficacement votre propre firewall Linux.
Je remercie le CUEFA (Grenoble, Isère / 38) et en particulière Romain KOBYLANSKI pour nous avoir fournit la salle et le matériel de cet atelier. Merci aussi à l'association Guilde pour l'organisation de l'atelier , et notamment (par ordre alphabétique) Edgar BONET, Christophe FIXOT et Jérôme KIEFFER.
Ce document peut être librement lu, stocké, reproduit, diffusé, traduit et cité par tous moyens et sur tous supports aux conditions suivantes:
Toute incompatibilité des clauses ci-dessus avec des dispositions ou contraintes légales, contractuelles ou judiciaires implique une limitation correspondante du droit de lecture, utilisation ou redistribution verbatim ou modifiée du document.
Site de référence : http://olivieraj.free.fr/ | Last modified: Tue Apr 20 23:08:00 CEST 2004 |