L'article précédent a montré quelques techniques de sécurité système afin de protéger un système de "lui-même". Cet article présente un autre niveau de sécurité : protéger les uns des autres les systèmes d'un même réseau local. Toute organisation disposant d'un parc informatique relie aujourd'hui ses systèmes par un réseau local. De plus en plus de particuliers possèdent plusieurs machines. Pour des raisons évidentes de mise en commun de certaines informations internes, d'accès à des ressources partagées, les systèmes sont généralement plus permissifs vis-à-vis des systèmes du réseau local que par rapport aux systèmes de l'extérieur.
Il en résulte qu'il est souvent plus facile d'attaquer un système depuis l'intérieur que depuis l'extérieur. De plus, certains systèmes, considérés comme peu importants, par exemple des stations de travail, peuvent souffrir d'un manque d'attention en matière de sécurité. Si le réseau local est relié à l'Internet, un cracker extérieur pourra, dans un premier temps, s'approprier une des machines faibles et, dans un second temps, continuer son action depuis cette machine. Il bénéficiera ainsi des droits et privilèges accordés aux machines du réseau local.
Nous allons aborder deux catégories de problèmes de sécurité réseau interne : les problèmes engendrés par les machines reliées au même réseau physique (même brin Ethernet par exemple) et les problèmes liés à l'utilisation détournée de certains services réseau. Encore une fois, cet article ne saurait être exhaustif sur toutes les techniques et trous de sécurité utilisés par les crackers.
Le sniffing
Les données circulent souvent en clair sur un réseau local. Par exemple, lorsqu'on utilise la commande telnet, le login et le mot de passe sont envoyés en clair à la machine sur laquelle on désire se connecter. Le sniffing consiste à configurer une machine du réseau local afin qu'elle puisse recevoir tous les paquets qui y circulent, même ceux qui ne lui sont pas directement destinés. Ainsi, dans l'exemple précédent, un cracker pourrait simplement écouter le réseau, afin d'y trouver les mots de passe des autres utilisateurs.
Un système Linux est particulièrement bien adapté au sniffing. Il suffit d'être root sur la machine et d'utiliser un logiciel prévu à cet effet. La plupart des distributions proposent en standard le paquetage tcpdump qui permet de faire du sniffing. Ce n'est pas pour favoriser le cracking, mais pour aider les administrateurs systèmes dans leurs tâches de débogage réseau. En effet, tcpdump permet de réaliser une trace complète de tous les paquets circulant sur le réseau, ce qui s'avère utile, voire indispensable, pour résoudre certains problèmes.
tcpdump fait passer l'interface réseau dans un mode particulier, appelé promiscuous-mode, lui permettant ainsi d'observer tous les paquets. Pour chaque paquet, des informations sont affichées à l'écran : les machines source et destination, les ports source et destination, le type de paquet, les données brutes du paquet, etc. En analysant ces informations, on peut reconstituer les données transmises sur le réseau. Il est souvent utile d'utiliser un script permettant de reconstituer automatiquement les informations intéressantes depuis les données brutes données par tcpdump. Essayez par exemple la commande suivante (en root) :
tcpdump -l -q -x port telnet
Essayez ensuite un telnet sur une autre machine du réseau local : l'écran se remplit d'informations assez difficiles à comprendre... Les plus perspicaces des lecteurs remarqueront peut-être, au milieu de la foule d'informations, certains paquets contenant des codes correspondant aux caractères entrés par l'utilisateur au moment de la saisie du login et du mot de passe. Un petit script en Perl peut facilement faire le tri dans ces informations et sortir du lot, automatiquement, les informations pertinentes :
#!/usr/bin/perl #Utilise tcpdump version 3.4 $host = shift || <<machine1>>; $port = <<telnet>>; print <<Sniffing $host sur $port\n>>; open (SNIF, <</usr/sbin/tcpdump -l -q -x dst host $host and port $port |>>); while (<SNIF>) { if (/tcp ([0-9]*) /) { $tcp = $1; $- = <SNIF>; if (/[0-9a-f]{4} ([0-9a-f]{4})/) { $size = hex <<0x$1>>; } $n1 = int (($size - 1) / 16); while ($n1 > 0) { $_ = <SNIF>; $n1-; } $c1 = chop; $c2 = chop; $c3 = chop; $car = chr(hex <<0x$c3$c2>>); if ($tcp == 1) { print stderr <<$car>>; } elsif ($tcp == 2) { print stderr <<\n>>; } } } |
Entrez ce script dans votre éditeur de programmes préféré, donnez-lui les droits en exécution puis lancez-le (en root), en indiquant comme premier paramètre le nom d'une machine sur le réseau local. Dans une autre fenêtre, exécutez un telnet sur la machine que vous avez passée en paramètre. Admirez ce qu'il se passe lorsque vous entrez vos login et mot de passe... Evidemment, toute personne sur le séseau local effectuant un telnet sur cette machine subira le même sort...
Il est assez difficile de régler le problème du sniffing. Il est nécessaire qu'aucun utilisateur ne puisse être root sur les machines du réseau local (sauf évidemment l'administrateur !). Mais que faire avec les systèmes d'exploitation qui n'ont aucune notion de droits utilisateurs ? Que faire si un utilisateur est autorisé à connecter une machine personnelle (par exemple un portable) sur le réseau ?
L'action la plus évidente à mettre en oeuvre pour résoudre ce problème est le cryptage des données. Une solution consiste à interdire tous les protocoles qui font circuler des informations sensibles en clair : telnet, ftp, samba, etc. et de les remplacer par d'autres protocoles sécurisés (ssh) ou, pour certains, de les configurer pour une transmission sécurisée (samba a la possibilité de traiter des mots de passe cryptés). On peut aussi encapsuler certains protocoles dans des tunnels sécurisés grâce à ssh. Enfin, on peut appliquer un patch au noyau Linux afin qu'il intègre la norme IPSec, rendant tous les échanges de données cryptés. Il est à noter que IPv6 intégrera en standard cette fonctionnalité.
Les sites à visiter sont les home page de freeswan pour IPSec (http://www.xs4all.nl/~freeswan), la faq de ssh et les documentations des logiciels pour leur configuration (fichier ENCRYPTION.txt pour samba)
L'IP spoofing
Le spoofing est une méthode généralement employée depuis l'extérieur. Son principe est le suivant : soit trois machines A, B et C. A a des privilèges sur B (par exemple le rlogin est autorisé de A vers B). C est la machine d'un cracker. Si le cracker arrive à faire passer sa machine C pour A aux yeux de B, alors il aura les mêmes privilèges que A. Le jeu consiste à faire recevoir par B des paquets envoyés par C mais contenant l'adresse IP de A. Les services détournables par cette méthode sont ceux dont la relation d'authentification se faire sur l'adresse IP (c'est le cas de toutes les commandes r : rlogin, rsh, etc). On dit souvent que ce genre d'attaque est aveugle (blind attack) dans le sens où même si C peut envoyer des paquets contenant l'adresse de A, il ne pourra pas recevoir les paquets envoyés par B à destination de A. Il en résulte que C doit toujours envoyer à B ce qu'il attend, en prédisant les contenus de chaque paquet envoyé, mais en n'ayant aucune possibilité de voir réellement ce que B envoie.
Sur un réseau local, le spoofing est encore plus terrible. En effet, si B et C se trouvent sur le même réseau physique, alors C peut voir les paquets de B à destination de A. Et tout devient alors plus facile... Il existe même une méthode physique déconcertante de facilité : lorsque A est éteint, une personne peut très bien déposer sur le réseau une machine personnelle en lui ayant donné la même adresse IP que A. On ne peut même plus parler de spoofing : c'est de l'usurpation d'identité !
Il existe plusieurs méthodes pour contrer ce genre d'attaque : supprimer tous les protocoles dont l'authentification est basée sur l'adresse IP (les commandes r*), faire que tous les échanges de données soient cryptés / authentifiés (IPSec). Pour plus d'informations, on consultera un excellent numéro de Phrack magazine (http://www.fc.net/phrack/files/p48/p48-14.html).
Les commandes r*
Les commandes r* (rsh, rlogin, rwho, etc) sont encore souvent utilisées dans les organismes dont l'architecture informatique est construite sur des machines Unix. Le but est de simplifier la vie de l'utilisateur en lui permettant de se connecter à divers services sur différentes machines sans entrer plusieurs fois son mot de passe. On peut configurer un système pour le rendre équivalent à un autre : toute personne identifiée sur un système peut alors se loguer par rlogin sur l'autre système sans fournir de mot de passe. Par exemple, l'utilisateur toto se logue sur une machine. Il pourra, par un simple rlogin, se loguer sous toto sur toute machine équivalente.
Les commandes r* se configurent par plusieurs fichiers : le fichier /etc/hosts.equiv et, éventuellement, plusieurs fichiers .rhosts dans les répertoires utilisateurs. Ces fichiers sont souvent lisibles par tous les utilisateurs d'un système. Un utilisateur peut facilement se faire passer, sur un système sur lequel il a les droits de root, pour un utilisateur de nom toto : il crée un compte toto, puis se logue sous toto ! Si la machine sur laquelle il travaille est désignée comme équivalente à un autre système, il pourra s'y loguer et faire ce que bon lui semble des fichiers de toto... Etre root sur une machine n'est pas compliqué : si, par exemple, certaines machines sont des PC, il existe des distributions de Linux tenant sur une disquette et rebooter est un jeu d'enfant ! Il existe même des logiciels sous d'autres systèmes d'exploitation non sécurisés qui permettent de se faire passer sans le moindre effort pour n'importe qui... La solution : pas de pitié pour les commandes r* ! Il faut les désactiver en commentant les lignes qui les concernent dans le fichier /etc/inetd.conf.
Voilà un protocole intéressant ! Il permet de partager des fichiers entre plusieurs systèmes. Il n'est pas rare de trouver des réseaux sur lesquels les répertoires utilisateurs sont exportés par un système afin que les utilisateurs puissent retrouver leurs fichiers quand ils se connectent à d'autres systèmes. Malheureusement, encore une fois, le mécanisme d'authentification de NFS n'est pas très évolué : il est basé sur les noms des machines autorisées et sur l'UID, c'est-à-dire le numéro d'utilisateur. Le fichier /etc/exports d'un système contient les droits qu'ont les autres machines sur certains répertoires. Par exemple, une ligne du genre : /home *.domain (rw) permet de partager la totalité des comptes utilisateurs pour les machines du domaine Internet domain et ce, en lecture / écriture.
Attention toutefois, cela ne signifie pas que chaque utilisateur peut avoir accès en écriture sur les fichiers d'un autre utilisateur. Etre root sur un système ne suffira pas non plus pour écraser les données d'un autre utilisateur. Par contre, si on crée un compte d'UID, disons 100, sur le système crack.domain, on pourra lire et écrire dans le répertoire de l'utilisateur 100 du système sur lequel s'exécute NFS !
D'autres exemples montrent aussi le laxisme de certains administrateurs : imaginons qu'un système NFS exporte, pour une raison quelconque, le répertoire /usr/games ou /usr en lecture / écriture. La plupart des fichiers /etc/passwd contiennent une ligne définissant un utilisateur games ayant comme répertoire personnel /usr/games. Un cracker pourrait déposer dans ce répertoire un fichier .rhosts. Si les commandes r* ne sont pas désactivées, un simple rlogin lui permettrait de se loguer sur le système ! De là à exécuter un exploit pour être root, il n'y a qu'un pas...
Comment palier à ce problème ? Outre la méthode brutale : ne pas exporter les fichiers à risque, il existe des méthodes qui permettent de sécuriser NFS : Secure NFS (http://www.cs.vu.nl/~gerco/SecureRPC/).
Encore beaucoup de travail pour les administrateurs systèmes... Sans compter tous les problèmes non évoqués et les attaques externes que nous aborderons le mois prochain !