9 points par GN⁺ 2026-01-23 | 1 commentaires | Partager sur WhatsApp
  • Un cas d’analyse a mis au jour le phénomène suivant dans une session SSH : des centaines de paquets sont envoyés pour une seule frappe, puis la cause a été identifiée
  • L’analyse avec tcpdump a montré que la plupart des paquets étaient des messages répétitifs de 36 octets, émis à un intervalle d’environ 20 ms
  • La cause était la fonctionnalité de « keystroke timing obfuscation » ajoutée à SSH en 2023, qui envoie de nombreux paquets de « chaff » (SSH2_MSG_PING) pour masquer le timing de saisie de l’utilisateur
  • En désactivant cette fonctionnalité ou en modifiant le serveur pour qu’il n’annonce plus l’extension [email protected], l’utilisation CPU et la bande passante chutent de plus de moitié
  • Cet exemple montre qu’une fonctionnalité de sécurité de SSH peut devenir une charge importante dans les applications où les performances en temps réel sont critiques (par exemple les jeux)

Découverte du problème

  • Lors de tests sur la TUI d’un jeu haute performance exécuté via SSH, il a été constaté qu’une seule frappe générait 270 paquets
    • D’après tcpdump, 66 % étaient des messages de 36 octets, 33 % des ACK TCP, et le reste une petite quantité d’autres données
    • En moyenne, 90 paquets/s étaient transmis, avec un intervalle d’environ 11 ms
  • Pendant les tests, le serveur avait été mal configuré pour n’envoyer que le message « your screen is too small », et dans ce cas l’utilisation CPU et de la bande passante a été divisée par deux
    • Comme aucune donnée de jeu ne devait être transmise, l’utilisation CPU aurait dû être proche de 0 %, mais elle restait autour de 50 %
    • Cela a conduit à soupçonner un surcoût de communication propre à SSH

Enquête

  • Comparaison du trafic SSH en fonctionnement normal et en état d’erreur à l’aide de tcpdump
    • Même en état d’erreur, des paquets de 36 octets continuaient à être émis toutes les 20 ms
    • Le même motif a été observé avec le client SSH par défaut de macOS
  • L’analyse du fichier pcap avec Claude Code a montré que
    • sur un total de 413 703 paquets, 66 % faisaient 36 octets et 34 % étaient des ACK de 0 octet
    • c’était le client SSH qui générait activement les paquets

Cause profonde

  • Le journal de débogage SSH (ssh -vvv) a affiché le message suivant
    obfuscate_keystroke_timing: starting: interval ~20ms
    obfuscate_keystroke_timing: stopping: chaff time expired (101 chaff packets sent)
    
    • L’intervalle de 20 ms et les dizaines à la centaine de paquets de chaff correspondaient au motif réellement observé
  • La cause était la fonctionnalité d’obfuscation du timing des frappes ajoutée à SSH en 2023
    • Elle envoie des paquets de « chaff » aléatoires afin d’éviter que le schéma de vitesse de frappe de l’utilisateur ne soit exposé
    • Utile pour la sécurité, elle provoque toutefois une surcharge excessive dans les environnements où la latence est critique

Solution

  • Côté client, la fonctionnalité peut être désactivée avec l’option ObscureKeystrokeTiming=no
    • Après application, l’utilisation CPU et la bande passante ont fortement diminué, tout en maintenant une transmission des données normale
  • Côté serveur, une réponse a consisté à retirer l’annonce de l’extension [email protected] dans la bibliothèque SSH de Go
    • Après avoir annulé le commit concerné et relancé les tests, les résultats étaient les suivants
      • utilisation CPU 29.9 % → 11.6 %,
        appels système 3.10s → 0.66s,
        opérations de chiffrement 1.6s → 0.11s,
        bande passante 6.5Mbit/s → 3Mbit/s
    • Les performances se sont améliorées de plus de 50 %

Expérience de débogage avec un LLM

  • Claude Code a permis d’automatiser l’analyse de tcpdump et tshark, ce qui a aidé à cerner rapidement la cause du problème
    • Il a aussi été possible de conserver un modèle mental du problème en observant l’exécution des commandes en temps réel
  • ChatGPT a au contraire mal interprété le comportement de SSH en le jugeant « normal », ce qui a aussi mis en évidence des différences entre modèles
  • Les LLM ne remplacent pas l’ensemble du processus de résolution, mais se montrent très efficaces comme outils d’analyse d’appoint
  • Il s’agit d’un exemple où le raisonnement humain et l’analyse d’un LLM ont été combinés pour résoudre un problème complexe de performances réseau

1 commentaires

 
GN⁺ 2026-01-23
Réactions sur Hacker News
  • Forker la bibliothèque crypto de Go me semble un peu effrayant
    Je réfléchis à une manière de maintenir mon petit patch en sécurité
    En réalité, je pense que ce genre de fonctionnalité devrait être intégré en upstream comme option de la bibliothèque SSH
    Dans des environnements non fiables, envoyer des paquets de chaff (bruit) est un bon choix par défaut, mais on veut aussi souvent économiser de la bande passante

    • Le contrôler d’une manière qui n’annonce pas la fonctionnalité est une approche trop fragile
      La bonne solution serait d’ajouter une option permettant au serveur de signaler au client que ce n’est “pas nécessaire”, puis au client d’accepter ou d’émettre un avertissement
    • En fait, un comportement proche existe déjà
      Il ne s’applique qu’aux sessions TTY, et le client peut le désactiver
      Mais ici, c’est un cas exceptionnel où le serveur sait à l’avance que la connexion n’est pas sensible
      Dans la plupart des cas, le client s’attend à ce que le paramètre ObscureKeystrokeTiming soit respecté
    • Malgré tout, je pense que ce changement a de fortes chances d’être rejeté
      La bibliothèque crypto est une base de code très normative, au point qu’on ne peut même pas modifier l’ordre des cipher suites TLS
    • Même dans un environnement de confiance, des menaces existent
      Cela ressemble à un cas d’usage SSH très spécifique
      Si on l’expose trop largement, on risque un scénario de type « on configure et on oublie », ce qui pourrait au contraire affaiblir la sécurité
    • Il fut un temps où j’utilisais un ZX80 avec 1 Ko de RAM
      J’ai aussi connu les communications au modem 1200 bps, et les modems 56K étaient en pratique très exagérés
      Vers 1994, je travaillais dans une école militaire au Royaume-Uni et j’ai découvert le WWW pour la première fois ; à l’époque, je m’étais dit « bof »
      Avec le recul, le changement d’époque est vraiment saisissant
  • Je n’avais jamais entendu parler de cette fonction d’obfuscation, c’était intéressant
    Pour déboguer le comportement de ssh, une bonne méthode consiste aussi à patcher le chiffrement None pour voir directement le contenu des paquets
    Si la sécurité n’est pas importante mais que la performance l’est, comme pour un jeu en terminal, on peut aussi envisager d’utiliser telnet

  • Je ne savais pas que SSH faisait ce genre de chose
    Je comprends pourquoi c’est activé par défaut, mais dans mon environnement il vaudrait sans doute mieux le désactiver

    1. Je tape presque jamais de secrets directement via SSH
    2. Il n’y a aucune raison qu’un acteur étatique cherche à sniffer mes frappes
    3. La connexion est intercontinentale, donc économiser la bande passante est important
      Je pense donc régler ObscureKeystrokeTiming=no. Y a-t-il une raison de ne pas le faire ?
    • Une attitude trop optimiste vis-à-vis de la sécurité est dangereuse
      (1) Il n’est pas toujours facile de savoir quand une personne saisit un secret, et l’ensemble de son activité peut faire l’objet d’une analyse de motifs
      (2) C’est une attaque faisable même dans un labo universitaire — voir cet article USENIX et ce cas de recherche
      (3) Sur un Internet dominé par le trafic vidéo, sacrifier la sécurité pour économiser quelques octets de frappes n’a guère de sens
    • Le secret qu’on saisit le plus souvent sur une connexion SSH tty, c’est le mot de passe sudo
      Si un attaquant analyse le timing des frappes, il peut potentiellement estimer les commandes et les motifs du mot de passe chiffré
      Bien sûr, le déchiffrement reste difficile puisque la clé de session change à chaque fois, mais la possibilité existe
      Moi aussi, je copie-colle depuis un gestionnaire de mots de passe pour la plupart de mes mots de passe
    • On ne peut pas être certain qu’un texte en clair divulgué sera inutile à un attaquant
      La plupart des gens ont l’impression qu’ils peuvent désactiver des fonctions de sécurité de SSH sans aucun problème, mais c’est surtout qu’ils ont eu de la chance
      Si la performance est vraiment prioritaire, mieux vaut Telnet ; si la sécurité est vraiment prioritaire, la combinaison ContainerSSH + OAuth2 est préférable
  • En 2004, j’avais fait des recherches sur l’analyse des délais entre frappes dans les sessions SSH pour deviner les commandes
    Voir cette analyse de l’époque
    Le patch de 2023 a donc fini par résoudre ce problème

    • Je me souviens de Dug Song et Solar Designer présentant l’analyse temporelle de SSH à la conférence de hacking HAL2001
      Support de présentation
      Le temps passe vraiment vite
  • Je ne suis pas sûr que Claude ait réellement aidé pour le débogage
    L’auteur semblait déjà savoir dans quelle direction aller, et Claude donnait surtout l’impression d’abonder dans son sens
    Le fait que Claude dise des choses comme “Holy Cow!” est un peu agaçant

    • Malgré tout, si cela l’a aidé à clarifier sa pensée comme avec le Rubber Duck Debugging, ça a de la valeur
      Quand je débogue le fonctionnement d’un système avec Claude, même sans réponse directe, cela m’aide à structurer ma compréhension et à garder la motivation
      Wiki sur le Rubber Duck Debugging
    • Claude est bien plus rapide que moi pour l’extraction de champs dans des pcap ou les traitements awk
    • Les IA excellent à détecter une personnalité dans un texte
      Vu que l’auteur a gardé la réaction “holy cow” dans son billet, Claude semble avoir bien senti l’ambiance
    • Ce n’était peut-être pas une bonne idée de donner une personnalité aux outils de développement
  • En utilisant TCP_CORK, on peut réduire le nombre de paquets sans ajouter de latence
    Désactiver TCP_NODELAY est aussi une option, mais au prix d’une augmentation de la latence

    • Je n’avais jamais entendu parler de TCP_CORK, c’est intéressant
      Si on met le socket en cork, le noyau met les données en tampon puis les envoie au moment de l’uncork ou à l’atteinte du MSS
      Autrement dit, cela regroupe les paquets avant envoi
      Référence
    • Je ne connaissais pas TCP_CORK, mais ça a l’air vraiment utile
      Je recevrai toujours les ping, mais je pourrai probablement réduire le nombre de pong envoyés
      J’ai déjà essayé TCP_NODELAY, mais la latence augmentait trop pour mon jeu
      Ancien post HN
    • Mais comme les paquets de chaff sont envoyés toutes les 20 ms, on peut douter que TCP_CORK puisse les regrouper
      Dans une logique d’obfuscation, la fusion temporelle (coalescing) semble impossible
  • L’expression « The smoking gun! » m’a fait rire
    Je ne suis pas anglophone natif, mais Claude l’utilise souvent, c’est comme ça que je l’ai apprise
    Maintenant, elle se répand presque comme un tic de langage

  • Je trouve dommage cette dépendance aux LLM
    Avec Wireshark, ça aurait sans doute été résolu plus vite en regardant simplement une capture de paquets
    Le dissector SSH est assez mature

    • Je ne suis pas fan des LLM non plus, mais quand on regarde les paquets SSH dans Wireshark, on ne voit généralement que des paquets chiffrés, donc peu d’informations utiles
      Même avec tcpdump sur une seule frappe, on obtient des centaines de paquets chiffrés
      Au final, grâce au LLM, l’auteur a appris quelque chose d’intéressant et l’a partagé, donc cela avait de l’intérêt
    • Le dissector SSH n’est pas parfait
      Après le message NEWKEYS, il ne parse plus, et même avec un patch en chiffrement none, il n’interprète pas complètement le flux
      Il y a encore matière à amélioration
    • Dire « il suffisait de regarder dans Wireshark » sonne comme du gatekeeping
      Apprendre en s’aidant d’outils a tout à fait sa valeur
    • SSH est, dès son nom, un protocole de sécurité
      Il est difficile d’en tirer des informations réellement utiles à partir d’une simple capture de paquets
    • L’auteur ne connaissait pas l’analyseur de paquets SSH, et a simplement utilisé un outil généraliste (LLM) à la place
      Je ne vois pas en quoi ce serait malheureux
  • En 2023, SSH a ajouté une fonctionnalité d’obfuscation du timing des frappes
    Comme on peut deviner les caractères à partir de la vitesse de frappe, SSH mélange des paquets de chaff pour empêcher l’attaquant de les distinguer
    Mais cela me semble être une mauvaise approche
    Si on le voulait vraiment, il suffirait d’envoyer toutes les frappes à intervalles de 50 ms

    • Une latence de 50 ms à la saisie serait probablement très désagréable
    • On ne sait pas très bien si cela veut dire passer de 20 ms à 50 ms, ou bien émettre en continu à intervalles réguliers
      L’implémentation actuelle regroupe par tranches de 20 ms, puis cesse d’envoyer du chaff après un certain temps sans saisie
  • La vocation première de SSH, c’est la sécurité, mais si on n’en a pas besoin, on peut se demander pourquoi utiliser SSH
    Par exemple, netcat (nc) est installé par défaut sur la plupart des plateformes

    • Le fait que « la sécurité soit la priorité n°1 » ne veut pas dire que c’est le seul critère
      Avec SSH, il y a aussi d’autres considérations comme la performance ou la commodité
      L’auteur disait simplement que la fonctionnalité de confidentialité liée à l’obfuscation des frappes ne lui était pas utile
      Il peut tout à fait vouloir conserver le chiffrement et les garanties d’intégrité
      Autrement dit, il choisit de désactiver seulement une partie des fonctions de sécurité de SSH tout en gardant l’essentiel
    • SSH est désormais aussi inclus dans Windows, donc dire que « nc est présent sur toutes les plateformes » n’est pas exact