Petit retour sur Sockstress
Par Mickaël le 15 mai 2011, 11h14 - Commentaires - Lien permanent
Voici l'article « Sockstress, l’épuisement de TCP » que j'avais publié dans le Misc 46 (novembre 2009) traitant d'attaque sur les connexions TCP. Cet article est sous licence Creative Commons Attribution-NonCommercial-NoDerivs.
Après le buzz sur les problèmes du système DNS, le sujet brûlant soulevé par les faiblesses de BGP, voici TCP qui pointe son nez. Ce sont là des protocoles nécessaires pour un bon fonctionnement de réseaux, tel qu'Internet, qui sont mis à mal. Beaucoup d'incompréhension et de spéculations ont donc fait suite à l'annonce de cette nouvelle découverte qui sonnait une fois encore la mort d'Internet par de possibles dénis de service très efficaces.
Tout a commencé par la notification de Jack C. Louis et Robert E. Lee (Outpost24) à plusieurs fabriquant de machines dédiées au réseau (routeurs, pare-feux…) et à certains éditeurs de systèmes 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, handicapant dans la foulée les oubliés…
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écouvert de cette faille, 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.
Chronologie récapitulative :
- 2005 (au minimum) : découverte du problème ;
- septembre 2008 : publications (avec peu de détails) ;
- juin 2009 : premier PoC public : NKiller2 ;
- septembre 2009 : 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 ce bogue lors de l'optimisation du scanner Unicornscan. Alors que l'équipe de développement était 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 (non public), nommé Sockstress, destiné à recréer ces états gênants. Après investigation sur différents périphériques réseaux ils se sont vite aperçu 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 a vu le jour sous le nom de NKiller2[1] diffusée dans Phrack 66. Cette première (et unique) preuve de concept tire partie de la même vulnérabilité TCP à savoir le maintient de la connexion. Contrairement à Sockstress, il 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. Le constat est que peu importe qu'il s'agisse d'« implémentations maison », il est très probable qu'elles soient également impactées étant donné que la vulnérabilité repose sur un des fondements de TCP.
Lee et Louis on mis au point différente 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 (encart d'information)
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é 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'informations utiles entre les deux protagonistes.
Le problème
Il existe essentiellement deux types de déni 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éseaux traitants 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 leurs états, il est possible de maintenir un flux durant une longue période dans un état actif mais très peut réactif. Si un nombre suffisant de connexions de ce type sont établies, le système cible va commencer à être en manque de ressources pour gérer d'autres connexions, qui elles peuvent être légitimes.
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[2]. Contrairement aux autre 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 soit 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 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 maintient 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 terme de ressources, on passe d'un rapport de 1 vs 1 (pour un flood traditionnel) vers un rapport de X vs 1 en terme 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[3].
On a alors à notre disposition une attaque requérant de faibles ressources réseau et étant capable d'en nécessiter un grand nombre.
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 figage de la machine attaquée (avec ou sans écran bleu) ou encore 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.
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[4].
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 fournis 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'autre possibilités pour maximiser les effets, comme par exemple faire en sorte de congestionner le serveur par des requêtes nécessitant plus de ressources (calcul, mémoire…).
Comme l'on dit les auteurs originaux, avec quelques dizaine de paquets par seconde il est possible d'avoir un impact important, même à partir d'une liaison réseau à faible débit.
Remède
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 trouvent 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 distinct pour émettre et recevoir les paquets avec peu, voir aucun partage d'information entre ces opérations. Il nous est alors possible de détecter ce type d'outils en simulant une connexion établie (acquittement), vers le présumé client, 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éseau NATés peuvent malheureusement (pour eux) en pâtir. Bien sur, d'autre types de détections sont possibles s'il s'agit d'une attaque multiple.
Contre-mesure
Le bon usage de TCP conseil 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 maintient 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 sorti par les éditeurs afin de combler les trous. 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 fournis 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 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 par une configuration du pare-feu (à titre d'exemple), mais aucun patch pour Linux étant donné que le problème est considéré inhérent au protocole TCP[5]. Les règles de pare-feu proposées 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 de filtrage strictes. À 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 les parties composant un système d'information est plus ou moins sensible et nécessite donc une attention particulière. Pourtant, pendant plus de 30 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 ».
Au vu des propositions de protections émises par les fabriquants, 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 tout les systèmes l'utilisant. Voilà comment peut naître une vulnérabilité multi-plateforme.
Notes
[1] NKiller2 à été créé par ithilgore
[2] Ceci est particulièrement vrai lorsque des SYN cookies sont utilisés.
[3] Voir le Max Segment Lifetime défini dans la RFC 793.
[4] 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…
[5] On peut cependant noter qu'il existait déjà des techniques de protections 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 RFCs !
