Massive Attack : an overview on advanced DDoS mitigation cns at minithins.net Last Update > 07/03/2004 > ongoing JunOS 6.2 support, Cisco's uRPF and CAR fixed To Do > feed me with configurations for Foundry (ACL, rate-limit, AQM, CBAC-like, {black,sink}holing) http://www.foundrynet.com/services/documentation/ > DocBook translation (then make a big chunky html) "Semper ego auditor tantum ? Nunquamne reponam ?" Thomas de Quincey, De l'Assassinat considéré comme un des Beaux-Arts Résumé Cet article offre un aperçu - un instantané même - des méthodes les plus avancées, en cours de déploiement, d'expérimentation ou de développement, permettant de lutter contre les Distributed Denial of Service et même, parfois, d'identifier leurs auteurs. Ces techniques agissant soit directement sur le chemin, soit sur le management de queues, elles s'appliquent de facto à l'infrastructure réseau et en particulier aux routeurs, constituant le coeur du net, son squelette. Ce document se focalise sur le matériel Cisco mais abordera éventuellement d'autres systèmes, libres (*BSD, Linux, Zebra) ou propriétaires (Juniper, Foundry). Il est admis que vous connaissez au moins basiquement ces systèmes et que vous possédez une bonne compréhension du modèle TCP/IP et des disciplines d'évitement de congestion des implémentations TCP (New)Reno. La sécurisation complète d'infrastructure Cisco (pas uniquement contre les DoS) est par ailleurs résumée dans une présentation en [FIS02]. 1. Rappels 2. Path-oriented 2.1. ACL 2.2. RPF 2.3. Route filtering 2.4. {Black,Sink}hole 2.5. NBAR 2.6. iTrace 2.7. SPIE 2.8. IP Source Tracker 3. Exhaustion-oriented 3.1. RED 3.2. ECN 3.3. CAR 3.4. ACC 3.5. CBAC 3.6. TCP SYN Cookies 4. Conclusion 5. Références 1. Rappels Tout d'abord, quelques rapides rappels sur ce que sont les DoS et leurs différents types, qui ne cessent d'augmenter et de s'étoffer de jour en jour [CHAR]. Un Denial of Service ou DoS est une attaque destinée à limiter ou empêcher le bon fonctionnement, la disponibilité d'une machine. Les DoS agissent la plupart du temps par Ressource Starvation, c'est-à-dire qu'ils consomment un maximum de ressources (CPU, RAM...) de la machine attaquée afin de la rendre inopérante. Avec assez de ressources du côté attaquant, n'importe quelle machine est susceptible d'être victime d'un DoS par 'ressource starvation'. Mais il existe plusieurs méthodes permettant de faire beaucoup de dégâts avec peu de ressources. En premier lieu desquelles, et sans doute par ordre de célébrité, on trouve les smurfs. Les smurfs agissent à partir du protocole ICMP et des adresses IP broadcast. L'attaquant envoie un paquet ICMP echo request à une ou même plusieurs adresses broadcast (de préférence appartenant à des réseaux de classes B voire A) en usurpant l'adresse de l'hôte cible, ainsi les echo reply de la totalité des hôtes se trouvant derrière l'adresse broadcast (jusqu'à 65535 machines pour une classe B) répondront à la machine cible tous en même temps entraînant la situation de DoS. Le réseau de l'adresse broadcast agit ici comme réflecteur pour le DoS. Une autre méthode très répandue est le SYN flood. Elle exploite TCP en créant un nombre important de connexions semi-ouvertes dans un intervalles de temps restreint. Chaque segment TCP avec le flag SYN déclenche chez l'hôte cible la création d'un espace mémoire communément appelée TCP Control Block (TCB) contenant les informations relatives à la connexion. Une fois le SYN reçu, l'hôte renvoie un SYN/ACK puis attendant de recevoir un ACK afin de compléter le processus d'initialisation. Cependant, les segments du SYN flood auront été spoofé de sorte que l'hôte cible ne reçoive jamais de ACK en réponse et reste en état SYN-RECEIVED. La succession rapide de création de TCB remplissant les queues de connexions en état incomplet finit par consommer assez de mémoire pour ralentir ou stopper l'hôte cible. Une variation récente de cette attaque, appelée Naptha [NAP00], a été dévoilé. Le principe reste le même, à savoir la consommation des ressources mémoire par la création rapide d'un grand nombre de TCB. Mais afin de contourner les nombreuses parades qui ont été mise en place contre les SYN floods, le naptha tente d'initialiser complètement une connexion puis de laisser l'hôte cible en état ESTABLISHED après avoir envoyé un unique ACK après le SYN/ACK, ou en état CLOSE-WAIT après lui avoir un ACK suivi d'un FIN initialisant le four-way handshake de déconnexion. Pour éviter de consommer un TCB de son côté, l'attaquant doit ici réaliser une connexion en TCP blind spoofing. Ce dernier détail rend l'attaque bien plus complexe puisqu'elle nécessite la prédiction de Sequence Number TCP générés par des Pseudo Random Number Generator (PRNG). Cependant de récents travaux [ZAL01] sur l'utilisation des attracteurs étranges pour l'identification de patterns de génération pourrait faciliter la mise en application des napthas. Mais une condition de DoS peut aussi apparaître avec un faible nombre de paquets par exemple à cause d'une erreur dans une application. Ce cas de figure s'est par exemple présenté début 2002 dans BlackICE Defender, outil de sécurité réseau propriétaire. En interceptant un paquet ICMP similaire à un Ping of Death - c'est-à-dire légitime mais fragmenté et forgé de manière à être hors limite une fois réassemblé par le destinataire, causant crash ou ralentissement - crashait à son tour, entraînant parfois son hôte à sa suite. La faille, qui s'est finalement avérée être un buffer overflow, était ici due à un bug de gestion du trafic en sortie du driver propriétaire utilisé par BlackICE pour l'interception des paquets sous Windows 2000 et Windows XP. De même il y a quelques années existait le small footprint DoS, contre TCPdump et ses dérivés, consistant en un unique paquet avec les champs IP Version et IP Total Length mis à 0. Ces cas sont doublement dangereux puisqu'ils représentent des DoS applicatifs nécessitant une signature mais attaquent en plus les applications utilisant ces signatures. Ces types de vulnérabilités peuvent être spécifiques à un système, un logiciel, ou même une configuration particulière de plusieurs d'entre eux. Plus simple mais tout aussi destructeur, une attaque, semblable aux SYN flood que nous avons vus, peut être ciblé contre une machine ou un service critique dont la dégradation des performances entraînera un effet de bord assimilable à un DoS. C'est par exemple ce qu'à souligné un récent draft IETF sur la sécurité du protocole BGPv4 [MUR03]. Toutes ces méthodes peuvent aisément être combinées. Une dizaine d'année de cela, les ISP ont remarqué le développement inquiétant du phénomène de 'route flap'. Ce terme désigne le retrait et l'annonce successive et répétée de routes sur une courte échelle de temps. Chaque flap pousse le routeur à mettre à jour sa table de routage, causant une surcharge non néglibéable. D'autre part, les délais de convergence des routes au niveau global donnent aux flaps un impact important sur la stabilité du routage. En réponse, les organisations liées au routage ont rapidement déployée une proposition de Curtis Villamizar, résumée ensuite dans la RFC 2439 [2439], nommée route flap damping. Cette technique consiste à surveiller les retraits et réannonces, en ajoutant une pénalité à une route à chaque retrait. Lorsqu'on dépasse une certaine valeur de pénalité, c'est-à-dire qu'on observe un nombre de flap élevé sur une courte période, la route n'est plus utilisée ni annoncée pour une durée prédéterminée partant du dernier flap ; chaque flap redéclenchant le timer en augmentant le compteur de pénalité. En effet, ce compteur diminue en fonction du temps, tant qu'on observe plus aucun nouveau flap. Lorsqu'il repasse en-dessous d'un seuil de réutilisation, la route retrouve sa place dans les tables de routage. Le problème vient alors du fait qu'un attaquant peut très bien forcer une route à "flapper" pour subir des pénalités et donc disparaître d'Internet. Une vaste attaque coordonnée peut même complétement couper un réseau de ses voisins. Il suffit de lancer un flood sur le routeur, en particulier sur le port 179/tcp habituellement utilisé pour les sessions BGP. Le manque de ressources provoquera éventuellement des timeouts voire un reboot du routeur. Cette interruption des sessions, si répétée, sera rapidement assimilée à du flapping, et donc pénalisée. Le RIPE a publié un document très complet sur la bonne utilisation du damping [RIPE01] encourageant notamment l'utilisation des messages BGP du type REFRESH et des équivalents à la 'soft-configuration' de Cisco. Ces deux techniques permettent en effet de modifier une politique BGP sans nécessiter une réinitialisation de la session, potentiellement assimilée à du flapping. De même, le "proggressive damping" incite à pénaliser plus fortement les prefixes courts puisque les prefixes longs sont plus stables et leur suppression causerait, selon toute vraisemblance, plus de désagréments pour les utilisateurs. Cela revient concrêtement à encourager fortement l'agrégation des routes. Enfin, les serveurs racines DNS sont protégés et listés comme 'Golden Networks'. Malgré tout, ce type d'attaques combinées, entraînant un DoS en cascade, demeure réalisable pour qui dispose de connaissances et d'une organisation rigoureuse. La dernière classe de DoS que nous aborderons n'est pas réellement une méthode en soit mais plutôt un raffinement. Il s'agit de faire partir l'attaque non plus d'un unique hôte attaquant, mais d'une multitude de serveurs esclaves contrôlés par un client maître, potentiellement via plusieurs proxies. C'est ainsi que fonctionnent les outils Trinoo, Tribal Flood Network 2000 (TFN2k) et Stacheldaht dont vous pourrez trouver des analyses individuelles détaillées sur le site de Dave Dittrich [DITT]. Stacheldaht s'est rendu célèbre début 2001 lors des impressionnantes mais triviales attaques contre Yahoo!, CNN, eBay et bien d'autres. Ces outils agissent habituellement par une génération simple d'un grand nombre d'ICMP echo reply ou d'UDP echo sans grande finesse. Mais n'importe laquelle des attaques déjà décrites peut être appliquée à cette architecture distribuée, à laquelle on a attribué la dénomination DDoS pour Distributed Denial of Service. Ils nécessitent de plus le contrôle d'un nombre important de machines ce qui pousse leurs utilisateurs à l'intrusion massive, quasiment industrielle, allant jusqu'à exploiter des worms, comme ce fut le cas de Code Red II en 2001 dont chaque instance ciblait le site de la Maison Blanche. Outre les DoS massifs ou non, protocolaires ou applicatifs, il faut également remarquer une autre source involontaire mais néanmoins dévastatrice : les worms. Depuis 1988 et l'Internet Worm de Robert Morris, ces applications automatiques se propageant sur les réseaux au gré des vulnérabilités ont énormément évolués [PAX+02]. Ainsi les nouvelles concernant l'apparition de nouveaux worms se sont multipliés ces dernières années, et des noms comme Code Red et Nimda entre juillet et septembre 2001, ou Sapphire début 2003, sont désormais célèbres. L'analyse de ce dernier [WEA+03], a permis d'établir une classification entre Sapphire, restraint par la bande passante, et Code Red et Nimda de l'autre côté, limités par la latence. En effet, Sapphire, exploitant une faille SQL Microsoft, ne nécessitait qu'un unique paquet UDP de 404 octets, permettait une propagation rapide et aveugle. Le vers a ainsi pu contaminé 90% des hôtes vulnérables en 10 minutes, utilisant dans ce laps de temps énormément de bande passante : "[Sapphire] caused considerable harm simply by overloading networks and taking database servers out of operation. Many individual sites lost connectivity as their access bandwidth was saturated by local copies of the worm and there were several reports of Internet backbone disruption" [WEA+03] A l'opposé, Code Red et Nimda utilisaient des transmissions TCP et se trouvaient limités par la durée de synchronisation, imposée par le protocole via le three-way handshake, et les procédures d'acquittement. La vitesse de propagation étaient donc fonction des délais dans les réseaux. La quantité de mise en tampon - Code Red faisant 4ko et Nimda 60ko - a nécessairement dégradé ces délais et la fiabilité des transmissions. Malgré cela, une meilleure utilisation du multithreading aurait pu rendre ces vers tout aussi dévastateurs, du point de vue des DoS, que Sapphire, comme l'ont montré Paxson & al. en [WEA+03]. Plus particulièrement, Code Red I, attaquant les serveurs Microsoft IIS à l'instar de Code Red II et Nimda, se propageait par l'intermédiaire de 99 threads concurrents avec en plus un bug qui poussait un thread particulier à scanner la même séquence d'adresses IP, pouvant créer des situations de DoS vers ces adresses. Nimda quant à lui utilisait jusqu'à 5 vecteurs de propagation, du web au mail en passant par les partitions partagés, multipliant d'autant l'apparition de conditions de DoS pendant son expansion. Comme vous le voyez, le risque est omniprésent et nécessite donc une large protection. Notez cependant que les technologies présentées dans cet article ne concernent en aucun cas les attaques applicatives, du fait de leur spécifité. Les seules protections résideraient alors en un processus complexe d'audit permettant de dégager des signatures uniques. Celles-ci pourraient ensuite être éventuellement utilisées par un IDS pour détecter ces attaques, et parfois même les arrêter. Bien que le principe de contre-mesures soit encore bien peu développé dans le domaine de la sécurité, vous pouvez déjà trouver quelques exemples d'application dans les IDS Prelude et les développements de Snort tels Guardian, Hogwash ou encore FlexResp (ou même, dans une certaine mesure, Cisco Firewall IDS et NBAR, étudiés dans cet article). Cette catégorie d'outils intégrés étant désormais nommés Intrusion Prevention System. Nous nous intéresserons ici principalement aux technologies capables de détecter, prévenir ou identifier un DDoS. Elles doivent alors pouvoir s'appliquer à un réseau entier à travers le matériel en formant l'architecture. C'est à cause de cette optique généraliste que les technologies étudiées suivront le plus souvent un modèle anomaly-based et se baseront sur les statistiques. Les deux orientations que nous avons suivies pour notre étude sont l'identification et le contrôle des DDoS en fonction de leur chemin (path-oriented) ou en fonction de l'utilisation des ressources (exhaustion-oriented). La première partie accueille également les descriptions de plusieurs schémas d'identification de la source. Ce n'est pas seulement un élément utile lors de la phase de forensic mais également, devant le manque criant de mesures automatiques dans la lutte contre les DDoS, une source d'information essentielle à obtenir le plus rapidement afin d'appliquer des mesures réactives au plus près de la source. La seconde approche s'est quant à elle vu récemment confirmée dans un article évoquant la limitation des DoS par une surveillance stricte du Quality of Service (QoS) [RED+02]. 2. Path-oriented Les DoS ont toujours une source, qu'elle soit directe ou indirecte. Une solution évidente pour arrêter un DoS est tout simplement de bloquer les paquets vecteurs de condition de DoS. Cependant, lorsqu'on s'intéresse plus particulièrement aux DDoS, non applicatifs le plus souvent, les sources se multiplient et se falsifient plus aisément. Il dévient alors des plus ardus d'en identifier la source afin de constituer un agrégat capable de servir au pistage, dit traceback, ou au simple blocage. D'autre part, le protocole BGP, utilisé pour l'annonce de routes entre routeurs, offre certaines possibilités de configuration dangereuse, telles l'annonce de routes vers des adresses privées ou non allouées ainsi que, plus généralement, l'annonce de prefixes n'appartenant pas au réseau annonceur. Ces erreurs, intentionelles ou non, peuvent alors renforcer un DDoS en suscitant d'importantes quantités de messages ICMP host unreachable, éventuellement en supprimant toute possibilité de communication avec les prefixes illégalement annoncés. Nous observons donc que les DDoS viennent ne tirent pas seulement partie d'approximations dans le design des protocoles de niveau OSI 3 ou 4, mais également des erreurs de configurations de l'infrastructure réseau. Ces deux conditions réunies offrent aux DDoS la possibilité de résonner plus fort encore et de causer plus de dégâts. Dans cette première partie, nous allons donc nous intéresser en particulier aux procédés touchant à la caractérisation et au cheminement du paquet dans le réseau. Plus concrètement, cela indique une étude poussée des mécanismes liés au filtrage, blocage ou comptabilité du trafic. Les deux premiers permettent de restreindre ou supprimer complétement l'impact d'un DDoS en limitant ses capacités de résonance. Le dernier point, quant à lui, permettra de compenser à la fois les erreurs de design et de configuration pour réduire l'anonymité de l'attaque. Ceci aura pour effet de faciliter la prise de contre-mesures actives en identifiant cibles et attaquants, tout en rendant l'attaque moins aisée et séduisante à entreprendre. 2.1. ACL ACL, pour Access Control List, est le terme désignant les règles de filtrage sur les systèmes Cisco. Plus généralement, nous aborderons les techniques logicielles permettant, à un routeur ou un firewall, de filtrer le trafic selon agrégat. Les principales DDoS ne possédant pas de signature particulière ou bien facilement modifiable, la détection par pattern matching comme dans les IDS s'avère inopérante. Le filtrage dynamique brut contre un attaquant s'avère également peu utile puisque la bande passante en amont s'avère toujours utilisée. Ce point force d'ailleurs les responsables d'une infrastructure réseau à placer les protections le plus proche possible de l'attaquant, donc généralement au niveau des border routers. Mais la principale opposition au filtrage dynamique est tout simplement l'utilisation systématique du spoofing dans ces techniques. Pour limiter cela, quelques règles simples peuvent être appliquées. D'abord pour éviter que notre réseau ne serve de réflecteur pour un smurf, nous avons la possibilité chez Cisco d'interdire les réponses à un broadcast issue d'une adresse unicast. Notez que cette configuration est celle par défaut depuis IOS 12.0. router(config)#interface ethernet 0 router(config-if)#no ip directed-broadcast Nous allons ensuite filtrer plusieurs blocs d'adresses que nous savons attribuées à des réseaux privés non routables sur Internet, ou bien réservées à des usages expérimentaux. Cette politique de filtrage ingress est résumée parfaitement dans la RFC 2267 [1812][2267]. Plusieurs de ces adresses sont indiquées dans la RFC 1918 accompagnées de leur politique de routage comme ci-dessous "Because private addresses have no global meaning, routing information about private networks shall not be propagated on inter-enterprise links, and packets with private source or destination addresses should not be forwarded across such links. Routers in networks not using private address space, especially those of Internet service providers, are expected to be configured to reject (filter out) routing information about private networks. If such a router receives such information the rejection shall not be treated as a routing protocol error." Les blocs que nous filtreront selon la RFC 1918 sont : - 0.0.0.0/8 représentant une machine sans adresse ce qui ne doit pas exister - 127.0.0.0/8 représentant l'interface de loopback - 169.254.0.0/16 utilisé comme adresse d'autoconfiguration en cas d'échec avec DHCP - 192.0.2.0/24 réservé pour documentation et test - 192.168.0.0/16 ; 172.16.0.0/12 et 10.0.0.0/8 pour les adresses privées - 224.0.0.0/3 représentant des réseaux multicast de classe D notamment utilisé par OSPF et certains broadcast videos, et expérimentaux de classe E Pour plus d'informations sur l'assignation d'espaces d'adresses et même de numéros d'Autonomous System (privés de 64512 à 65535), référez vous aux RFC 1166 et 1466 et aux registres de l'IANA [IANA] sur l'adressage IPv4 listant plusieurs classes C. Enfin, fin 2002, l'IANA a souhaité résumé en un seul document ces contenus dispérsés au sein de la RFC 3330 [3330]. Nous ne nous sommes cependant pas appuyés sur les listes proposées et très régulièrement mises à jours par Cymru [CYMRU], du fait justement de l'instabilité de cette liste. Elle est cependant de plus en plus reconnue et digne de confiance. Elle est, de plus, accompagnée de configuration prête-à-l'emploir pour Cisco et Juniper. Sur les routeurs Cisco, nous allons configurer des access-list. Cette opération s'effectue en mode 'configure terminal' : router#configure Configuring from terminal, memory, or network [terminal]? Enter configuration commands, one per line. End with CNTL/Z. router(config)# La commande access-list se décompose de la manière suivante : access-list {permit | deny | remark} [log [log-input]] Number a la double fonction de numéroter l'access list, et donc par extension, l'access group, tout en spécifiant le type d'ACL souhaité. De 1 à 99 ce sont des ACL standards tout comme de 1300 à 1999 si cela ne suffit pas ; de même, de 100 à 199 et de 2000 à 2699, nous avons affaire à des Extended ACL. La liste n'est pas exhaustive, et vous en apprendrez bien plus en tapant : router#access list ? Nous utiliserons les EACL contrôlant la source, la destination, le protocole et le port. Les différents mots-clés qu'elles nous permettent d'utiliser sont les suivants : - 'permit' et 'deny' permettent de laisser passer ou de bloquer un paquet tandis que 'remark' permet de placer un commentaire - 'protocol' matche les paquets d'un protocole donnée (eigrp, gre, icmp, igmp, igrp, ip, ipinip, nos, ospf, tcp, ou udp) - 'source' correspond à l'adresse IP à bloquer, et 'source mask' à son masque de sous-réseau en notation inversée. En mettant ce champ à any, votre règle sera valable quelque soit l'adresse. - le champ suivant est constitué d'un opérateur 'lt' pour inférieur à, 'gt' pour supérieur à, 'eq' pour égal ou 'neq' pour différent, suivi du numéro de port source. L'utilisation de comparateurs permettra de filtrer selon une gamme de ports. - 'destination', 'destination mask' et 'destination port', sont équivalent aux champs précédents pour la destination - 'options' peut prendre pour valeur 'tos' (max-reliability, max-throughput, min-delay, min-monetary-cost, normal) ou 'precedence' (critical, flash, flash-override, immediate, internet, network, priority, routine) avec le protocole IP pour filtrer selon le ToS ou l'IP Precedence, respectivement. Mais vous pouvez également spécifier l'état 'established' pour TCP vérifiant ainsi la présence du flag ACK, ou bien, pour ICMP, la paire type/code ou simplement le nom du message. - Les derniers mots-clés coïncident avec les instructions de journalisation, soit 'log' pour une journalisation classique des informations du paquet, suivi éventuellement de 'log-input' pour ajouter à ces informations les adresses MAC et l'interface de réception. Notez qu'un paquet unique n'est enregistré qu'une seule fois toute les 5 minutes, les données journalisées se voyant alors complétées par un compter du nombre d'occurence. ------------------------------------ SNiP ------------------------------------- no access-list 101 ! filtrage selon les RFCs 1918, 1166, 1466 et 3330 access-list 101 deny ip 0.0.0.0 0.255.255.255 any log log-input access-list 101 deny ip 10.0.0.0 0.255.255.255 any log log-input access-list 101 deny ip 14.0.0.0 0.255.255.255 any log log-input access-list 101 deny ip 24.0.0.0 0.255.255.255 any log log-input access-list 101 deny ip 127.0.0.0 0.255.255.255 any log log-input access-list 101 deny ip 169.254.0.0 0.0.255.255 any log log-input access-list 101 deny ip 172.16.0.0 0.15.255.255 any log log-input access-list 101 deny ip 192.0.2.0 0.0.0.255 any log log-input access-list 101 deny ip 198.18.0.0 0.1.255.255 any log log-input access-list 101 deny ip 192.88.99.0 0.0.0.255 any log log-input access-list 101 deny ip 192.168.0.0 0.0.255.255 any log log-input access-list 101 deny ip 224.0.0.0 31.255.255.255 any log log-input access-list 101 deny ip 240.0.0.0 15.255.255.255 ant log log-input ! Bonus Track : Sun Microsystems cluster interconnects access-list 101 deny ip 204.152.64.0 0.0.0.255 any log log-input ! adresses internes arrivant depuis l'extérieur access-list 101 deny ip any log log-input ------------------------------------ SNiP ------------------------------------- Il ne reste plus qu'à appliquer cette configuration à votre routeur, sur l'interface de sortie, bien entendu : router(config)#interface ethernet 0 router(config-if)#ip access-group 101 in router(config-if)#^Z router#write Building configuration... [OK] router# Cette configuration est à appliquer sur l'interface externe en entrée. Mais elle peut - et même doit ! - s'appliquer tout aussi bien en output sur l'une des interfaces pour éviter de laisser fuir des adresses non-autorisées. Si vous êtes chargés de l'administration d'un réseau important, et remaquez que vos access-lists s'allongent de manière inquiètante pour les performances de vos routeurs, sachez qu'il existe une solution. En effet, depuis IOS 12.0(6)S, les ACL ont la possibilité d'être compilées, devenant ainsi des Turbo ACL. Le ruleset est remplacé par une structure de données, dites lookup tables, proche des tables de routage. Le parcours du ruleset est alors remplacé par des comparaisons avec entre les en-têtes de paquets et ces lookup tables. Le tout en conservant la règle du "first match win" (arrêt à la première équivalence entre un paquet et une règle) propres aux ACL Cisco. Il suffit, pour effectuer la compilation, d'entrée la ligne suivante : router(config)#access-list compiled La documentation Cisco [TACL] affirme que pour des rulesets de plus de 3 entrées, grâce aux lookup tables, la charge CPU et la durée de recherche de concordance sont désormais fixes, quelqu'eût été la taille du ruleset d'origine maintenant compilé. La compensation est une consommation supérieure à la normale de mémoire, de l'ordre de un Mo par access-group. Il devient alors capital de correctement grouper ses règles. D'autre part, si votre ruleset comporte des ACL de type reflexive, dynamique ou bornées dans le temps, celles-ci se verront exclues de la compilation. Ce genre de configuration peut créer des situations peu confortables ou ACL exotiques en liste et ACL classiques compilées fonctionnent parallèlement. Les Turbo ACL demeurent toutefois intéressantes pour obtenir un filtrage restrictif qui ne pénalise les opérations de routage à son profit. La commande 'show access-list compiled' propose des informations très complètes en particulier pour déterminer les règles exotiques qui n'ont pas pu être compilées. Celle-ci seront alors affichées par la commande accompagnées de la mention "Unsuitable" dans la colonne "State" : router#show access-list compiled Vous trouverez plus de détails sur les ACL en [RIP]. Sachez également, dans un souci d'interopérabilité, que la configuration et la syntaxe des ACL sont très similaires pour GNU Zebra [ZEBRA], le sous-système de routage libre le plus complet à ce jour. Pour aller encore un peu plus loin avec les technologies Cisco, sachez que vous disposez d'un des rares dispositifs intégrés liant IDS et firewall, au sein du Firewall IDS [FIDS], présent depuis IOS 12.0(5)T. Comme tout bon IDS, il inspecte chaque paquets ou sessions traversant le routeur, à la recherche d'analogies avec l'une de ses 59 signatures. Il est alors capable, en outre de la classique journalisation, de prendre des actions en réponses à une alerte afin de contrecarrer une attaque en cours, et ce de manière complètement automatisée. Pour les amateurs de Cisco jusqu'au bout des ongles, il sera même possible de l'intégré comme senseur du Secure IDS (c'est-à-dire NetRanger) et d'obtenir un système de journalisation des alertes centralisé. Les signatures utilisées sont basiquement hierarchisée, entre 'atomic' pour celles concernant un unique paquet et 'compound' lorsqu'on surveille une suite d'actions ou d'états (hierarchie interne au système), ou entre 'info' pour les actions de reconnaissances (généralement atomiques) et 'attack' pour les attaques complètes (plutôt compound). Les réponses, quant à elles, sont 'alarm' pour alerter via syslog, 'drop' pour rejeter le paquet et 'reset', reservé au transmission TCP, qui permet de terminer une connexion en envoyant un segment RST à chaque extrêmité. Vous pouvez tout d'abord configurer le comportement par défaut pour les deux types de signatures attack et info, c'est-à-dire une ou plusieurs des 3 actions présentées : router(config)#ip audit info action alarm router(config)#ip audit attack action alarm drop reset Comme notre sujet se concentre sur les DDoS, il est assez inutile de consommer des ressources au niveau des routeurs pour tenter de détecter toutes les attaques. Firewall IDS est en effet un gros consommateur de ressources, comme tout IDS ou firewall, à cause de la recherche de correspondances ou de la notification. D'autre part, il apparaît évident que 59 signatures sont bien peu de choses face aux nouvelles attaques découvertes chaque jour. Même si la volonté de Cisco était de constituer un système à jour, ce qui nécessiterait des mises à jour régulières, la méthodologie de mise à jour d'IOS deviendrait vite épuisante. Un IDS dédié sera plus à même de se consacrer à la détection d'attaques, disposant d'un ruleset certainement plus à jour. Heureusement, Firewall IDS offre la possibilité de désactiver des signatures. router(config)#ip audit signature {disable | list } Signature-id est un numéro d'identification d'une signature. Vous pourrez trouver la liste complète dans la documentation Cisco [FIDS] ou dans la NetRanger Network Security Database. Dans notre cas, elles seront toutes désactivées (disable) à l'exception des signatures 3050 (SYN flood), 2154 (Ping of Death) et 3106 (spam). La seconde option, list, permet d'attacher une signature à un numéro d'ACL. Mais cette opération sera de toutes manières réalisée par la commande suivante : router(config)#ip audit name {info | attack} [list ] [action [alarm] [drop] [reset]] 'ip audit name' permet d'attacher un type entier de signatures à une ACL, tout en définissant les actions à prendre. Ces dernières prendront le dessus sur la configuration par défaut. Vous trouverez ci-dessous un exemple d'application avec et sans couplage à une ACL. ------------------------------------ SNiP ------------------------------------- ! application sans ACL ip audit signature 1000 disable ip audit name reco info action alarm ! seules les Standard ACL sont acceptées ip audit name forged list 99 alarm drop reset access-list 99 deny 198.162.0.0 0.0.255.255 ------------------------------------ SNiP ------------------------------------- Remarquez que lier une règle d'audit et une ACL n'est absolument pas obligatoire. Cette méthode permet seulement, avec 'ip audit signature', de personnaliser totalement le set de signatures utilisées selon l'hôte ou le réseau, pour protéger ce qu'on appelle communemment des trusted hosts. Il ne reste plus alors qu'à attacher vos règles d'audit à une interface, comme pour une ACL : router(config)#interface ethernet 0 router(config-if)#ip audit {in | out} Typiquement, on attachera les règles dans le sens rentrant (in) pour une interface externe et dans le sens sortant (out) pour une interface interne. Notez que la règle 3106 se rapportant à la détection du spam nécessite une petite configuration supplémentaire. Elle se base en effet sur le nombre d'adresses mails contenues par le champ SMTP RCPT TO, c'est-à-dire le champ indiquant les destinataires. La valeur par défaut est 250, mais vous avez tous loisirs de l'ajuster de la manière suivante : router(config)#ip audit smtp spam 50 Enfin, pour la notification par la journalisation, vous avez également une marge de configuration permettant de définir son format (syslog par défaut). Ceci vous permettra par exemple d'adopter un format lisible en cas de notification distante vers NetRanger. Ci-dessous, la commande en question : router(config)#ip audit notify log [nr-director | syslog] Enfin, vous disposez des habituelles commandes d'afficage du sous-système, toutefois un peu plus complètes qu'à l'habitude pour le Firewall IDS. Outre l'afficache de la configuration globale, vous pouvez consulter la configuration par interface, ainsi que des statistiques d'utilisation : router#show ip audit configuration router#show ip audit interface router#show ip audit statistics Ces dernières peuvent être remises à zéro de la manière suivante : router#clear ip audit statistics Tandis que la configuration globale d'audit peut être supprimée avec la commande qui suit : router#clear ip audit configuration Bien sûr vous pouvez vouloir appliquer une protection minimale contre les paquets forgés, tirant parti d'adresses non routables, sans avoir un large réseau disposant de routeurs. Pour cela il vous suffit d'appliquer la même configuration à vos firewalls. Ci-dessous un exemple de configuration pour IPFilter [IPF] (et sans doute Packet Filter d'OpenBSD). Ce firewall existe sur de nombreux systèmes et le ruleset est aisément traduisible. ------------------------------------ SNiP ------------------------------------- # bloque et log les paquets avec les adresses sources suivante en entrée sur # l'interface fxp0, assumant que celle-ci est l'interface externe extinf=fxp0 us=/ block in log quick on $extinf from 0.0.0.0/8 to any block in log quick on $extinf from 10.0.0.0/8 to any block in log quick on $extinf from 14.0.0.0/8 to any block in log quick on $extinf from 24.0.0.0/8 to any block in log quick on $extinf from 127.0.0.0/8 to any block in log quick on $extinf from 169.254.0.0/16 to any block in log quick on $extinf from 172.16.0.0/12 to any block in log quick on $extinf from 192.0.2.0/24 to any block in log quick on $extinf from 192.18.0.0/15 to any block in log quick on $extinf from 192.88.99.0/24 to any block in log quick on $extinf from 192.168.0.0/16 to any block in log quick on $extinf from 204.152.64.0/24 to any block in log quick on $extinf from 224.0.0.0/3 to any block in log quick on $extinf from 240.0.0.0/4 to any block in log quick on $extinf from $us to any ------------------------------------ SNiP ------------------------------------- Afin de vous faciliter la vie, voici les mêmes règles traduites pour iptables, le firewall du projet Netfilter, disponible depuis Linux 2.4.x. ------------------------------------ SNiP ------------------------------------- # même principe, interface d'exemple eth0 EXTINF=eth0 US=/ iptables -A INPUT -i $EXTINF -s 0.0.0.0/8 -j DROP iptables -A INPUT -i $EXTINF -s 10.0.0.0/8 -j DROP iptables -A INPUT -i $EXTINF -s 14.0.0.0/8 -j DROP iptables -A INPUT -i $EXTINF -s 24.0.0.0/8 -j DROP iptables -A INPUT -i $EXTINF -s 127.0.0.0/8 -j DROP iptables -A INPUT -i $EXTINF -s 169.254.0.0/16 -j DROP iptables -A INPUT -i $EXTINF -s 172.16.0.0/12 -j DROP iptables -A INPUT -i $EXTINF -s 192.0.2.0/24 -j DROP iptables -A INPUT -i $EXTINF -s 192.18.0.0/15 -j DROP iptables -A INPUT -i $EXTINF -s 192.88.99.0/24 -j DROP iptables -A INPUT -i $EXTINF -s 192.168.0.0/16 -j DROP iptables -A INPUT -i $EXTINF -s 204.152.64.0/24 -j DROP iptables -A INPUT -i $EXTINF -s 224.0.0.0/3 -j DROP iptables -A INPUT -i $EXTINF -s 240.0.0.0/4 -j DROP iptables -A INPUT -i $EXTINF -s $US -j DROP iptables -A INPUT -i £EXTINF -j LOG -log-prefix "incoming pkts on extif:" ------------------------------------ SNiP ------------------------------------- Pour les programmes de DDoS, il ne sert à rien d'essayer de filtrer les ports de leur daemons et proxies puisqu'ils utiliseront en général pour communiquer des covert channels, tels que la célèbre paire ICMP echo request/reply. Pour utiliser un système similaire au Cisco Firewall IDS, vous pouvez utiliser Snort couplé à Guardian [GRD]. Ce dernier scan les logs Snort et, en cas d'alertes, exécute un shell script insérant une règle dynamique dans le firewall. Ce mécanisme fonctionne avec iptables, ipchains et ipfwadm sur Linux et ipfw sur FreeBSD. Cependant cette alternative est peu élégante et multiplie les possibilités d'erreurs ou d'abus, nous faisant préférer des systèmes intégrés comme Cisco IOS ou bien, en open source, Prelude IDS [PREL]. L'intérêt principal, dans le fait d'aborder le filtrage, est de donner un aperçu des capacités disponibles sur tous les systèmes récents. Vous disposez ainsi d'un moyen simple de vous protéger unilatéralement d'attaques par spoofing des plus basiques, ainsi que d'erreurs ou d'exploitation dans des configurations BGP laxistes. Toutes ces erreurs peuvent mener à des DDoS. 2.2. RPF Le Reverse Path Forwarding est une technologie initiée par Cisco, mais désormais largement répandue dans les développeurs d'infrastructure réseau et même cité en 1995 dans la RFC 1812 [1812], qui peut s'avérer très utile dans la lutte contre le spoofing. Cette vulnérabilité du protocole IP est en effet très liée aux attaques DDoS. En bloquant partiellement ou totalement la possibilité de faire entrer des paquets forgés dans un réseau, nous réduisons grandement l'exposition de ce réseau aux DDoS. Lorsqu'un paquet arrive sur une interface, RPF vérifie que l'interface ayant reçu ce paquet coïncide avec le plus court chemin du routeur à la source. C'est seulement à cette condition que le routeur pourra faire suivre le paquet. Dans le cas contraire, cela signifie que le paquet est illégitime (délibérément construit lors d'une attaque, ou bien issue d'une erreur de routage) et il est donc rejeté. Le Unicast RPF atteint ce but en recherchant le "best return-path", celui-ci étant défini par sa métrique. Lorsqu'un paquet arrive sur une interface, le routeur vérifie dans sa table de routage quelle serait l'interface de sortie pour un paquet dont la source correspondrait à la destination de celui qui est traité par RPF. Si la réponse correspond à l'interface d'arrivée du paquet examiné, alors celui-ci passe. Dans le cas contraire, il est rejeté. L'évaluation effectuée sur le paquet revient concrètement à déterminer si il est bien passé par l'interface correspondant au chemin le plus court. Le processus ainsi décrit est nommé strict mode. Il existe en effet un processus d'évaluation différent, appelé 'loose mode' qui ne fait plus le test de l'interface d'arrivée, mais se contente de vérifier qu'il existe bien, dans la table de routage, d'une route vers l'adresse source du paquet évalué. Remarquez que ce test est sous-entendu par le strict mode. Dans tous les cas, RPF agira comme un filtre vis-à-vis des routes non-existantes. En utilisant largement le loose mode, même au niveau du coeur de l'infrastructure, il devient alors possible de filtrer les paquets dont la source n'est pas allouée ou même privée, si la distribution des routes est filtrée correctement. Il existait en effet plusieurs limitations ennuyeuses à RPF. Tout d'abord, en cas de présence de routes par défaut sur une ou plusieurs interfaces, le comportement devient plus laxiste, puisque nous disposerons dans tous les cas d'une route vers l'adresse source. Le loose mode devient alors complétement inutile, et il se contente de laisser passer tous les paquets. Le strict mode conserve encore un peu de son utilité, mais il ne dépend plus que de la présence ou non d'une route par défaut pour l'interface d'arrivée du paquet évalué. D'autre part, RPF éprouve des difficultés face aux routes asymétriques inhérentes au processus de décision des protocoles de routage dynamique modernes, qui n'autorise à choisir qu'une seule et unique route vers une destination donnée. La conséquence est mineure à la frontière entre client et ISP qui n'est généralement constituée qu'un unique peering. Du point de vue de RPF, elle devient bien plus importante pour ce qui est des frontières entre plusieurs ISP, en particulier dans les Internet eXchange Point (IXP). Dans ces environnements spécifiques, il est courant de voir se développer des routes asymétriques entre flux ascendant et descendant par exemple. L'implémentation originale de RPF, qui correspond au strict mode, interdisait totalement son utilisation aux frontières ISP-ISP, sauf à définir explicitement des filtres protégeant les routes que l'on savait asymétriques du rejet par RPF. C'est également pour cela qu'a été développé le loose mode, qui enlève la barrière de la vérification d'interface, et permet un fonctionnement normal en presque toutes circonstances. On observe la première implémentation de Unicast RPF (uRPF) par Cisco dans IOS 11.1(17)CC [IOSRPF]. Celle-ci n'implémentait que le strict mode et ne prévoyait pas de traitement spécial contre le problème des routes par défaut. Sa configuration, par interface, s'avère très simple. Le seule pre-requis, comme pour toutes les implémentations de uRPF, est l'activation de la technologie Cisco Express Forwarding, CEF, afin de tirer parti de son design optimal pour le forwarding. L'exemple ci-dessous configurera l'uRPF en strict mode uniquement pour tous les IOS plus récents que la 11.1 ------------------------------------ SNiP ------------------------------------- ip cef ! strict mode incluant les routes par defaut interface ethernet 0 ip verify unicast reverse-path ------------------------------------ SNiP ------------------------------------- Cependant, comme nous le laissions entendre, Cisco a entièrement repenser uRPF en 2001, pour adresser les limitations que nous avons décrites. Barry Greene, à qui l'on doit de nombreuses innovations chez Cisco contre les DDoS, ainsi qu'une riche documentation sur le sujet, a écrit un white paper [GRE+01] énonçant clairement les problèmes motivant la reconception de uRPF et les solutions apportées. Le résultat est une nouvelle commande disponible cependant pour les routeurs de la série 12000 uniquement, avec IOS 12.0(22)S. Celle-ci permet de préciser si le test d'interface est effectuée (option 'rx') ou ignorée (option 'any'). Il permet également d'indiquer si les routes par défaut doivent être prises en compte ou non lors de l'évaluation, grâce à l'option 'allow-default'. Il est enfin possible d'autoriser le routeur à se pinger lui-même, ce que RPF interdirait en règle générale. Le patron [CNS] de la commande est donc le suivant : router(config-if)#ip verify unicast source reachable-via {rx | any} [allow-default] [allow-self-ping] [acl] Et l'exemple précédent revient à celui ci-après. ------------------------------------ SNiP ------------------------------------- ip cef ! strict mode incluant les routes par defaut interface ethernet 0 ip verify unicast source reachable-via rx allow-default ------------------------------------ SNiP ------------------------------------- Les deux commandes peuvent prendre en dernier argument un numéro d'ACL afin de permettre aux paquets échouant au test RPF de subir un traitement spécial. Par exemple, en ajoutant des règles 'permit', les paquets lui correspondant seront transmis quel que soit le résultat de RPF, tandis que 'deny' les rejettera toujours. Cette astuce vous permet également de loguer plus précisément les paquets évalués par RPF. Juniper a également très rapidement (dès la série JunOS 5.x) pourvu son système de la même fonctionnalité. La configuration de uRPF nécessite cependant quelques étapes supplémentaires. Il est tout d'abord nécessaire de l'activer globalement dans la hierarchie 'routing-options' de la CLI. Le point intéressant est que vous êtes alors en mesure de préciser si la vérification RPF doit s'effectuer contre les routes actives, c'est-à-dire en terminologie Juniper, installées dans le Forwarding Engine (en fait la FIB), ou contre les routes possibles, c'est-à-dire apprises par le Routing Engine (à travers les différents protocoles de routage dynamique). Le premier cas est appliqué avec la déclaration 'active-paths' et le second avec 'feasible-paths'. Le patron [JRPFR] de la commande est le suivant. ------------------------------------ SNiP ------------------------------------- [edit] routing-options { forwarding-table { unicast-reverse-path (active-paths | feasible-paths); } } ------------------------------------ SNiP ------------------------------------- Cette méthode règle efficacement la plupart des problèmes liés au routage asymétrique, et ceux sans réduire la protection offerte par RPF en passant en loose mode. Il ne reste plus qu'à configurer uRPF pour chacune de vos interfaces avec la déclaration 'rpf-check'. JunOS supporte parfaitement les deux modes tels que décrit théoriquement. De même, vous pouvez spécifier un 'fail-filter' à la commande 'rpf-check' pour spécifier un traitement spécial à certains paquets qui échoueraient au test RPF. Ce fail-filter est un firewall filter défini au même niveau hiérarchique que rpf-check. Le mode par défaut est strict mode. Pour spécifier le mode désiré, il suffit d'ajouter 'mode (loose | strict)' au même niveau que rpf-check. Les lignes ci-dessous sont le patron [JRPFI] de la commande. ------------------------------------ SNiP ------------------------------------- [edit] interfaces { fe-0/0/0 { unit 0 { family inet { rpf-check fail-filter ; mode (loose | strict); } } } } ------------------------------------ SNiP ------------------------------------- Devant l'intérêt suscité par cette fonctionnalité, il n'a pas fallu attendre longtemps pour en retrouver des équivalents dans le logiciel libre. L'importance d'une telle commande est de simplifier le travail de l'administrateur en remplaçant aisément les configurations complexes nécessaires auparavant pour atteindre le même but. En effet, sur tout firewall gérant correctement les opérateurs logiques, il sera possible d'écrire une règle empêchant tous paquets marqués d'une certaine adresse de passer par autre chose que l'interface à laquelle cette adresse est normalement attachée. Cette technique ne correspond pas à une réelle implémentation de l'algorithme RPF, mais reste intéressante. Par exemple, en suivant une syntaxe type IPF (ou PF), la configuration serait telle que ci-dessous (avec extif l'interface externe et subnet le réseau privé) : block drop in on !$extif inet from $subnet to any Depuis Linux 2.4, vous pouvez activer une telle fonctionnalité par interface via les variables disponibles dans /proc/sys/net/ipv4/conf/. Même si il est exprimé différemment, le raisonnement reste le même. Pour Linux, si l'interface par laquelle le paquet analysé est supposé quitter son réseau ne correspond pas à celle par laquelle il rentre, alors il est considéré comme invalide et rejeté. Clairement, cela revient à effectuer les mêmes vérifications dans la table de routage que celle exprimée dans le cas général. Pour l'activer dans une interface donnée, exécutez la ligne suivante : # echo "1" > /proc/sys/net/ipv4/conf//rp_filter Où 'interface' est à remplacer par le nom de l'interface. Pour étendre cette configuration à l'ensemble de vos interfaces, remplacez 'interface' par 'default" ou 'all'. Enfin, pour la rendre persistante, il vous faudra ajouter cette commande sous forme de script à /etc/rc.d/init.d/. Linux ne semble pas être en mesure de faire la distinction entre strict mode et loose mode, ce qui nous interdit de le placer à un autre endroit qu'à la frontière client/ISP. Pour détecter quels paquets sont effectivement rejetés, afin de corriger éventuellement une configuration indésirable, ajoutez également cette entrée : # echo "1" >/proc/sys/net/ipv4/conf//log_martians Pour étendre cette configuration, suivez les mêmes instructions que pour rp_filter. Plus de détails dans le Linux Advanced Routing & Traffic Control (LARTC) Howto [LARTC]. Pour ce qui est de FreeBSD, la ré-implémentation d'IPFW, sous le nom IPFW2, a vu l'ajout de deux mots-clés supplémentaires : verrevpath [VRP] pour le strict mode et versrcreach [VSR] pour le loose mode. Le premier est apparu à partir de FreeBSD 4.8 (avec l'option IPFW2) et FreeBSD 5.0 (avec l'option IPFW), tandis que le second existe à partir de FreeBSD 5.3 suite à la simple demande d'un utilisateur. Toutes deux font une évidente référence aux commandes RPF de Cisco. Le fonctionnement de ces deux options est strictement le même que pour Cisco ou Juniper, ce qui place FreeBSD au rang des systèmes adaptés aux infrastructures réseau. Pour chaque paquet correspondant à une règle 'verrevpath', IPFW vérifie, au sein de la table de routage, si l'interface d'arrivée du paquet coincide avec celle liée à la route vers l'adresse source du paquet. Par précaution, tous les paquets issus de la machine elle-même, ainsi que ceux qui ne possèderaient pas d'interface de sortie correspondante à leur adresse source, passe le test. Les règles versrcreach effectuent, pour leur part, le test RPF en loose mode. Le kernel se contente alors de vérifier si l'adresse source est simplement joignable par n'importe quelle route présente dans la table de routage, sans distinction d'interface. Une règle ipfw appliquant une vérification RPF stricte à tous les paquets entrant dans un réseau ressemblera à celle qui suit, avec extif représentant l'interface d'entrée : ipfw add 100 allow log all from any to any recv ${extif} verrevpath Il n'y a qu'à changer verrevpath pour versrcreach pour qu'IPFW utilise le loose mode et que cette configuration soit utilisable dans le coeur de l'infrastructure ou entre des ISP disposant de plusieurs peerings. Le dernier à suivre le mouvement fut OpenBSD, avec PF [PF]. Depuis la release 3.3, celui-ci dispose du mot-clé 'antispoof' sur lequel vous trouverez des informations complètes dans pf.conf(5) [MANPF]. La commande type IPF que nous avons vu plus haut, peut désormais être remplacée, dans pf.conf, grâce à antispoof, de la façon suivante : antispoof for $extif inet Outre la vérification qu'aucun paquet ayant pour source une adresse du réseau auquel est attachée une certaine interface (ici extif) ne sorte pas une autre, une seconde protection, spécifique à OpenBSD, est ajoutée en rejetant complétement tout paquet ayant pour source l'adresse de l'interface protégée. Elle remplace donc aussi la règle suivante, où 192.168.0.1 correspondait à l'interface protégée du firewall : block drop in inet from 192.168.0.1 to any Notez que les applications qui communiquent avec les interfaces locales via l'interface loopback peuvent se trouver perturbées, comme précisé dans la man page pf.conf(5). Pensez alors à ajouter une règle autorisant explicitement les transmissions depuis l'interface de loopback. Enfin, vous aurez certainement remarqué que bien qu'antispoof soit très utile, il ne représente en aucun cas une vraie implémentation de l'algorithme RPF. Elle permet cependant d'automatiser une vérification utile et, au final, apporte le même résultat. Par contre, tout comme Linux, OpenBSD ne comprend pas la différence entre loose mode et strict mode, le releguant aux bordures de réseaux ne possédant qu'une seule connexion entre eux. 2.3. Route filtering Poursuivant notre lutte acharnée contre le spoofing, il apparaît rapidement judicieux et nécessaire d'éviter simplement la possibilité de router un paquet apparemment forgé. En effet, les auteurs de spam et de DDoS disposent de plusieurs techniques permettant l'usurpation ou le détournement temporaire d'adresses afin de lancer leurs attaques. Un routeur malin peut ainsi servir à introduire dans la table BGP Internet globale des annonces de routes de courte durée vers des adresses privées. Dans la même veine, la désagrégation consiste à annoncer des routes plus spécifiques, c'est-à-dire d'une longueur de prefixe (en notation CIDR) plus grande, la rendant ainsi prioritaire dans le processus de prise de décision BGP pour l'installation d'une route. Afin de contrôler au plus près les annonces reçues et distribuées, Cisco (et, par extension, Zebra) dispose de plusieurs mécanismes à même d'effectuer un filtrage des routes propagées, via BGP, au niveau de vos routeurs externes, dits routeurs eBGP. Chaque réseau se voit attribué dans sa globalité un numéro d'AS (Autonomous System). La distinction entre routeur externe (eBGP) et interne (iBGP) se base alors sur les numéros d'AS utilisés pendant une session. Si'ils diffèrent entre deux routeurs voisins, nous nous trouvons en présence d'une liaison eBGP, c'est-à-dire entre deux réseaux, soutendant des modes de propagation de routes différents. Les méthodes décrites ci-après permettent de ne pas tenir compte de certaines annonces de routes en les filtrant simplement dès l'entrée de votre réseau. Ainsi, il n'y aura jamais aucune route, dans nos tables de routage, vers ces adresses. Les deux méthodes en question ont pour noms 'distribute-list' et 'prefix-list'. Bien que relativement redondantes, nous évoquerons les deux pour plusieurs raisons. Tout d'abord, elles sont mutuellement exclusive, ce qui signifie que vous ne pouvez en aucun cas les appliquer simultanément sur un même routeur. Il est même recommander de rester cohérent de d'utiliser la même technique à l'échelle de votre réseau. La différence majeure entre ces deux commandes demeure la catégorisation des informations. Dans un cas, 'distribute-list', il est fait appel aux ACL pour filtrer les adresses annoncées, tandis que 'prefix-list' utilise un mécanisme qui lui est propre. Les deux schémas se configurent de manière similaire en mode BGP config. Les distribute-list, présentes depuis IOS 10.0, comme toutes les innombrables options de la commande 'neighbor', pourront s'appliquer individuellement à chaque routeur voisin selon leur adresse IP, ou bien à tous les routeurs voisins définis au sein d'un peer group. Voyez la documentation Cisco [CBGP] pour de plus amples informations sur cette configuration très pratique. Une distribute-list est en réalité une simple invocation d'une Standard ACL contre laquelle les messages BGP seront testés. Pour appliquer une telle liste aux messages en provenance d'un routeur voisin, utilisez la commande suivante : router(config-router)#neighbor { | } distribute-list { | } {in | out} Comme vous le voyez, la commande est assez simple. Outre la définition du voisin ou du groupe de voisins auquel les ACL s'appliqueront, vous pouvez ensuite spécifier le numéro de ces fameuses ACL ou bien, à défaut, préciser le nom d'une prefix-list. La configuration finale, en reprenant les ACL vues à la section 2.1., ressemblera à l'exemple suivant. ------------------------------------ SNiP ------------------------------------- ! filtrage de route annoncées par le voisin d'adresse x.x.x.x neighbor x.x.x.x distribute-list 101 in ------------------------------------ SNiP ------------------------------------- La description des distribute-list a pu vous intringuer par la mise sur un pied d'égalité des ACL et des prefix-list. En effet, ces dernières, apparues seulement sur IOS 12.0, constituent un réel remplacement des ACL. Le but est de fournir une amélioration des performances pour ce qui est du chargement de la liste et des vérifications de validité des routes. D'après Cisco, l'objectif est atteint, en particulier lorsque l'utilisateur manipule des listes importantes. Le remplacement pur et simple des ACL a également conduit à quelques modifications dans le fonctionnement du filtrage. Ainsi désormais, une politique restrictive est appliquée par défaut, ce qui signifie que, dès lors qu'une prefix-list est activée, tout ce qui n'est pas expressement autorisé se voit implicitement rejeté, comme l'explique la documentation Cisco attenante. Un autre changement est intervenu dans l'ordonnancement des règles elles-mêmes. En lieu et place des numéros d'ACL, les règles des prefix-list sont désignées de manière unique par un numéro de séquence. Ces numéros s'incrémentent, par défaut, de 5 à chaque nouvelle règle. L'idée sous-jacente est de pouvoir ajouter des règles intermédiaires après coup, simplifiant la mise à jour de la liste. Cependant, désactiver cette génération automatique peut s'effectuer très simplement : router(config-router)#no ip prefix-list sequence number Il devient alors obligatoire de préciser le numéro de séquence de chacun de vos règles. Cette option restait possible dans la configuration par défaut, conservant l'incrément automatique de 5 entre une règle au numéro de séquence spécifié et une laissée au soin de la génération automatique. Cette opération est réalisé à travers l'option 'seq' de la commande 'ip prefix-list' qui suit : router(config-router)#ip prefix-list [seq ] {deny | permit} [ge ] [le ] Cette commande permet d'une manière générale de créer une liste (dont le nom remplace 'name') et d'ajouter des règles en spécifiant une adresse IP suivant de la longueur de son masque de sous-réseau, juste après avoir précisé l'action 'deny' pour rejeter la route ou 'permit' pour l'autoriser. Les options ge (greater-or-equal, >=) et le (lesser-or-equal, =<) sont des comparateurs permettant de définir des seuils pour le masque de sous-réseau. Un masque inférieur à 8 dénote par exemple une route très générale, et peut être considéré comme suspect. Appliquer une prefix-list à un routeur voisin peut s'effectuer, comme nous l'avons vu, par une distribute-list, ou bien par une option séparée de neighbor dédiée aux prefix list, bien qu'identique à distribute-list : router(config-router)#neighbor { | } prefix-list {in | out} La configuration finale, suivant les RFCs RFC 1918, 1166 et 1466, sera telle que celle ci-dessous. ------------------------------------ SNiP ------------------------------------- ! prefix-list 'rfc', avec seq automatique no preflix-list rfc ip prefix-list rfc deny 0.0.0.0/8 ip prefix-list rfc deny 10.0.0.0/8 ip prefix-list rfc deny 14.0.0.0/8 ip prefix-list rfc deny 24.0.0.0/8 ip prefix-list rfc deny 127.0.0.0/8 ip prefix-list rfc deny 169.254.0.0/16 ip prefix-list rfc deny 172.16.0.0/12 ip prefix-list rfc deny 192.0.2.0/24 ip prefix-list rfc deny 192.18.0.0/15 ip prefix-list rfc deny 192.88.99.0/24 ip prefix-list rfc deny 192.168.0.0/16 ip prefix-list rfc deny 204.152.64.0/24 ip prefix-list rfc deny 224.0.0.0/3 ip prefix-list rfc deny 240.0.0.0/4 ip prefix-list rfc permit any ! application au neighbor x.x.x.x de la liste 'rfc' router bgp neighbor x.x.x.x prefix-list rfc in ------------------------------------ SNiP ------------------------------------- Retenez qu'une troisième solution était encore possible, qui apporte une plus grande clarté dans la configuration, avec l'utilisation de route-map. En effet, ces dernières disposent comme match criteria de 'match ip address' acceptant des ACL ou des prefix-list. Dans tous les cas (distribute-list, prefix-list ou route-map) 'in' indiquera de filtrer les routes en provenance du voisin, tandis que 'out' appliquera une liste donnée aux annonces que votre routeur émet vers son voisin. Les deux configurations simultanées sont souhaitables. Plus de précisions, en particulier sur les commandes 'show' attenantes, sont disponibles en [CBGP]. Le routage BGP exige une certaine rigueur dans les configurations pour éviter d'annoncer n'importe quoi n'importe comment. Comme nous avons déjà pu l'évoquer, filtrer strictement les routes sortant ou entrant dans notre réseau permet de se prévenir de nombreuses situations assimilables à un DoS. Une configuration rejettant par défaut et autorisant explicitement (restrictive stance) permettrait quant à elle d'éviter une bonne partie des attaques tirant parti de configurations laxistes de la part des titulaires d'AS. En plus du filtrage des adresses "spéciales" que nous venons de voir, vérifiez toujours que vous n'annoncez effectivement que les préfixes sur lesquels vous avez une autorité. Et n'oubliez jamais que la sécurité tient une place primordiale dans l'amélioration de la qualité et de la continuité du service. 2.4. {Black,Sink}hole Au sein de l'infrastructure réseau, nous avons également la possibilité de définir un 'blackhole' [GRE02]. Un tel dispositif permet de faire totalement disparaître le trafic à destination d'une machine. Ainsi, lorsqu'un DoS est détecté, il suffit de "blackholer" la cible de l'attaque pour la protéger au niveau de l'infrastructure. Sous Cisco, cela correspondra à la définition d'une route statique sur nos routeurs, liant l'adresse de la cible et la pseudo-interface null0. Concrètement, l'invocation de null0, sur les routeurs disposant de la technologie CEF, implique une gestion particulière au sein de l'Adjacency Table, entraînant à son tour le rejet pur et simple des paquets transitant par la pseudo-interface. Il est alors intéressant de noter que les processeurs utilisés dans les routeurs Cisco sont optimisés afin d'être plus efficace dans des conditions de rejets que dans celles de forwarding. Il existe cependant quelques inconvénients intrinsèques aux blackholes. D'abord, la détection du DoS reste bien évidemment à la charge de l'administrateur réseau via un dispositif parallèle. Cela implique que le blackhole nécessite l'intervention manuelle du même administrateur pour être mis en place, réduisant, par ce délai, l'efficacité de la mesure. L'autre désavantage majeur est qu'aucune distinction ne peut être faite entre les paquets effectivement à l'origine du DoS et le trafic légitime. Outre que cette méthode se voit plutôt à des cas extrêmes et manifestes, dans lesquels une interruption temporaire du service est préférable, le blackhole se verra surtout utilisé ponctuellement afin d'identifier le point d'entrée de l'attaque dans le réseau à partir des messages ICMP unreachable, puis de placer sur ce point d'entrée des ACLs ou des politiques de limitation de débit (voir sections 2.1 et 3.3 respectivement). La technique que nous décrivons nécessiterait cependant la configuration de chacun de nos routeurs, travail ô combien fastidieux. Le bon sens nous indique donc d'utiliser BGP pour redistribuer les informations concernant le blackhole. L'idée est de préparamétrer sur tous les routeurs une route vers null0 attribuée à un bloc d'adresses inutilisé (très important puisque tous les routeurs rejetteront de fait les paquets de et vers ces adresses) tel qu'un bloc d'adresses RFC 1918. Attention dans ce cas aux interfaces sur lesquelles vous appliquez vos filtres distribute-list, afin de ne pas empêcher la redistribution de vos routes blackhole. La ligne suivante permet de lier le bloc choisi à une route vers null0 : router(config)#ip route 255.255.255.0 null0 Il est ensuite nécessaire de définir un routeur de moindre importance, dit 'blackhole server', depuis lequel nous définirons le blackhole et le propagerons par BGP à toute l'infrastructure. Cette étape sera réalisée, sous IOS, à l'aide d'une politique route-map. Celle-ci appliquera aux routes statiques locales affublées d'un certain tag un nouveau next-hop correspondant au bloc d'adresses inutilisé. Comme ce dernier est partout routé vers null0, tous les paquets appartenant à ces routes statiques locales seront supprimés. La route-map policy est de forme similaire à celle ci-dessous. ------------------------------------ SNiP ------------------------------------- ! on the blackhole server (configuration phase) in 'configure bgp' mode redistribute static route-map blackhole route-map blackhole permit 10 match tag 1337 set ip next-hop set local-preference 500 set community no-export set origin igp ------------------------------------ SNiP ------------------------------------- Bien que la commande route-map soit sans doute l'une des plus familière aux administrateurs Cisco, analysons cette séquence plus en détail. Le nom de la politique est 'blackhole' et son numéro de séquence (cf. ACL et filter-list) 10. Cette politique s'applique à toutes les routes statiques possédant le tag '1337'. Pour cette route, une série de 'set options' est alors prise. Le next-hop est remplacé par le bloc inutilisé sélectionné précédemment, la préférence locale est mise à 500 pour que la route vers le nouveau next-hop soit choisie à coup sûr comme best-path selon le processus de décision de BGP pour les routes de provenance interne (iBGP), le champ community est mis à no-export pour ne pas annoncer cette nouvelle route en dehors de notre AS (risque de blackhole complet de la part des peers), et enfin le 'BGP origin code' est 'igp' indiquant que la source est un routeur interne. L'application d'une politique route-map sur les routes reçues peut se faire soit sur la base d'une interface, soit pour un voisin (neighbor) désigné. Dans le premier cas, pour IOS, il faudra simplement entre en mode configuration interface : router(config)#interface ethernet 0 router(config-if)#ip policy route-map blackhole Dans le second cas de figure, il sera préférable de créer un groupe réunissant l'ensemble des routeurs internes et d'appliquer à toutes les routes reçues depuis ce groupe notre politique. Cette procédure s'effectue en mode configuration bgp pour IOS. ------------------------------------ SNiP ------------------------------------- neighbor peer-group neighbor route-map blackhole in neighbor remote-as neighbor w.x.y.z peer-group ------------------------------------ SNiP ------------------------------------- Dans cette séquence, nous créons un peer-group que nous nommons (en remplaçant pg-name) et dont les routeurs appartiennent à l'AS local puisqu'il regroupe les routeurs internes (remplacer AS par le numéro d'AS local), nous lui appliquons la route-map blackhole sur les routes entrantes, et enfin nous y ajoutons autant de routeurs que nécessaires (en iBGP entièrement connecté, sans réflecteurs de routes, cela correspond à la totalité des routeurs iBGP). Lorsqu'un DoS occure, il suffira alors de placer, sur le blackhole server, une route statique marquée du tag correspondant à la route-map policy, comme dans l'exemple qui suit, en remplaçant par la cible du DoS : router(config)#ip route 255.255.255.255 null0 tag 1337 Mais le mécanisme de blackhole permet également de remonter la source de l'attaque spoofée, ceci en journalisant les paquets ICMP * unreachable et l'interface qui les génère. Cela vous indiquera ainsi par déduction le point d'entrée du trafic spoofé dans votre domaine. Appliquer cette méthode à de larges échelles permettrait de remonter plus facilement la source d'un trafic spoofé en passant d'AS en AS. La journalisation s'effectue très simplement par les ACL : router#access-list 101 permit icmp any any unreachables log log-input Notez cependant que la redirection vers null0 risque de générer une forte quantité de messages ICMP unreachable. Afin de ne pas surcharger le routeur, il sera alors nécessaire de limiter le débit de ces messages - comme indiqué en section 3.3. de cet article - ou bien carrément de les supprimer totalement avec 'no ip unreachables'. Comme nous l'avons déjà rapidement abordé, la méthode originale de blackholing provoque un rejet complet du trafic à destination de la cible de l'attaque, incluant le trafic potentiellement légitime. BGP offre pourtant des attributs permettant d'identifier des chemins (path) distincts et donc de leur appliquer des règles différentes. Face à ce constat, une méthodologie améliorée de mise en oeuvre d'un blackhole est apparu en tant que draft IETF [TURK02]. Pour décrire ce raffinement du blackhole, nous prendrons un numéro d'AS d'exemple, 1337. L'idée est que chaque routeur dispose d'une politique route-map se déclenchant selon une valeur de l'attribut BGP community différente pour chaque routeur. Pour simplifier la lecture de nos configurations et aussi nous conformer à la RFC 1997 spécifiant le format de l'attribut community (AS:NN, où AS est le numéro d'AS et NN un nombre quelconque, chacun sur deux octets), entrez la commande suivante en mode de configuration globale : router(config)#ip bgp-community new-format Comme pour un blackhole normal, il faut s'assurer que les routeurs en bordure du réseau possède bien une route statique orientant le bloc inutilisé, servant de nouveau next-hop en cas d'attaque, vers la pseudo-interface null0 : router(config)#ip route 255.255.255.0 null0 Il est ensuite demandé de créer une AS-Path ACL permettant d'identifier les annonces BGP provenant bien de notre AS (1337). Ceci servira ensuite à empêcher un réseau externe d'utiliser nos valeurs de community pour blackholer n'importe quel réseau en envoyant des annonces qui déclencheraient notre blackhole amélioré. Il faut créer d'abord une ACL classique qui matchera tout le trafic, puis l'appliquer à une AS-Path ACL qui cherchera une correspondance (regexp) entre l'attribut AS et notre numéro d'AS. Dans le processus BGP, lorsqu'un routeur transmet une route, il y ajoute son numéro d'AS au début de l'attribut AS path, avant de transmettre l'annonce. 1337 sera donc recherché en tout début d'AS path, le reste important peu. ------------------------------------ SNiP ------------------------------------- access-list 1 permit ip any ! appliquez-la à toutes les interfaces interface ethernet 0 ip access-group 1 out ! 1337 doit se trouver au debut d'AS Path, peu importe ce vient ensuite ! voyez la documentation Cisco concernant les regexp ip as-path access-list 1 permit ^1337 .* ------------------------------------ SNiP ------------------------------------- L'utilisation de la valeur de l'attribut community parmis les match criterions de nos politiques route-map nécessite la création préalable de community ACL. Chaque routeur devant chercher sa propre community ainsi que celle englobant la totalité des borders routers, il existera deux règles dans la liste ; la première étant spécifique à chaque routeur. ------------------------------------ SNiP ------------------------------------- no ip community-list 1 ! la première ligne change pour chaque routeur ip community-list 1 permit 1337:01 ip community-list 1 permit 1337:411 ------------------------------------ SNiP ------------------------------------- Il ne reste plus qu'à installer sur chacun de nos border routers une politique route-map permettant de déclencher un blackhole à l'appel de sa valeur de community. C'est ici que l'on se rend particulièrement compte de l'intérêt de cette méthode par rapport à la précédente. Au lieu de voir tous les routeurs relayer la mesure de blackhole, seul le peer eBGP désiré le fait, laissant les autres routes supposées légitimes intactes. Une mesure de blackhole générale est cependant prévue par l'auteur de cette technique améliorée puisqu'il préconise d'installer également une politique route-map se déclenchant à la réception de la valeur de community correspondant à l'ensemble des routeurs eBGP (1337:411). Cette étape a été simplifié en utilisant un numéro de community-list englobant les deux valeurs community (une community-list se comportant comme une ACL). ------------------------------------ SNiP ------------------------------------- redistribute bgp route-map enhanced_blackhole route-map enhanced_blackhole permit 20 match community 1 match as-path 1 set ip next-hop set local-preference 500 set community no-advertise set origin igp ------------------------------------ SNiP ------------------------------------- En cas d'attaque, il ne reste plus qu'à annoncer, par l'intermédiaire de BGP, les routes vers la cible affublées de la valeur de community du peer eBGP identifié comme point d'entrée de l'attaque. Vous remarquerez cependant ici une lacune importante du draft. Celui-ci semble assumer que l'administrateur est capable d'identifier le routeur eBGP par lequel transite l'attaque. Non seulement ce postulat n'est pas évident dans la vie réelle mais, de plus, dans le cas d'une attaque distribuée (DDoS), les points d'entrée peuvent être assez nombreux. Il faudrait alors plutôt voir dans ce raffinement du blackhole un remplacement du filtering classique apportant, en outre, une capacité d'activation distante. La modification de la valeur de community nécessite de passer par BGP, donc par une politique route-map, à l'instar des route-maps utilisées pour la route statique null0 sur un serveur blackhole. Suivez la séquence de commandes suivante, en remplaçant 'ebgp_community' par la valeur de community du peer eBGP point d'entrée présumé de l'attaque. Retenez bien que nous voulons ici modifier la valeur 'community' d'une route statique annoncée aux autres peers, elle sera donc à appliquer en sortie. ------------------------------------ SNiP ------------------------------------- redistribute static route-map trigger_blackhole route-map trigger_blackhole permit 30 match tag 318 set community no-export : set local-preference 500 set origin igp ------------------------------------ SNiP ------------------------------------- Comme à votre habitude, lorsqu'un DoS est détecté, il suffira d'ajouter localement une route statique vers null0 pour déclencher le processus de blackhole : router(config)#ip route 255.255.255.255 null0 tag 318 De façon relativement récente, on a vu apparaître un raffinement supplémentaire au blackhole. Le principe en est succintement décrit dans le draft abordant la méthode de blackhole améliorée [TURK02] vue auparavant. Cette nouvelle technique, nommée sinkhole par analogie aux blackholes dont elle reprend une partie de la configuration, consiste, non plus à ré-annoncer une route donnée afin que tout le trafic vers sa destination soit supprimé, mais à la place à orienter ce trafic vers une installation dédiée à des fins d'analyse. Si nous sommes effectivement face à une attaque de type DDoS, il peut être nécessaire pour l'opérateur d'analyser le trafic d'attaque et d'en extraire le plus possible d'information avant, éventuellement, de le faire suivre à sa destination légitime, pour n'éveiller aucun soupçons. Dans une conférence [GRE+03] donnée au NANOG (North American Network Operators Group), Barry Greene comparait quant à lui les sinkholes aux honeypots. En effet, si vous décidez d'annoncer, depuis un sinkhole, des adresses supposées non-routables ou non-attribuées, vous obtiendrez un trafic exclusivement illégitime issue, par exemple, de scans manuels ou annoncant des worms. Vous le voyez donc, les sinkholes représentent des outils nouveaux dont le spectre d'utilisations est plus qu'intéressant. Ils peuvent ainsi se voir complexifier à volonté : d'une simple machine basée sur Zebra réalisant une classification par des ACL jusqu'à un vrai petit réseau d'analyse rassemblant plusieurs types de sondes (IDS, honeypot, firewall avec tarpit ou IPS, ...). La configuration est en soit très proche de celle d'un blackhole. Le système sera constitué d'un serveur, c'est-à-dire un routeur depuis lequel nous déclenchons le reroutage vers le routeur sinkhole, et de ce dernier. Sur le serveur, la configuration reste la même que d'habitude. ------------------------------------ SNiP ------------------------------------- redistribute static route-map trigger_sinkhole route-map trigger_sinkhole permit 40 match tag 374 set next-hop set community no-export : set origin igp ------------------------------------ SNiP ------------------------------------- La redirection vers le sinkhole se fait encore une fois via une route statique affublée du tag correspondant à notre route-map : router(config)#ip route 255.255.255.255 null0 tag 374 La configuration du sinkhole s'effectue également comme les autres avec une route-map applicable sur la base d'une interface ou bien des échanges avec un voisin (neighbor) ou groupe de voisins (peer-group). La route-map sera très simple, et ressemblera à celle ci-dessous, en remplaçant analysis par l'IP de l'interface connectée réseau d'analyse. ------------------------------------ SNiP ------------------------------------- route-map sinkhole_redirect permit 50 match community : set ip next-hop ------------------------------------ SNiP ------------------------------------- Il faudrait alors faire correspondre cette IP à ladite interface, par laquelle tout le trafic sera redirigé : router(config)#ip route 255.255.255.255 interface ethernet 0 Le routeur va alors tenter plusieurs requêtes ARP afin de trouver le destinataire final du trafic qui devrait, selon toute vraisemblance, lui être attaché à la sortie de la route statique. Comme ce n'est pas le cas et que nous voulons simplement transmettre le trafic via cette interface pour qu'il soit analysé avant d'être forwardé, nous ajoutons une entrée ARP statique fausse (fake MAC address) dans le cache de notre routeur sinkhole, 'arpa' désignant le type de l'adresse, ethernet : router(config)#arp arpa La réelle difficulté dans la mise en place d'un sinkhole viendra plus probablement de l'installation d'un réseau d'analyse passif derrière la passerelle sinkhole. En lieu et place d'une cible soumise à un DDoS, nous aurions pu créer une route statique vers des espaces d'adresses invalides ou réservées. C'est de cette configuration qui permet de transformer le sinkhole en routeur puisqu'ainsi, nous redirigeons pour analyse un trafic qui est purement illégitime, qu'il soit malicieux ou issue d'erreurs de configuration. Mieux encore ! le réseau d'analyse n'étant qu'un simple brin ethernet dépourvu du moindre adressage ou routage - un simple switch permettra de dupliquer le trafic pour chaque senseur - nous pouvons ajouter un routeur à la sortie de ce réseau en le chargeant de diriger le trafic analysé vers sa destination originelle. Lorsqu'une attaque est détectée, nous faisons transiter le trafic par le sinkhole et son réseau d'analyse de manière complétement transparente avant de le rediriger vers sa destination originelle. Le seul danger viendra du nombre de hops rajoutés. Il est également capital de bien configurer les ACL bornant le réseau d'analyse. Si celles-ci laissent passer le moindre trafic, le sinkhole devient totalement inefficace et perd tout son intérêt. Il faut de plus les créer de façon suffisament fine pour qu'elles puissent servir également à la comptabilité des données transitant, en sus des sondes spécialisées. Il a été fait état de bien d'autres utilisations des sinkholes encore. L'une d'elle en particulier, même si elle peut s'avérer relativement coûteuse à mettre en place à cause de sa complexité et de la difficulté de sa maintenance, est des plus prometteuses pour la protection des routeurs eux-mêmes. Les protocoles de routage peuvent se regrouper généralement en deux groupes distincts selon l'interface qu'ils voudront utiliser. On trouve des protocoles loopback (utilisant leur adresse de loopback avec une configuration multihop) et des protocoles adjacents nécessitant une connectivité directe. La question est alors de savoir si vos routeurs internes d'importance stratégique nécessitent réellement un accès multihop, le rendant plus vulnérable depuis l'extérieur. Imaginons alors un backbone composé de routeurs directement connectés ; si nous utilisons un sinkhole annonçant - via un IGP, c'est-à-dire uniquement pour les autres routeurs directement connectés, qui prendront ainsi le pas sur toute autre type d'annonce - les adresses des interfaces directement connectées depuis celles des interfaces non connectées, nous pouvons alors éloigner toutes attaques directes contre ces routeurs. N'oubliez pas qu'un sinkhole empêche le moindre paquet d'échapper au sinkhole, de même qu'il n'est qu'un réseau (ou une machine) passif et distinct du routeur. Vous protégez d'un seul coup vos routeurs contre l'identification par des mécanismes fonctionnant sur le modèle de traceroute, mais également les attaques depuis le réseau interne qui n'aurait donc pas pu être filtrée par les ACL en bordure de réseau, et enfin contre les attaques DoS par réflexion. Si un attaquant lance un paquet broadcast spoofant l'adresse de l'un des routeurs disposant du sinkhole que nous avons décrit, ce paquet atteindra sa destination, mais sa réponse - qui entraînerait un DDoS - est irrémédiablement aspirée par le sinkhole. Dans toutes les techniques vues précédemment, gardez à l'esprit que la propagation d'une route peut être affinée. Par exemple, selon l'application de vos politiques route-map sur une interface ou pour tous les voisins, la route se verra distribuée uniquement aux routeurs en amont ou bien plus largement. Ces variations de configuration dépendront également de la manière dont vous introduisez des routes : au niveau du *hole routeur ou bien via un routeur serveur distinct. Encore une fois, ne sont présentés ici que des exemples, l'expérimentation réfléchie est la meilleure façon d'apprendre. Vous le voyez, les blackholes et les sinkholes sont des techniques aux applications multiples qui n'ont pour limite que l'imagination des administrateurs. Faire des essais avec ces techniques est le meilleur moyen de les apprivoiser et d'en affiner la configuration. Ils sont réellement l'évolution, à l'échelle du réseau, des techniques de sécurité développées ces dernières années, du firewall au honeypot. A la fois en tant que méthode de filtrage à l'efficacité redoutable (blackhole) ou comme technique d'analyse, d'identification et de protection (sinkhole), elles sont réellement capitales pour la défense d'un réseau relativement important face aux DDoS. Le projet Guardian, offrant des scripts de filtrage réagissant à des alertes Snort, dispose, quant à lui, d'un script équivalent null0 pour Linux. Ce dernier est cependant considéré comme peu stable, aussi bien par l'auteur que par la communauté. De plus amples informations, en particulier pour les matériels Juniper, sont à votre disposition en [UUBH]. 2.5. NBAR A partir da la version 12.0(5)XE2 d'IOS, Cisco propose une nouvelle technologie propriétaire nommée NBAR, pour Network-Based Application Recognition [NBAR]. La problématique initiale à laquelle cette fonctionnalité vient répondre est due à l'augmentation du nombres de protocoles induisant des spécificités nécessitant une gestion particulière au niveau d'un quelconque classificateur de paquets. Pour chaque protocole nouveau dans la couche OSI application, l'utilisation grandissante de canaux de contrôles et de données séparés ainsi que de ports dynamiques, ou encore les échanges basées sur la reconnaissance et la mémoire d'états, requièrent en effet une connaissance plus intime de chaque protocole afin de pouvoir gérer au mieux ses accès et ses limitations. NBAR est donc, au départ, une initiative destinée à étendre l'application de politiques de QoS à divers protocoles spécifiques de cette couche application, comme ceux utilisés lors d'appels de procédure distants (RPC, SQL, LDAP, ...), les applications multimedia (RTP, H.323, même IRC) ou de simples protocoles d'échanges de données (FTP, HTTP, ...). Quant à nous, nous exploiterons les possibilités de NBAR pour reconnaître quelque signatures de DDoS protocolaires connues (en particulier le cas des DDoS induits par des worms) pour ensuite lui appliquer des limitations strictes telles celles présentées dans cet article (ACL, CAR, blackhole). Comme c'est le cas de nombreuses technologies spécifiques à Cisco, les informations publiques ne donnent que peu d'informations sur le fonctionnement interne de telle ou telle fonctionnalité. Ainsi, il est fait mention d'un algorithme de Protocol Discovery permettant de classifier les données traitées en protocoles de couche 4 à 7. Cet algorithme se base sur plusieurs indices très variés. Il examine tout d'abord les ports TCP ou UDP afin de vérifier s'il ne correspond pas à un service connu pour utiliser ce port. Cette première étape n'est pas plus efficace qu'un administrateur système entrant manuellement des ACL de classification pour les ports usuels des services qu'il souhaite analyser et traiter. Il existe donc toute une batterie de tests supplémentaires consistant en une analyse exhaustive de chaque paquet. C'est cette capacité d'analyse exceptionnelle qui est effectivement appelée Protocol Discovery. Cet algorithme est capable d'identifier des protocoles fonctionnement sur des ports TCP ou UDP alloués dynamiquement en reconnaissant le protocole par la construction particulière des données (en particulier les en-têtes) ainsi que la forme des échanges. C'est également l'approche en vogue dernièrement dans le domaine des IDS avec, en particulier, les productions de Robert Graham (autrefois BlackIce, racheté depuis par ISS). Mais il sait également utiliser des expressions rationnelles (regexp) pour retrouver certaines chaînes de caractères biens spécifiques dans le contenu TCP. Cependant, certainement pour des raisons de vitesse et d'utilisation mémoire, ce type de recherche est limitée au 400 premiers octets du payload. Outre ces mesures génériques, NBAR offre l'intérêt de proposer des gestions particulières pour certains protocoles complexes ou très intéressant à traiter. Nous noterons en particulier la gestion des protocoles HTTP, RTP, ainsi que FastTrack et Gnutella. Pour le premier, il sera possible de créer des configurations NBAR basées sur l'identification des URL, hostnames et même type MIME (jusqu'à 24 occurences concurrentes, puisqu'il est ici aussi question de regexp), sans jamais se baser sur les ports usuels, offrant une souplesse et une fiabilité supplémentaire. Pour RTP, protocole utilisé de streaming il est possible de faire la distinction entre un flux audio ou vidéo - l'analyse protocolaire ne couvrant pas RTCP, le canal de contrôle allant de paire avec RTP (comme FTP et FTP-DATA). Enfin, FastTrack et Gnutella sont les deux protocoles de peer-to-peer supportés par NBAR. Le premier est par exemple utilisé par KaZaa tandis que le second est exploité par de nombreux clients comme LimeWire ou Gnucleus. Ils sont si répandus que les protocoles alternatifs sont souvent basés dessus permettant, avec le support de ces deux-là uniquement, de couvrir l'immense majorité des échanges P2P. La gestion particulière permettra ici de créer des configurations NBAR basées sur les noms des fichiers échangés. Enfin, même si Cisco conserve le monopole de la création des fichiers de descriptions de protocoles, il existe une commande afin d'ajouter un support succint pour des protocoles supplémentaires. Son format est le suivant : router(config)#ip nbar custom { } {source | destination} {tcp | udp} {range | } Comme vous l'avez sans doute devinez, l'identification ne peut s'effectuer que par des critères de recherche très limités. Au premier rang desquels on trouve la recherche d'occurence située à 'offset' (de 256 octets maximum par rapport au début du paquet), le format de recherche ('ascii', 'hex' ou 'decimal') et enfin la valeur recherchée dont la longueur maximale varie seulement le format de recherche (16 caractères ASCII, 4 octets en hexadécimal ou 4 octets en décimal). Ensuite, vous pouvez éventuellement spécifier la direction du flux, ce qui revient à indiquer si les numéros de ports à rechercher sont les ports 'source' ou 'destination'. Vous indiquez alors le type de protocole de transport ('udp' ou 'tcp') avant de finalement spécifier un espace de ports borné par un nombre de départ et de fin, en sus ou à la place de un à 16 ports statiques. Comme nous l'avons brièvement évoqué, Cisco tient à conserver le monopole de l'ajout de descriptions de protocoles à l'algorithme de Protocol Discovery. Ces descriptions sont réunies dans un Packet Description Language Module (PDLM) permettant certes l'ajout de nouveaux protocoles sans un flashage complet d'IOS mais dont l'aspect totalement propriétaire et fermé coupe Cisco d'une belle occasion d'obtenir un support communautaire bénévole susceptible d'étendre de manière importante les capacités et donc le succès de NBAR. D'autre part, NBAR connait plusieurs inconvénients qui peuvent s'avérer très dommageables. Le moins sévère est l'impossibilité de gérer les requêtes HTTP/1.1 dites 'pipeline', c'est-à-dire le cas de figure où plusieurs requêtes sont envoyées groupées. Même si ce détail n'est pas capital, il laisse planer des questions sur la fiabilité de la gestion particulière de HTTP puisqu'il peut signifier que NBAR a besoin d'au moins un échange complet pour classifier un flux HTTP, ouvrant la porte à des tentatives d'évasion. D'autre part - et c'est encore plus grave du point de vue de l'évasion - la fragmentation n'est pas supportée. Ce détails, résolus par les IDS depuis fort longtemps sans atteintes notables aux performances, empêche NBAR d'être un candidat idéal pour la classification des données du point de vue de la sécurité. Enfin, mais c'est là le lot de tous les dispositifs d'analyse "en ligne", des flux asymétriques induits par l'architecture de routage empêcheront NBAR d'effectuer la moindre analyse, semblant indiquer encore que NBAR nécessite un échange complet (comme la plupart des fonctionnalités similaires, encore une fois). La question des performances est quant à elle amplement détaillée par Cisco (et plus ou moins confirmée sur plusieurs mailing-lists). NBAR apparaît ainsi induire une augmentation de l'utilisation du CPU de 20% en plus d'une consommation de 150 octets par flux appelant un suivi d'états. Un emplacement mémoire de 1Mo (soit environ 5000 flux concurrents) est allouée une première fois, puis étendu si besoin est par tranche de 200 à 400 octets. Venons au fait ! Grâce à ses capacités de reconnaissance de protocole ainsi que la souplesse d'interfacage avec des ACL ou des règles de QoS, NBAR va nour permettre d'identifier des flux applicatifs susceptibles de causer un (D)DoS et de les réprimer. Etudions tout d'abord une configuration NBAR typique. Le Protocol Discovery s'active séparemment pour chaque interface comme c-après : router(config)#interface router(config-if)#ip nbar protocol-discovery Nous allons maintenant créer une class-map qui définira les protocoles que nous souhaitons surveiller. Une class-map peut contenir un ou plusieurs critères de correspondance. Dans le cas d'une liste de critères, vous pouvez choisir si vous désirez définir votre class-map pour les paquets contenant tous ces critères (match-all) ou seulement l'un d'eux (match-any), selon la même différence qu'entre un ET et un OU logique. L'exemple suivant créé une classe 'test' surveillant les protocoles HTTP et SMTP, où seul l'un des deux protocoles suffit pour qu'un flux soit géré par cette classe. router(config)#class-map match-any test router(config-cmap)#match protocol http router(config-cmap)#match protocol smtp La classe de trafic ainsi définie doit alors être liée à la structure définissant les politiques de QoS, une policy-map. Celle-ci comprendra le nom de classe de trafic qu'elle contraindra, suivi de une ou plusieurs commande QoS, comme dans l'exemple ci-dessous, toujours avec la classe 'test'. router(config)#policy-map test router(config-pmap)#class test router(config-pmap-c)# ! entrez ici vos commandes QoS Enfin, la policy-map résultante (ici encore 'test') est elle-même attachée à une interface, pour être appliquée en entrée ou en sortie. router(config)#interface ethernet 0 router(config-if)#service-policy [input | output] test L'utilisation de NBAR dans une optique sécuritaire se base entièrement sur les commandes QoS disponibles avec policy-map et les opérations qu'elles nous permettent d'effectuer. Notre premier exemple utiliser le rate-limiting (voir section 3.3.) pour limiter le débit d'un type de trafic particulier via la commande 'police'. Pour reprendre la configuration classique NBAR, il faudra d'abord créer une class-map identifiant le trafic incriminé. Pour reprendre des exemples existants et simplifier les démonstrations de configuration, nous utiliserons les vers Code Red et Nimda qui utilisaient notamment des vulnérabilités contre les services ISAPI du serveur HTTP Microsoft IIS 4.0 et 5.0. L'attaque était relativement simple à détecter puisqu'elle se traduisait le plus souvent par une invocation à une DLL nommée idq.dll, via le fichier default.ida. Nous pouvons donc rechercher cette dernière chaîne de caractère dans les URL, grâce à NBAR. C'est ce que nous faisons avec la classe 'worms' ci-dessous, la chaîne de caractère étant une regexp entre guillemets. router(config)#class-map match-any worms router(config-cmap)#match protocol http url "*default.ida*" router(config-cmap)#match protocol http url "*cmd.exe*" router(config-cmap)#match protocol http url "*root.exe*" Nous appliquons alors une limitation en débit grâce à la commande 'police' dans une policy-map nommée 'worms-policed'. Ici, nous avons pris l'exemple d'un lien ethernet 10 mbps. router(config)#policy-map worms-policed router(config-pmap)#class worms router(config-pmap)#police 6000 900 1500 conform-action transmit exceed-action set-dscp-transmit 2 violate-action drop Poursuivez ensuite la configuration NBAR comme décrit plus haut. La méthode ainsi réalisée est la plus simple pour ce qui est de la syntaxe. Pour utiliser de véritables Committed Access Rate (CAR) et donc la commande rate-limit, nous passerons par un autre schéma de configuration. Au lieu d'utiliser directement les QoS commandes disponibles au sein d'une policy-map, nous utiliserons celle-ci pour marquer les paquets incriminés d'une certaine valeur dans les différents champs IP QoS disponibles (IP Precedence, Quality-of-Service, DiffServ Codepoint). Pour cela, nous réutiliserons la même class-map, mais modifierons la policy-map de la manière suivante : router(config)#policy-map worms-cared router(config-pmap)#class worms router(config-pmap)#set ip dscp 1 Dans ce cas particulier, tous les paquets classés comme appartenant à un flux HTTP dangereux verra son champ DSCP (DiffServ Codepoint) mis à 1. Il pourra ainsi être reconnu dans la suite du processus de forwarding et traité en conséquence. Cette particularité nécessite cependant une configuration plus rigoureuse. Jusqu'à maintenant, le choix de l'interface sur laquelle appliquer notre policy-map était conduit uniquement par le désir de limiter le trafic dans le sens ascendant ou descendant. Pour avoir une configuration plus lisible et moins sensible aux erreurs, nous placerons désormais nos policy-map sur l'interface d'entrée/externe (appelée ethernet 0) pour classer le trafic, et nos actions sur l'interface de sortie/interne (appelée ethernet 1). Dans les cas où vous avez plusieurs commandes à appliquer sur une même interface, référez à l'excellente documentation pour vérifier l'ordre d'opération [OP]. Par exemple, les ACL sont traitées avant les CAR qui sont traitées avant 'police'. router(config)interface ethernet 0 router(config-if)service-policy input worms-cared Après cela, nous appliquons donc notre action, ici la commande 'rate-limit', en sortie, grâce aux lignes suivantes : router(config)#access-list 103 permit ip any any dscp 1 router(config)#access-list 103 permit ip any any router(config)#interface ethernet 1 router(config-if)#ip access group 103 out router(config-if)#rate-limit output access-group 103 6000 900 1500 conform-action transmit exceed-action drop La configuration finale est résumée ci-dessous. ------------------------------------ SNiP ------------------------------------- ! class-map 'worms' class-map match-any worms match protocol http url "*default.ida*" match protocol http url "*cmd.exe*" match protocol http url "*root.exe*" ! policy-map 'worms-cared' policy-map worms-cared class worms set ip dscp 1 ! interface d'entrée interface ethernet 0 service-policy input worms-cared no access-list 103 access-list 103 permit ip any any dscp 1 ! interface de sortie interface ethernet 1 ip access group 103 out rate-limit output access-group 103 6000 900 1500 conform-action transmit exceed-action drop ------------------------------------ SNiP ------------------------------------- Nous pouvons utiliser exactement le même schéma que pour 'rate-limit' avec des ACL pour simplement rejeter le trafic marqué au lieu de le limiter. Il suffira de reprendre la même configuration que précédemment en retirant la ligne sur rate-limit et en changeant 'permit' en 'deny' dans l'ACL correspondant aux paquets marqués. La configuration résultante sera alors telle que ci-dessous. ------------------------------------ SNiP ------------------------------------- ! class-map 'worms' class-map match-any worms match protocol http url "*default.ida*" match protocol http url "*cmd.exe*" match protocol http url "*root.exe*" ! policy-map 'worms-dropped' policy-map worms-dropped class worms set ip dscp 1 ! interface d'entrée interface ethernet 0 service-policy input worms-dropped no access-list 103 access-list 103 deny ip any any dscp 1 access-list 103 permit ip any any ! interface de sortie interface ethernet 1 ip access group 103 out ------------------------------------ SNiP ------------------------------------- Enfin, nous pouvons réutiliser les configurations étudiées lors de la section 2.4 pour rejeter les paquets avec de meilleures performances, ou simplement les détourner pour analyse. Le début de la configuration étant toujours le même, nous ne décrirons que la partie qui change. ------------------------------------ SNiP ------------------------------------- ! class-map 'worms' class-map match-any worms match protocol http url "*default.ida*" match protocol http url "*cmd.exe*" match protocol http url "*root.exe*" ! policy-map 'worms-nulled' policy-map worms-nulled class worms set ip dscp 1 ! interface d'entrée interface ethernet 0 service-policy input worms-nulled no access-list 104 access-list 104 permit ip any any dscp 1 access-list 104 permit ip any any route-map worms-nulled 10 match ip address 104 set interface null0 ! interface de sortie interface ethernet 1 ip access group 104 out ip policy route-map worms-nulled ------------------------------------ SNiP ------------------------------------- Nous avons simplement repris les EACL de classification précédentes, qui ici ne rejettent aucun paquet, puis nous avons ajouter une route-map appelée 'worms-nulled' qui va créer une route vers null0 pour les paquets correspondant à nos EACL. Ces EACL et la route-map sont alors appliquées à l'interface de sortie. Notez que dans le sens sortant (outbound), les ACL seront bien examinées avec la route-map, permettant la concordance entre les deux. Les trois approchent que nous avons décrites (CAR avec police ou rate-limit, EACL simples, et enfin null0) furent proposées et utilisées avec succès lors des alertes qui ont suivi l'apparition respective des vers Code Red [CR] puis Nimda [NIMDA] que nous avons déjà évoqués. Ici encore, c'est dans la diversité des environnements open source que réside leur faiblesse. Le manque de cohérence et la généralité expliquent en grande partie qu'on ne dispose pas aussi facilement des mêmes fonctionnalités que chez Cisco, par exemple. Les seules propositions s'en rapprochant sont peut-être les IPS, pour Intrusion Prevention System. Ces logiciels ne sont en fait que le résultat logique du mariage entre les IDS et les firewalls. On pourrait même les réduire à de simples firewalls équipés d'un engin de pattern matching. La plupart des projets d'IPS libres sont basés sur Snort. Cependant, il ne sera possible dans tous les cas que de rejeter des paquets suite à une alerte, et non de les traitant de manière aussi variée que chez les vendeurs spécialisés. Parmis les projets les plus séduisants, on retiendra cependant SnortSam, qui permet de filtrer dynamiquement certaines IP suite à la génération d'alertes Snort. Son architecture est constituée d'un output plugin chargé par Snort qui surveillera chaque arrivée d'alerte. Si l'une d'elle correspond à une ligne dans son fichier de configuration, il envoie les règles de filtrage à un agent placé sur un firewall, éventuellement distant. Le contenu de cette communication est chiffré pour plus de sécurité. L'avantage majeur de cette approche est l'interopérabilité puisque SnortSam supporte plusieurs types de firewalls (iptables, pf, ipf, Cisco Pix et ACL classiques, Checkpoint Firewall-1, etc.). Sa faiblesse est justement introduite par cette même interopérabilité. En se réduisant à un dénominateur commun, le jeu d'instructions disponibles s'appauvrit. Une documentation complète, bien que pas toujours à jour, est disponible sur le site officiel de SnortSam [SAM] Toujours pour Snort, vous aurez très certainement entendu parler des FlexResp. Cette fonctionnalité permet de bloquer une connexion en se basant directement sur les protocoles utilisés. Au lieu de supprimer un paquet au niveau de la machine, l'IDS sortira de son rôle passif pour envoyer des segments RST en cas de flux TCP, ou des messages ICMP en cas de flux UDP, dans tous les cas spoofés afin de faire croire à une ou aux deux extrêmités de la connexion que celle-ci a été fermé, entraînant la suppresion des blocs de contrôles et donc l'oubli de la connexion. Reprenant la documentation Snort [RESP], les différents mots-clés disponibles à ajouter à vos règles sont les suivants : - rst_snd envoie un segment TCP RST à l'initiateur de la session - rst_rcv envoie un segment TCP RST au destinataire de la session - rst_all envoie un segment TCP RST aux deux extrêmités de la session - icmp_net envoie un message ICMP 'network unreachable' à l'initiateur de la connexion UDP - icmp_host envoie un message ICMP 'host unreachable' à l'initiateur de la connexion UDP - icmp_port envoie un message ICMP 'port unreachable' à l'initiateur de la connexion UDP - icmp_all envoie les trois messages ICMP précédents à l'initiateur de la connexion UDP Pour utiliser les FlexResp, il suffit d'ajouter 'resp:;' à votre règle Snort, en remplaçant 'keyword' par l'un des mots-clés présentés. Pour reprendre notre exemple bien particulier des vers basés sur la faille ISAPI d'IIS, nous utiliserons le préprocesseur HTTP de Snort en lui indiquant d'interpréter tous flux HTTP comme étant destiné à un serveur IIS, afin de déjouer les tentatives d'évasions. Puis, nous ajouterons une règle recherchant la chaîne de caractère 'default.ida' dans l'URL des messages HTTP contenus dans un segment TCP ACK. Lorsqu'un tel paquet est detecté, un segment RST est envoyé aux deux extrêmités de la transmission. ------------------------------------ SNiP ------------------------------------- preprocessor http_inspect_server: server default \ profile iis ports { 80 8080 } alert tcp any any -> any any (uricontent:"default.ida"; flags:A; \ resp:rst_all: msg:ISAPI buffer overrun) ------------------------------------ SNiP ------------------------------------- Notez que des deux approches, SnortSam est la plus sûre et fiable. Un IDS ne devrait en effet pas pouvoir envoyer la moindre donnée vers un attaquant au risque de trahir sa présence. De plus, un attaquant pourra aisément utiliser un une pile TCP/IP modifiée (même un worm) ignorant les segments RST, s'immunisant de cette façon. Enfin, la facilité d'emploi du spoofing risquerait de transformer cette mesure de sécurité en une tentante invitation au DoS. Il suffit en effet d'interpréter les rulesets Snort, d'envoyer des paquets construits pour y répondre mais avec des adresses forgés appartenant aux machines ou au réseau qu'on souhaite couper, pour disposer d'un moyen anonyme de créer des DoS. En tentant de réduire le risque de DDoS, on aura alors faciliter l'exploitation de DoS, en permettant d'utiliser l'IDS comme relai. 2.5. iTrace Les nombreuses possibilités d'attaques spoofées, en particulier dans les cas de DDoS, et la difficulté qu'elles entraînent dans la recherche de la source réelle, ont poussé Steve Bellovin - au palmarès évocateur puisqu'il se cache derrière le livre "Firewalls and Internet Security", la RFC 1948 et pushback qui est présenté un peu plus loin - à développer, au sein de l'IETF, un nouveau type de message ICMP (sans code) permettant de suivre le chemin d'un paquet : l'ICMP Traceback Message [ITRACE]. La génération est définie au niveau de chaque routeur et s'effectue suite au passage de 1 paquet sur 20000 selon la valeur par défaut recommandée qui peut bien sûr être adaptée ; sans jamais dépasser les 1/1000. La paquet traceback est toujours généré avec un TTL de 255 pour contre-vérifier la distance par rapport au routeur. Ce message est formé d'une série de champs organisés chacun selon le format TLV (Tag-Length-Value) indiquant d'abord le type d'information, puis sa longueur et enfin sa valeur proprement dite. Les tags sont les suivant : 0x01 Back Link 0x02 Forward Link 0x03 Interface Name 0x04 IPv4 Address Pair 0x05 IPv6 Address Pair 0x06 MAC Address Pair 0x07 Operator-Defined Link Identifier 0x08 Timestamp 0x09 Traced Packet Contents 0x0A Probability 0x0B RouterId 0x0C HMAC Authentication Data 0x0D Key Disclosure List 0x0E Key Disclosure 0x0F Public-Key Information Un traceback doit contenir un back link ou un forward link et éventuellement les 2. Un *link inclut au minimum une paire d'adresses IPv4 ou IPv6 dans le sens du parcours du paquet (source puis destination) au-dessus du routeur dans le cas d'un backlink et au-dessous du routeur pour un forward link, avec éventuellement un nom d'interface du point de vue du générateur (le routeur à l'origine du traceback) ainsi qu'une paire d'adresses physiques (MAC ou chaînes de caractères définies par l'opérateur). Le tag timestamp spécifie le moment au format Network Time Protocol auquel le paquet tracé est arrivé au niveau du générateur. Le tag traced packet contents doit contenir si il est spécifié au moins l'header IP et les 8 premiers octets du payload. Probablity indique la probabilité avec laquelle le paquet tracé a été sélectionné pour générer un traceback, cette probabilité étant définissable pour chaque routeur. RouterId est un identifiant qui ne devrait généralement avoir de sens que pour l'organisation propriétaire du routeur générateur. Les derniers tags sont utilisés pour l'authentification des traceback. Un attaquant pourrait en effet vouloir générer des faux traceback afin de brouiller les pistes remontant jusqu'à lui. Le tag HMAC Authentification est impératif, il est subdivisé en champs algorithme (HMAC-MD5-128, HMAC-SHA1-160, probable utilisation des ISAKMP codepoints), keyid, timestamp de génération de la clé au format NTP toujours et Message Authentification Code pour l'authentification proprement dite. Les derniers champs permettent de donner des informations sur les clés précédemment utilisées ainsi que des informations sur la PKI utilisée afin de vérifier l'identité du routeur (via le certificat de son organisation). Divers aspects de la sécurité comme le spoofing et les Denial of Service sont pris en compte dans le design de ce nouveau type ICMP. Ainsi il est conseillé de baser la probabilité de génération sur un pseudo random number generator plutôt que sur un simple comptage cyclique. Comme nous l'avons dit, par défaut la génération par probabilité est de l'ordre de 1 pour 20000 afin de ne rajouter que 0.1% de trafic sur la totalité d'Internet (supputant une largueur moyenne de 20 hops). Cependant lors d'un DDoS, le nombre de paquets augmentera essentiellement autour du point de convergence qu'est la victime et donc ce seront les routeurs les plus proches qui auront le plus de chance de générer des messages ICMP traceback. Pour remédier à ce problème, un draft supplémentaire [MAN+01], spécifiant comment obtenir délibérément des ICMP traceback, a été rédigé. Il recommande d'attacher à chaque route une "Intention Value" indiquant la probabilité d'envoi de traceback désirée pour cette route. Le routeur sélectionne le forwarding path pour un paquet réceptionné, consulte l'Intention Value pour cette route, et envoi un ICMP traceback à la destination si nécessaire. De plus, elle spécifie également qu'un routeur qui reçoit un traceback à router peut réutiliser ces informations afin de constituer un agrégat qui entraînera à son tour la génération de traceback vers la source. Enfin l'Intention Value devra être redistribuée entre les routeurs à l'aide de BGP. Mais comme vous l'avez sans doute remarqué, cette méthode se limite par sa conception au traceback forward link, réduisant son utilité. Mais n'oubliez pas que l'iTrace n'est encore qu'au stade de proposition et aucune implémentation n'est encore projeté. D'ailleurs, en février 2002, le schéma Intention Driven devait encore être réécrit pour s'adapter à tous types de tag link. Et fin 2003, les documents relatifs à sa mise en place avaient même disparu du site de l'IETF, pour n'être que pauvrement remplacé en octobre 2003 par un draft [ATP] (très mal écrit) définissant un Active Traceback Protocol. Celui-ci se contente de réutiliser l'infrastructure conçue par Steve Bellovin pour iTrace afin d'y adjoindre un mécanisme compatible déclenchant le tracking à la suite d'une requête d'un administrateur ayant obtenu une Security Association avec l'origine du tracking, comme il est prévu de pouvoir le faire avec iTrace. La compatibilité s'étend également à la reconnaissance de numéro d'identification de génération de traceback classique afin de pouvoir recouper traceback actif (ATP) et passif (iTrace). Le problème reste le même : à savoir une implémentation inexistante doublée de zone de floue autour des règles et mécanismes de génération des traceback. Si iTrace présent l'intérêt d'un outil statistique multi-usage facile à mettre en place au sein des réseaux pré-existant, Intention-driven iTrace ou ATP, qui tente de répondre à l'envie des administrateurs de contrôler très précisément la génération des traceback afin d'en améliorer la précision, n'apportent pas de réelles solutions. L'examen des techniques suivantes semblent démontrer que, si le tracking passif s'intègre très bien par des solutions protocolaires, sa contre-partie active doit reposer plus abondamment sur des outils logiciels originaux. 2.7. SPIE Source Path Isolation Enfine, ou SPIE [SPIE], désigne un système d'IP traceback mis au point par le MIT et BBN Technologies avec des fonds du DARPA, et se trouve à l'étude auprès de l'IETF [IPPT]. Contrairement à l'iTrace, SPIE fournit des informations relatives au traçage d'un paquet en réponse à des requêtes explicites au lieu de se baser sur des probabilités. SPIE est également remarquable pour l'attention faite à la protection de la vie privée - notamment quant à la subversion de SPIE en système généralisé de surveillance et d'accounting - ainsi que les performances en particulier au niveau de l'encombrement mémoire. Le problème du traceback est bien souvent de stocker les informations d'accounting relatives à chaque paquet transmis. Ce problème est éludé avec iTrace en effectuant une génération immédiate mais probabiliste. SPIE résout quant à lui le problème en stockant des hash de chaque paquet IP à partir de 28 bits d'entête excluant les champs Time to Live, checksum, Type of Service et IP Options qui peuvent être modifiés à chaque hop. Les agents effectuant les hash sur les routeurs sont nommés DGA pour Data Generation Agent et peuvent aussi bien être software que hardware (attaché à une interface par exemple). Lorsqu'un paquet est intercepté au niveau du forwarding path d'un routeur, le DGA fait coïncider chaque fonction universelle de hashage avec un vecteur d'initialisation unique, à un bit dans un filtre en fleur nommé digest table. Ce mécanisme facilite les tests de traceback qui se résument pour chaque agents "vérifieurs" à prendre le hash d'une requête et à rechercher la présence d'un bit à la position correspondant à cette fonction de hashage dans le filtre en fleur. Le risque de collision est au plus de 0.139% sur un LAN, lorsqu'il y a manque de diversité de trafic. Les hashs sont finalement stockés dans des digest tables. L'utilisation des hashs permet aussi de préserver la vie privée des utilisateurs légitimes du réseau en ne stockant ni ne transmettant aucune information claire. ------------------------------------ SNiP ------------------------------------- Bloom filter _ 1st hash() -----> |1| | | | | 2nd hash() -----> |1| | | | | 2^n bits 3rd hash() -----> |0| | | | | 4th hash() -----> |1| _| <- n bits -> Représentation d'un filtre en fleur Reproduction de la figure 4 de [SPIE] ------------------------------------ SNiP ------------------------------------- Les DGA ne conservent les hash que peu de temps. Pour un stockage à plus long terme, les digest tables sont rapatriées sur des agents SPIE Collection and Reduction (SCAR) qui servent de points de concentration pour une zone du réseau, chapeautant plusieurs routeurs/DGA. Lorsqu'un administrateur souhaite vérifier le parcourt d'un paquet, il calcule son hash, fait une requête via le STM (SPIE Traceback Manager) qui relait auprès des tous les SCAR. Les requêtes sont constituées du hash du paquet recherché, du temps de réception et du dernier hop avant la destination. Chaque SCAR construit un graphe connexe par simulation du Reverse Path Forwarding représentant le parcourt du paquet pour sa zone d'autorité, puis le STM assemble la totalité de ces graphes pour former le parcours complet du paquet jusqu'aux DGA à l'extrémité du domaine (edges). L'utilisation des hash et des filtres en fleur permettent à SPIE de ne générer aucun faux négatifs, et seulement d'éventuels faux positifs créant un surplus d'information représenté par des branches supplémentaires - généralement limitées à un hop puisque les vecteurs des fonctions de hashage changent - dans le graphe d'un SCAR donné. L'un des objectifs originaux de SPIE est de supporter les multiples transformations légitimes que les paquets peuvent subir lors de leur transmission comme celles induites par le Network Port & Address Translation (NPAT), ainsi qu'IPSec et la fragmentation. Pour gérer convenablement ces transformations et éviter d'offrir là un moyen d'évasion, chaque DGA maintient simultanément à chaque digest table, une Transform Lookup Table (TLT) listant toutes les transformations effectuées dans la même période de temps que la génération d'un digest. Chaque entrée TLT comporte un digest, le type de transformation et un extrait du nouveau paquet suite à la transformation pour poursuivre le traceback. Lorsque le flag I est présent, le 4ème partie doit être considérée comme un pointeur vers une structure externe contenant les informations permettant de retrouver la trace du paquet. Ce flag peut aussi servir à conserver des données temporairement lorsque plusieurs digest signalent une même transformation. --------------------------------------- | Digest | Type | I | Packet Data | | 29 bits | 3 bits | flag | 32 bits | --------------------------------------- En conclusion, bien que plus complexe que l'iTrace, SPIE semble bien plus abouti comme système de traceback notamment au niveau de la protection de la vie privée et des performances. Une première implémentation, destinée à démontrer les qualités du système, a été rendu publique par BBN Technologies en mars 2002. Elle a été développé pour FreeBSD et son nombre important de dépendances (Zebra, net-SNMP, ...) se voit contre-balancé par une démonstration d'interface graphique en PerlTk. Notez enfin que la technologie a été soumis à l'IETF, ce qui laisse espérer une future généralisation de SPIE. 2.8. IP Source Tracker Face à ces nombreuses technologies de tracking en cours de standardisation ou de développement, Cisco a rapidement réagi en proposant dans les versions 12.0(21)S d'IOS une fonctionnalité originale, l'IP Source Tracker. Dans l'esprit de ces concepteurs [IPST], IP Source Tracker remplace un processus fastidieux de tracking que tout opérateur Cisco était à même de réaliser à partir d'ACL. En effet, lorsqu'une attaque de type DoS est détectée, il restait possible à l'administrateur du réseau de placer des ACL sur ses routeurs, en partant du plus proche de la cible du DoS, puis de se servir des logs produits par ces ACL pour remonter de routeurs en routeurs jusqu'au point d'entrée de l'attaque dans le réseau. Afin donc de faciliter la vie des administrateurs, Cisco propose une solution automatisée, basée, comme pour RPF, sur la technologie CEF. Après être parvenu à déterminer l'adresse cible du DoS, il vous suffit de taper la ligne suivante en configuration globale : router(config)#ip source-track
L'intérêt majeur est que le tracking de tous les paquets se dirigeant vers cette adresse s'effectuera automatiquement sur l'ensemble des interfaces du routeurs, sans avoir à configurer d'ACL sur chacune d'elle. Vous pouvez, bien sûr, paramètrez quelques options relatives au source tracker. En particulier, vous pouvez indiquez le nombre maximal d'adresses suivies simultanément - par défaut, non restraint - en limitant le nombre d'instance de la commande 'ip source-track' possibles. Tapez simplement la commande ci-dessous : routeur(config)#ip source-track address-limit Il faut également savoir que sur les modèles de routeurs Cisco sur lesquels l'IP Source Tracker est disponible, les données sont collectées au niveau des chaque carte réseau individuellement, puis exportées vers le processeur central. Il est donc possible de paramétrer l'intervalle, en secondes, entre ces exportations : routeur(config)#ip source-track export-interval Pour visionner les données issues du tracking, on trouve également plusieurs options différentes d'après le squelette suivant : router#show ip source-track {address} {summary | cache | export flows} L'adresse est optionnelle, vous permettant ainsi de visionner les statistiques pour une adresse suivies ou pour toutes les adresses suivies. Les options d'affichages qui viennent ensuite sont relativement auto-explicatives : 'summary' donne un court résumé des statistiques, 'cache' affiche les données collectées au niveau des cartes réseaux et 'export flows' délivre celles qui ont été exporté vers le processeur central. Notons toutefois plusieurs limitations importantes qui font essentiellement d'IPST, une simple solution d'appoint. D'abord, le système n'étant en aucun cas distribué - à moins éventuellement que vous ne scriptiez de manière simultanée et automatique sur l'ensemble des routeurs, puis fassiez remonter d'une quelconque manière ces données afin de les corréler et synthétiser -, le tracking n'est pas instantané à travers la totalité de votre parc de routeurs. Outre la tâche de configuration fastidieuse, cela signifie aussi qu'il vous restera à construire seul le graphe représentant le parcours des paquets. On retrouve donc ici les mêmes problèmes que pour les blackholes, à savoir le manque de coopération entre les différentes technologies Cisco. Le rate limiting ou RED - deux techniques qui sont étudiées ultérieurement - sont supportées par Cisco et pourraient être utilisées pour déclencher le tracking. D'autre part, contrairement à SPIE et iTrace, IP Source Tracker n'a pas une vocation universelle. Toutes les informations collectées s'arrêteront donc, au mieux, au niveau du point d'entrée de l'attaque dans votre réseau. Une coordination entre ISPs peut cependant rendre cette technologie intéressante, pour eux uniquement. C'est donc véritablement, comme énoncé honnêtement par Cisco, un simple remplacement plus productif de la méthode de recherche manuelle à base d'ACL. Enfin, si aucun impact sur les performances brutes des routeurs ne sont à déplorer, il faut tout de même remarquer que la surcharge sur les cartes réseaux peut provoquer des rejets de paquets. Ce n'est donc pas une technique à appliquer une bonne fois pour toute, mais bien une option temporaire en réaction à une attaque, comme le blackholing. D'autre part, un tel dispositif, ainsi que toutes les technologies de tracking présentes ou futures, ne vous dispensent en aucun cas de collecter le plus de données possible sur le trafic de votre réseau. Vous pourrez ainsi pallier en toute occasion les défauts ou défaillances de vos systèmes de tracking, et apporter un complément d'information dans les autres cas. Nous avons ainsi fait remarquer à quel point l'utilisation du logging au niveau des règles de firewall, ou bien le reporting lorsque vous employez un IDS, s'avère important. Dans le même ordre d'idée, Cisco propose de nombreuses commandes permettant de surveiller l'utilisation des ressources sur un routeur. L'une d'entre elle est Netflow. une autre technologie propriétaire Cisco basée sur CEF. Celle-ci permet de générer des statistiques détaillées du trafic passant par un routeur, et même éventuellement de les exporter vers une machine distantes d'administration, typiquement équipée de NetflowCollector. Sa configuration, sous IOS, s'effectue par interface : router(config)#interface ethernet 0 router(config-if)#ip route-cache flow Les statistiques peuvent alors aisément être affichés et vidées grâce aux commandes suivantes, respectivement : router#show ip cache flow router#clear ip flow stats Vous disposez également de quelques raffinements, comme le choix du nombre maximal d'entrées présentes dans le cache Netflow. La valeur par défaut est de 65536, sachant que chaque entrée nécessite approximativement 64 octets pour son stockage. Cette valeur pouvant varier de 2^10 à 2^19, voici la commande permettant de la choisir : router(config)#ip flow-cache entries Vous pouvez également, comme nous l'avons brièvement dit, exporter les données vers une console d'administration lorsqu'elle expire sur le routeur, afin d'en conserver une trace. Cette fonctionnalité facilite grandement le tracking manuel en permettant de centraliser vos données vers une seule et unique machine. La commande d'export est telle que ci-dessous, avec version indiquant le format qu'est capable de recevoir le logiciel destinataire, de 1, par défaut, à 5 : router(config)#ip flow-export [version ] Vous disposez d'une dernière fonctionnalité permettant de résumer les données collectées par Netflow au sein d'un Aggregation Cache (AC). Pour ce faire, appliquez le fichier de configuration ci-dessous. ------------------------------------ SNiP ------------------------------------- configure terminal ip flow-aggregation cache cache entries 2046 cache timeout inactive 120 cache timeout active 60 export destination enabled ------------------------------------ SNiP ------------------------------------- La plupart des options ont la même signification que les options Netflow classiques. La différence vient de la possibilité de spécifier les valeurs de timeout pour des entrées inactives et actives, avant de les voir supprimées et donc exportées. 'Scheme' permet, quant à elle, de définir le critère d'agrégation des paquets. Elle peut prendre comme valeur 'as' pour l'autonomous system auquel appartient le routeur, 'protocol-port' pour le type de protocole au niveau transport, 'destination-prefix' pour l'adresse de destination du paquet, 'source-destination' pour l'adresse source et 'prefix' les deux simultanément. Pour toutes agrégation basée sur le prefixe IP, vous pouvez indiquer une valeur minimale pour le masque de sous-réseau, selon la notation CIDR. Choissisez, parmis les séquences suivantes à entrer en mode configuration globale, celle qui équivaudra à votre agrégat. ------------------------------------ SNiP ------------------------------------- ! pour prefix ip flow-aggregation cache prefix mask source minimum 24 mask destination minimum 24 ! pour source-prefix ip flow-aggregation cache source-prefix mask source minimum 28 ! pour destination-prefix ip flow-aggregation cache destination-prefix mask destination minimum 28 ------------------------------------ SNiP ------------------------------------- Enfin, n'oubliez pas que, sous IOS, les informations délivrées par n'importe quelle commande 'show' peuvent être triées à l'aide d'expressions rationnelles. Pour ce faire, juste après la commande, tapez un pipe, suivi de 'begin' pour conserver les lignes commençant par l'expression, 'include' contenant l'expression et 'exclude' ne contenant pas l'expression. Puis, finissez par l'expression elle-même. Pour que Netflow n'affiche que les paquets orientés vers null0, la commande serait comme ci-dessous : router#show ip cache flow | include null Pour les systèmes libres compatibles Unix, vous pouvez utiliser l'excellent outil d'audit ARGUS (Audit Record Generation and Utilization System) [ARGUS]. Nous ne nous attarderons pas sur sa configuration qui a été déjà longuement décrite pour le public francophone dans d'autres documentations [BER02] dont une rédigée par CNS. 3. Exhaustion-oriented Notre première approche sert efficacement son but : limiter l'impact d'un DDoS en refoulant les paquets qui le véhicule à l'entrée du réseau protégée, ainsi qu'en permettant d'identifier rapidement l'origine de l'attaque (ou au moins son point d'entrée) pour y répondre par des contre-mesures appropriées. Mais même le plus efficace des filtrages ne suffit pas à réduire à néant les effets d'un DDoS puisque la bande passante reste monopolisée en amont. On remarquera par contre que de telles attaques impliquent généralement une forte augmentation de la congestion réseau, à mesure que l'on se rapproche de la cible dans le cas d'une attaque distribuée, ou bien le long du chemin d'attaque pour un DoS plus ciblé. Il est donc judicieux d'envisager la défense face aux DDoS sous l'angle de la lutte contre l'exhaustion des ressources. Même si cela paraît nous faire sortir légèrement de notre sujet initial, c'est dans cette optique de lutte généralisée contre la congestion que nous nous intéresserons tout particulièrement au domaine de l'Active Queue Management, très bien défini par la citation ci-après. "It is useful to distinguish between two classes of router algorithms related to congestion control: "queue management" versus "scheduling" algorithms. To a rough approximation, queue management algorithms manage the length of packet queues by dropping packets when necessary or appropriate, while scheduling algorithms determine which packet to send next and are used primarily to manage the allocation of bandwidth among flows. While these two router mechanisms are closely related, they address rather different performance issues." [2309] Des disciplines d'AQM sont notamment disponibles dans les QoS commands d'IOS, dans ALTQ [ALTQ] fourni avec les *BSD (natif à partir de FreeBSD 5.0, OpenBSD 3.0, NetBSD 1.6A et disponible auparavant via les patchs ALTQ ou les snapshots KAME), et dans iproute2 [IPR2] fourni avec Linux. L'AQM a pour nous un avantage important par rapport au scheduling également cité. Les disciplines disponibles s'appuient en effet sur les statistiques et ne demanderont donc pas une configuration spécifique à chaque réseau basée quant à elle sur une étude complexe des flux traversant le réseau. Une telle configuration serait de plus bien trop sensible aux variations du type de trafic, laissant la porte grande ouverte aux attaquants qui n'auraient qu'à modifier légèrement le type de trafic utilisé lors du DDoS pour non seulement contourner les mesures de scheduling mais également l'abuser en offrant une plus grande priorité aux flux liés à l'attaque. En étudiant de manière la plus généraliste possible la diminution de la congestion et la réduction de la consommation en bande passante, nous nous assurons d'une qualité et d'une continuité de service exemplaire en toutes situations, incluant en particulier les DDoS. Nous pourrions bien entendu suivre notre idée et aller jusqu'à évoquer les mesures d'optimisation de l'utilisation des ressources système (CPU, mémoire, etc.) de nombreux systèmes, ou même étudier le matériel le plus performant ou encore les différents algorithmes d'évitement de congestion sur les hôtes. Cependant, nous choississons d'étudier les mesures les plus génériques tant par leur portée - c'est-à-dire s'appliquant au niveau OSI 3 ou 4 de la pile TCP/IP et sur le matériel d'infrastructure réseau plutôt que sur les hôtes - que par leur implémentation. Nous nous écartons cependant parfois des AQM pour évoquer des technologies permettant elles aussi de réduire l'utilisation de la bande passante ou de supporter une plus forte charge sans interruption des services proposés, ou bien des technologies moins largement adoptées, mais pour autant répondant parfaitement à la problématique des DDoS. 3.1. RED Lorsqu'un routeur reçoit un paquet, il le place dans une queue FIFO pendant la durée de son traitement le long du forwarding path. Ces queues consommant des ressources, il a rapidement fallut