Le 5 novembre, l'équipe OpenSSH a publié 10.6p2, classé critique, pour un bypass de login qui ne demande aucun code d'exploit, aucune corruption de mémoire ni payload astucieux. Tu envoies un mot de passe de plus de 256 caractères à un compte qui n'a aucun mot de passe. Tu entres.
La faille ne vit pas dans un coin oublié d'internet. Elle vit dans Alpine Linux, et donc dans une très grande part des images de conteneurs que ton équipe télécharge chaque semaine. Si tu as un utilisateur de déploiement en clé seule sur un hôte Alpine avec l'authentification par mot de passe laissée par défaut, ce compte n'est plus en clé seule.
Voici la partie qui doit retenir ton attention : les comptes à risque sont ceux que tu as durcis.
Ce qui se passe vraiment sur le fil
Sans PAM, sshd vérifie lui-même les mots de passe. Il prend la tentative, la hache avec crypt() et compare le résultat au champ stocké dans /etc/shadow. Un compte normal stocke quelque chose comme $6$abc$k2P9... : un marqueur d'algorithme, un sel, un hachage.
Un compte sans mot de passe stocke un seul *. Ce marqueur n'est pas un hachage et aucun mot de passe ne peut jamais correspondre. C'est ainsi depuis 1980, quand Bill Joy a mis un * dans le champ de mot de passe du compte daemon dans 3BSD. Quinze mots d'intention, toujours respectés par tous les Unix de la planète.
Mais un * est trop court pour contenir un sel. Donc sshd en emprunte un : il prend le sel d'un autre compte local qui a un vrai hachage, hache ta tentative quand même et compare. Cet emprunt est arrivé en juillet 2016 comme correctif de CVE-2016-6210, un oracle de timing qui permettait aux attaquants d'énumérer les noms d'utilisateur valides. Perdre le même temps sur un utilisateur inexistant était tout le point.
Ajoute maintenant 2012. musl, la bibliothèque C sur laquelle Alpine est construit, a changé crypt() pour qu'un appel échoué renvoie un seul * au lieu de NULL, parce que trop de programmes ne vérifiaient jamais NULL et plantaient tout simplement. Vingt jours plus tard, musl a plafonné le hachage sha256 et sha512 à 256 octets pour stopper les attaques par déni de service qui nourrissent le hacheur d'entrées énormes.
Mets ces décisions dans un seul processus et la logique s'inverse :
- Le champ stocké est
*. - Ton mot de passe fait 257 octets ou plus, donc
crypt()le refuse et renvoie*. - sshd compare
*avec*. - Ça correspond.
Le chemin d'erreur est la porte. Pas un bug au sens d'une écriture mémoire égarée, mais une chaîne de quatre décisions individuellement raisonnables, prises à des décennies d'écart, qui s'accordent maintenant sur la mauvaise réponse.
Qui est vraiment exposé
L'avis d'Alpine liste quatre conditions qui doivent toutes être vraies :
- Le serveur exécute
openssh-server, construit sans PAM, ou exécuteopenssh-server-pamavecUsePAM no. PasswordAuthenticationestyes, ce qui est la valeur par défaut d'OpenSSH.- Un compte a
*dans son champ de mot de passe, ce qui signifie qu'aucun mot de passe n'est défini. - Au moins un autre compte local a un hachage
$5$ou$6$.
Cette dernière condition est la silencieuse. Un seul compte n'importe où sur la machine avec un hachage de mot de passe moderne suffit à exposer tous les comptes sans en avoir un. Sur Alpine, les comptes sans mot de passe incluent les utilisateurs en clé seule créés avec adduser, les utilisateurs de répertoire arrivant via musl-nscd, et root, qui est livré comme root:* depuis Alpine 3.16.
Root est toujours protégé par PermitRootLogin prohibit-password sauf si tu l'as changé. Ce bouclier signifie moins qu'il n'y paraît si un compte exposé peut escalader : les images tiny-cloud de 3.18.11 à 3.24.3 donnent à l'utilisateur alpine un doas sans mot de passe. Ces images sont sûres au premier démarrage et deviennent ouvertes dès qu'un hachage $6$ existe sur la machine, ce qui arrive la première fois qu'un admin définit un mot de passe de console.
L'attaquant a besoin d'un accès réseau, d'un nom de compte et d'un mot de passe entre 257 et 1 024 octets. L'avis dit que ça réussit à chaque tentative, sur une seule connexion. Aucune attaque l'utilisant n'avait été signalée quand le correctif est sorti.
Non affectés : les systèmes non Linux, le Linux basé sur glibc, tout ce qui vérifie les mots de passe via PAM, les systèmes avec PasswordAuthentication no, les comptes verrouillés avec ! plutôt que *, les conteneurs qui n'exécutent pas sshd, et les machines où aucun compte ne porte un hachage de style $. OpenWrt va en grande partie bien parce qu'il utilise par défaut Dropbear. Buildroot et Yocto méritent un coup d'œil.
Que faire aujourd'hui
Le chercheur qui l'a trouvé, Özgün Kültekin de Wakefield, a publié une analyse complète sur sshhole.com, et le surnom qui a collé n'est pas imprimable dans un deck client. La remédiation est ennuyeuse et rapide :
- Mets à jour. Lance
apk upgrade -U -a, puisrc-service sshd restart. Mettre à jour le paquet ne redémarre pas le daemon en cours d'exécution, donc le redémarrage n'est pas optionnel. Versions corrigées : 3.21.10, 3.22.8, 3.23.8 et 3.24.4. Les branches jusqu'à 3.16 sont en fin de support mais ont reçu des paquets aussi. - Si tu ne peux pas patcher immédiatement, désactive les logins par mot de passe. Confirme que ton login par clé fonctionne dans une deuxième session avant de fermer la première. Mets
PasswordAuthentication no, lancesshd -t, redémarre sshd. Vérifie avecsshd -T | grep -i passwordauthentication. - Chasse. Greppe
/var/log/messagespourAccepted password forcontre un compte sans mot de passe :alpine,root, un utilisateur de déploiement en clé seule. Examine l'usage dedoas, les utilisateurs récemment créés, les clés autorisées modifiées et les changements de fichiers. - Si tu ne peux pas exclure un login, traite la machine comme compromise. L'avis est aussi direct, et il a raison.
Si tu construis OpenSSH toi-même, 10.6p2 contient le changement : sshd refuse désormais une correspondance quand le champ stocké fait moins de quatre caractères. OpenSSH appelle ça un contournement et pointe musl comme cause racine.
Pourquoi le correctif est arrivé en un jour
Aucun identifiant CVE n'avait été attribué quand l'avis est sorti. Damien Miller a été explicite sur pourquoi son équipe a bougé à cette vitesse : les longs embargos sont dangereux maintenant, et aident surtout les attaquants, parce que le projet a récemment observé des agents d'IA redécouvrir les mêmes bugs, parfois en quelques heures.
Lis cette phrase deux fois, parce que c'est la vraie histoire. La vulnérabilité est un choix de conception de 2016 qui entre en collision avec un changement de bibliothèque de 2012. Le temps de réponse est fixé par les machines qui lisent du code toute la nuit et peuvent re-dériver une découverte depuis une piste partiellement publique en une journée de travail. Les fenêtres d'embargo se mesuraient autrefois à l'attention humaine. Elles se mesurent maintenant au débit d'inférence.
Ce que ça veut dire pour ton équipe
Trois choses, et seule la première parle d'OpenSSH.
Audite l'image de base, pas seulement l'application. La plupart des équipes que nous rencontrons peuvent nommer leur version de framework et ne peuvent pas nommer leur libc. L'ubiquité d'Alpine dans les conteneurs fait que les défauts de musl sont tes défauts, et musl a pris en 2012 une décision défendable qui est devenue un bypass d'authentification en 2026.
Écris tes hypothèses pour qu'elles puissent être falsifiées. "Les comptes en clé seule ne peuvent pas se connecter avec un mot de passe" était vrai, largement cru et copié dans des centaines de runbooks internes. Ça a cessé d'être vrai sans que personne n'édite les runbooks.
Suppose que ton compte le plus silencieux est celui qui compte. Le compte sans mot de passe, sans historique de shell, sans propriétaire dans l'organigramme. Dans cette faille c'était la cible, et un hachage $6$ égaré n'importe où sur la machine en a fait la porte d'entrée.
Patche, redémarre, vérifie. Puis pose la question qui paye vraiment : laquelle de nos hypothèses n'a pas été re-testée depuis que les machines sont devenues plus rapides que nous ?