Après le buzz sur le système DNS, le sujet brûlant soulevé par les faiblesses de BGP, voici TCP qui pointe le bout de son nez. Ce sont là les trois protocoles réseau les plus utilisés sur Internet qui sont mis à mal. Beaucoup d’incompréhension et de spéculations ont donc fait suite à l’annonce de cette découverte qui sonnait une fois encore la mort d’Internet du fait d’un déni de service très efficace.Tout a commencé par la notification de Jack C. Louis et Robert E. Lee [1] (de Outpost24) à plusieurs fabricants de machines dédiées au réseau (routeurs, pare-feu...) et à certains éditeurs de système d’exploitation. Cette vague d’information coordonnée avec l’aide du CERT de Finlande a été divulguée aux principaux acteurs des réseaux au niveau international afin d’éviter toute fuite gênante.
1. Bref historique
C’est d’un déni de service dont il est question, et plus précisément sur le protocole TCP. Le chercheur à l’origine de la découverte de cette faille dans TCP, Jack C. Louis, a mis en évidence un problème pratique lors du maintien d’une connexion. En effet, il est possible de maintenir indéfiniment un flux entre deux machines.
Récapitulatif historique :
- 2005 (au minimum) : découverte du problème ;
- 2008/09 : publications (avec peu de détails) ;
- 2009/06 : premier PoC public : NKiller2 ;
- 2009/09 : distribution des patchs (ou placebos) et mise à jour des alertes sur la vulnérabilité (CVE-2008-4609, MS09-048, cisco-sa-20090908-tcp24...).
Jack Louis a découvert [2] ce bogue lors de l’optimisation du scanner Unicornscan [3]. Alors qu’ils étaient en train de passer la couche TCP vers l’userland, ils se sont rendu compte de certains effets néfastes des connexions TCP. Il en est sorti un outil, nommé « Sockstress » (non public), destiné à recréer ces états gênants. Après investigation sur différents périphériques réseau, ils se sont vite aperçus de l’impact que cette découverte pouvait avoir. Ils ont alors fait le choix de ne divulguer cette faille qu’aux principaux acteurs des réseaux pour leur laisser le temps de mettre en place des correctifs.
En parallèle, une implémentation, très proche et diffusée dans Phrack 66 [4], a vu le jour sous le nom de NKiller2 [5]. Cette première (et unique) preuve de concept tire parti de la même vulnérabilité TCP, à savoir le maintien de la connexion. Contrairement à Sockstress, elle a beaucoup moins fait couler d’encre, alors que c’est une implémentation fonctionnelle qui est sortie trois mois avant les patchs correctifs.
Sur les 15 implémentations de TCP testées par les auteurs de la découverte, aucune n’était épargnée. Peu importe que les implémentations soient faites maison. Il est très probable qu’elles soient également impactées étant donné que la vulnérabilité est un des fondements de TCP.
Lee et Louis ont mis au point différents scénarios d’attaque découlant de ce problème. Les ressources impactées peuvent être : la mémoire, les temporisateurs et compteurs du noyau, et les applications fournissant le service sur le réseau.
Rôle de TCP
Le protocole de contrôle de transmission (Transmission Control Protocol) est un des piliers des réseaux actuels. Il se trouve au-dessus de la partie réseau et est chargé d’ajouter une abstraction de la partie réseau (IP) pour arriver à une connexion continue de données entre deux points. TCP permet de garantir la fiabilité des transmissions et leur restitution dans l’ordre originel de leur émission. Il est également chargé de contrôler tout ce qui est lié au débit (taille des paquets, fréquence d’échanges et gestion de la congestion), et au « routage applicatif » avec le système de ports (source et destination) qui donne la possibilité d’établir et de différencier plusieurs connexions entre deux adresses.
L’établissement d’une connexion s’effectue en trois étapes, couramment appelées « three-way handshake » :
- un premier envoi de paquet pour demander l’établissement d’une connexion du client vers le serveur (SYN) ;
- le retour du serveur avec un acquittement et une demande équivalente (SYN-ACK) ;
- un deuxième envoi du client confirmant la bonne réception, ce qui déclare la connexion ouverte (ACK).
Ces échanges ouvrent la voie à la communication d’information utile entre les deux protagonistes.
2. Le problème
Il existe essentiellement deux types de dénis de service. Le premier qui est souvent causé par un grand nombre d’attaquants (d’adresses) consiste à saturer la bande passante. C’est alors une « consumation » des ressources réseau. Le second type de DoS concerne les ressources du système visé. Cela dépend souvent de la partie applicative qui fournit le service. Il peut par exemple s’agir d’un service Web ou alors des dépendances qu’il a besoin pour fonctionner comme une base de données.
L’attaque évoquée impacte les ressources du système qui gère les échanges réseau (la partie TCP), autrement dit, le système d’exploitation. On est alors exposé à un DoS en saturation des ressources de la machine hôte.
Le problème est dû au fait qu’il est possible d’ouvrir une connexion avec une persistance infinie, et ce, avec la plupart des composants réseau traitant TCP.
Ce qui est intéressant ici, c’est le respect des règles établies (par le protocole TCP) et l’exploitation extrême qui en est faite. Le but est tout simplement de faire le coup de la panne ! En simulant une (très) mauvaise connexion réseau ou une surcharge du côté client, on a la possibilité de maintenir la connexion dans un état actif ayant un débit utile nul en permanence.
En manipulant les connexions TCP, ou plus particulièrement leur état, il est possible de maintenir un flux durant une longue période dans un état actif, mais très peu réactif. Si un nombre suffisant de connexions de ce type est établi, le système cible va commencer à être en manque de ressources pour gérer d’autres connexions, qui, elles, peuvent être légitimes.
2.1 Cause
Pour être en mesure d’effectuer cette attaque, l’acteur malveillant doit arriver à établir une connexion complète. Un three-way handshake permettant à l’interlocuteur de s’assurer que son correspondant est bien celui qu’il prétend être [6]. Contrairement aux autres attaques par déni de service réseau (du type synflood), on établit une connexion légitime, ce qui met le service réseau « en confiance ». C’est cet aspect qui est nouveau et qui fait tomber la plupart des protections mises en œuvre par TCP. En effet, une fois la connexion établie, la communication peut commencer, et durer !
L’astuce n’est pas en soi de maintenir une connexion établie, mais de le faire de manière à avoir un déséquilibre important d’allocation de ressources entre les deux protagonistes.
Lors de l’établissement d’une connexion TCP entre deux machines, différentes ressources sont nécessaires : un espace mémoire pour contenir les connexions actives et les attributs qui permettent de la reconnaître, des temporisateurs permettant de synchroniser les transferts de données et de maintenir ou non la connexion dans le temps.
Étant donné que le service attaqué gère les connexions de manière régulière, il lui incombe de maintenir active et de vérifier à intervalle régulier l’état de la connexion afin de la maintenir active.
La faiblesse de TCP qui est exploitée est justement le maintien de connexion. Afin d’en tirer profit, il est souhaitable de ne pas faire comme le service victime, c’est-à-dire d’établir des connexions sans en sauvegarder l’état, mais tout en étant capable de reconnaître une connexion établie afin de la maintenir... Grâce à cela, on est en mesure d’établir un grand nombre de connexions avec un minimum de ressources sur notre machine. En termes de ressources, on passe d’un rapport de 1 vs 1 (pour un flood traditionnel) vers un rapport de X vs 1 en termes de consommation de ressources.
Il reste maintenant le problème du débit. Pour établir une connexion, il faut avoir un service à joindre, et souvent les connexions n’ont pas pour objectif de s’éterniser (cas des services Web par exemple). La ruse consiste à jouer avec le paramètre indiquant le débit accepté par la demandeur, c’est-à-dire la taille de fenêtre du paquet TCP. On a alors la possibilité de réduire le débit des paquets nous arrivant en simulant un (gros) problème réseau qui nous empêche de continuer la connexion normalement, et de la suspendre temporairement tout en la gardant active. On réduit ainsi drastiquement le débit nécessaire alors qu’il nous est possible d’établir et de maintenir un grand nombre de connexions simultanées ! Le temps de pause entre deux requêtes en cas de congestion dépend des implémentations et peut être compris entre 30 secondes et 2 minutes [7].
On a alors à notre disposition une attaque requérant de faibles ressources réseau et étant capable d’en nécessiter un grand nombre.
2.2 Effets
L’effet d’une telle attaque sur un serveur ayant une application sous TCP a pour résultat un déni de service au niveau du système d’exploitation. En effet, dans toutes les applications (sauf celles qui implémentent leur propre pile TCP, mais elles sont très rares), la gestion réseau est déléguée à l’OS. C’est lui qui s’occupe d’établir les connexions, de les entretenir et de faire le lien avec la couche applicative du service.
L’impact est donc sur le système entier et donc toutes les applications qui sont amenées à utiliser les ressources réseau de la machine. Étant donné que le système d’exploitation ne s’occupe pas seulement des aspects réseau, c’est potentiellement tout le système qui peut devenir instable. Les auteurs de la découverte ont ainsi fait état de figement de la machine attaquée (avec ou sans écran bleu) ou encore d’une impossibilité de revenir à un état stable pour un certain OS.
Un autre point important est le fait que les réseaux (surtout Internet) font intervenir un nombre conséquent d’intermédiaires afin d’acheminer ou de filtrer le trafic. Ces équipements peuvent avoir à intervenir au niveau de la couche transport, et, dans ce cas, être également concernés par le déroulement des connexions. Sachant qu’un pare-feu gérant le suivi de connexion doit tenir à jour l’état des flux le traversant, lors d’une attaque, il peut être amené à avoir, en plus des connexions légitimes, un nombre très important de flux : nombre d’IP clientes × nombre de ports à leur disposition × nombre de services (ports) TCP accessibles pour chaque IP se trouvant derrière le pare-feu (serveurs). On comprend donc mieux pourquoi une attaque menée sur les services traversant de tels filtres peut avoir un impact conséquent sur tout le trajet des connexions. Les intermédiaires peuvent être le plus gros problème étant donné le traçage incontrôlé d’un grand nombre de connexions qu’ils doivent surveiller ou acheminer.
3. Exploitation
Une connexion TCP peut être dans plusieurs états : en écoute, établie, en attente, en fermeture, ainsi que dans les multiples états intermédiaires. Lors d’une fermeture de connexion, on doit passer par deux états : FIN_WAIT1 et FIN_WAIT2. Ils indiquent respectivement la demande de fermeture, et la fermeture effective de la connexion. Dans le cas de cette attaque, les paquets malveillants peuvent arriver dans un état FIN_WAIT1 et y rester tant que l’attaquant maintiendra la connexion active avec une taille de fenêtre nulle et ne validera pas la bonne réception des données. Du point de vue de l’application, la connexion est fermée, mais c’est en fait le système d’exploitation qui essaye désespérément de la clore. Le système est en attente d’acquittement de toutes les données transmises... Ce sont ces sockets qui prennent des ressources et empêchent potentiellement d’autres connexions [8].
Deux actions parallèles sont requises pour réaliser ce DoS :
- Une première partie doit être chargée d’initialiser les connexions avec le handsheck :
- Envoi du premier paquet SYN,
- Détection de la réception du paquet SYN-ACK et validation par l’envoi d’un paquet ACK pour conclure l’ouverture de connexion,
- Requête nécessitant une réponse du correspondant ;
- La seconde partie est chargée d’entretenir les connexions ouvertes, de manière « paresseuse ». Moins on fournit d’effort, plus la différence d’utilisation de ressources sera importante. Il faut donc mettre la taille de fenêtre à une valeur minimale, zéro étant le plus intéressant.
Avec cela, il est possible d’établir un grand nombre de connexions et de paralyser la cible. Il existe d’autres possibilités pour maximiser les effets, comme faire en sorte de congestionner le serveur par des requêtes nécessitant plus de ressources (calcul, mémoire...).
Comme l’ont dit les auteurs originaux, avec quelques dizaines de paquets par seconde, il est possible d’avoir un impact important, même à partir d’une liaison réseau à faible débit.
4. Remède
4.1 Détection
Une solution assez simple pour détecter certains types d’attaques est de scruter les connexions en cours et plus particulièrement leur état. Si un nombre anormalement grand de connexions se trouve dans un état FIN_WAIT1, alors il y a soit un (gros) problème réseau, soit une attaque en cours.
Pour être efficace, certain outils de floods utilisent deux flux d’exécution distincts pour émettre et recevoir les paquets avec peu, voire aucun partage d’information entre eux. Il nous est alors possible de détecter ce type d’outil en simulant une connexion établie (acquittement) sans qu’elle soit légitime. Si une réponse positive nous parvient (sans reset de la connexion), alors une activité suspecte est détectée et on peut intervenir sur les règles de filtrage pour écarter l’adresse supposée malveillante. Attention toutefois, car les réseaux NATés peuvent malheureusement (pour eux) en pâtir. Bien sûr, d’autres types de détections sont possibles s’il s’agit d’une attaque multiple.
4.2 Contre-mesure
Le bon usage de TCP conseille d’utiliser les SYN cookies afin d’empêcher le spoof d’adresse. Cette méthode de prévention est une bonne chose, mais ne protège pas de l’attaque actuelle étant donné que les connexions sont légitimes. L’attaquant peut simuler la gestion des SYN cookies comme le fait une pile TCP standard.
Le problème venant du maintien de la connexion, une solution tentante peut être de ne pas respecter les bonnes pratiques qui font la vulnérabilité de TCP, à savoir de couper la connexion lorsque le débit (la taille de fenêtre) est trop faible. C’est d’ailleurs cette méthode qui est en partie employée pour les patchs sortis par les éditeurs afin de combler le trou. Cet élan d’impolitesse envers les connexions a pour conséquence le non-respect du protocole, ce qui peut avoir des effets de bord imprévus.
Microsoft a fourni des patchs pour ses systèmes les plus récents, mais pas pour les anciennes versions (Windows 2000 et Windows XP) sous prétexte que l’un ne vaut « pas le coup » d’être modifié et que l’autre dispose d’un pare-feu par défaut et n’est donc pas en danger... La mise à jour a pour but de supprimer et de limiter le nombre de connexions pour permettre au système de rétablir ses ressources.
RedHat a, quant a lui, répondu [9] par une configuration du pare-feu (à titre d’exemple), mais n’a fourni aucun patch pour Linux étant donné que le problème est considéré comme inhérent au protocole TCP [10]. Les règles proposées de pare-feu peuvent être utiles pour un service ne devant maintenir que peu de connexions lors d’un usage normal. Cependant, de telles configurations impactent les réseaux qui sont NATés. En effet, de tels réseaux seraient considérés comme des attaquants si plusieurs machines tentaient une connexion (légitime) simultanée.
Dans tous les cas, la protection de base consiste à bien cerner les flux nécessaires lors d’un usage légitime du service vulnérable afin d’en tirer des règles des filtrages stricts. À titre d’exemple, pour un serveur Web, une connexion cliente n’a pas forcément une légitimité à rester active trop longtemps, pour la consultation d’une page, exception faite pour un téléchargement de gros fichier... Il est également important de garder à l’esprit que l’attaquant ne peut pas utiliser de technique de spoof. Les listes blanches sont donc une bonne mesure de protection, lorsque c’est possible, étant supposé que l’attaque ne vient pas d’une adresse de cette liste. Le problème reste néanmoins présent pour tous les services TCP publics ne requérant pas d’authentification.
Conclusion
Toutes parties composant un système d’information est plus ou moins sensible et nécessite donc une attention particulière. Pourtant, pendant 35 ans, cette vulnérabilité était exploitable (et sans doute exploitée) dans énormément de systèmes sans que personne ne tire (bruyamment) la sonnette d’alarme. Maintenant, on ne peut se passer de ce protocole et de ces « fonctionnalités ».
À la vue des propositions de protections émises par les fabricants, il n’y a actuellement pas de solution entièrement satisfaisante à ce problème. L’attaque tire sa force de l’omniprésence du protocole TCP sur les réseaux et plus particulièrement le réseau Internet. La compatibilité entre les différents systèmes d’exploitation étant nécessaire pour communiquer, les erreurs intrinsèques à un protocole d’échange de données ont un impact sur tous les systèmes l’utilisant. Voilà comment peut naître une vulnérabilité multi-plateforme.
Notes
[1] http://blog.robertlee.name
[2] http://debeveiligingsupdate.nl/audio/bevupd_0003.mp3
[4] http://www.phrack.org/issues.html?issue=66&id=9
[5] NKiller2 a été créé par ithilgore (http://sock-raw.org)
[6] Ceci est particulièrement vrai lorsque des SYN cookies sont utilisés.
[7] Voir le Max Segment Lifetime défini dans la RFC 793.
[8] Actuellement, les OS peuvent tuer les connexions orphelines (en cours de fermeture ; sans lien avec l’userland) lorsque le système le nécessite, ce qui n’empêche pas de remplacer la connexion fermée par une autre...
[9] http://kbase.redhat.com/faq/docs/DOC-18730
[10] On peut cependant noter qu’il existait déjà des techniques de protection dans Linux (voir net/ipv4/tcp_timer.c : tcp_out_of_resources()) et que le problème est identifié (voir tcp_probe_timer()), mais non corrigé, du fait des RFC !