Neutron, notre moteur d’IA, a obtenu un score de 97,1 % sur le benchmark CyberGym de l’UC Berkeley. En savoir plus

Analyse approfondie

Analyse approfondie

Contournement du mot de passe OpenSSH sur musl, corrigé en 10.6p2 (CVE-2026-123158)

OpenSSH sur musl sans PAM accepte un mot de passe de 257 octets pour les comptes verrouillés ; corrigé en 10.6p2 et dans les paquets Alpine.

En bref

  • Le sshd d'OpenSSH avec musl sans PAM accepte tout mot de passe de plus de 256 octets pour les comptes dont le champ shadow vaut *. Le projet OpenSSH a publié CVE-2026-123158 et la version 10.6p2 le 5 novembre 2026.
  • Les serveurs Alpine qui exécutent sshd avec authentification par mot de passe sont exposés si un autre compte local a un hachage $5$ ou $6$. Les images Alpine sont largement déployées ; les conteneurs sans sshd sont hors de cause.
  • MITRE attribue CVSS v3.1 8,1 High (CWE-394). Un laboratoire public et deux dépôts de preuve de concept existent ; aucune exploitation dans la nature n'a été signalée, et la CVE n'est pas au catalogue KEV au 6 novembre 2026.
  • Mettez à niveau vers OpenSSH 10.6p2, ou vers le paquet Alpine corrigé de votre branche, puis redémarrez sshd. Si vous ne pouvez pas, réglez PasswordAuthentication no ; voir « Comment corriger ? ».

Suis-je concerné ?

Vous êtes exposé uniquement lorsque toutes ces conditions sont réunies :

  • L'hôte exécute OpenSSH avant 10.6p2, ou un paquet openssh Alpine inférieur à la version corrigée du tableau.
  • sshd est compilé et exécuté avec musl et sans PAM. Le paquet openssh-server d'Alpine est compilé sans PAM. openssh-server-pam avec UsePAM yes n'est pas concerné ; le même paquet avec UsePAM no l'est.
  • PasswordAuthentication yes est actif. C'est la valeur par défaut d'OpenSSH.
  • Au moins un compte joignable par mot de passe a * comme champ de mot de passe shadow. Sur Alpine, cela inclut root, qui est livré avec root:* dans l'image de base depuis environ Alpine 3.16, les utilisateurs à clé créés avec adduser sans mot de passe, les utilisateurs d'un service d'annuaire sans entrée shadow, et l'utilisateur alpine des images officielles tiny-cloud.
  • Au moins un compte local possède un hachage crypt $5$ ou $6$, pour que sshd puisse emprunter un sel. Une machine sans aucun hachage SHA-256 ni SHA-512 n'atteint pas la faille.

Pour root, la valeur par défaut PermitRootLogin prohibit-password bloque encore les connexions par mot de passe. Root devient joignable lorsque PermitRootLogin yes est réglé, ou lorsqu'un autre compte * qui peut se connecter dispose d'une voie vers root, comme doas sans mot de passe sur les images tiny-cloud.

Les conteneurs qui n'exécutent pas sshd ne sont pas concernés. Les comptes verrouillés avec ! ne peuvent se connecter ni par mot de passe ni par clé, donc ils ne sont pas une cible. Les systèmes avec PasswordAuthentication no, ceux qui utilisent openssh-server-pam avec UsePAM yes et ceux qui n'ont aucun hachage $ sont aussi hors de cette faille.

Branche Versions concernées Version corrigée
OpenSSH amont (musl, PAM désactivé) 10.6p1 et antérieures 10.6p2 (publiée le 5 novembre 2026)
Alpine edge avant 10.6_p2-r0 10.6_p2-r0
Alpine 3.24 avant 10.3_p1-r2 10.3_p1-r2 (version ponctuelle 3.24.4)
Alpine 3.23 avant 10.2_p1-r1 10.2_p1-r1 (version ponctuelle 3.23.8)
Alpine 3.22 avant 10.0_p1-r11 10.0_p1-r11 (version ponctuelle 3.22.8)
Alpine 3.21 avant 9.9_p2-r1 9.9_p2-r1 (version ponctuelle 3.21.10)
Alpine 3.20 avant 9.7_p1-r6 9.7_p1-r6
Alpine 3.19 avant 9.6_p1-r3 9.6_p1-r3
Alpine 3.18 avant 9.3_p2-r4 9.3_p2-r4
Alpine 3.17 avant 9.1_p1-r7 9.1_p1-r7
Alpine 3.16 avant 9.0_p1-r6 9.0_p1-r6

Alpine a publié des paquets corrigés pour chaque branche de 3.16 à 3.24 et pour edge, y compris les versions qui ne reçoivent plus de mises à jour régulières. Les quatre versions ponctuelles actuelles qui portent le correctif sont 3.21.10, 3.22.8, 3.23.8 et 3.24.4.

Vérifiez ce que l'hôte exécute :

# Alpine: the installed OpenSSH packages and versions
apk info -v openssh-server openssh-server-pam 2>/dev/null

# Whether this sshd uses PAM (no means the vulnerable build on Alpine)
sshd -T 2>/dev/null | grep -i '^usepam'

# Whether password authentication is on
sshd -T 2>/dev/null | grep -i '^passwordauthentication'

# Accounts whose shadow password field is exactly *
sudo awk -F: '$2=="*"{print $1}' /etc/shadow

# Whether any local account has a SHA-256 or SHA-512 hash
sudo awk -F: '$2 ~ /^\$[56]\$/{print $1}' /etc/shadow

sshd -T exige root et une configuration lisible. Sur un système musl qui n'est pas Alpine, comme OpenWrt, Buildroot ou Yocto, utilisez le gestionnaire de paquets de la distribution et ssh -V pour identifier la version d'OpenSSH, puis comparez-la au paquet corrigé du fournisseur.

Comment corriger ?

  1. Sur Alpine, mettez le paquet à niveau et redémarrez sshd : apk upgrade -U -a rc-service sshd restart La mise à niveau ne redémarre pas un sshd en cours d'exécution ; le redémarrage est donc nécessaire. Reconstruisez toute image de conteneur à partir de la base ou du paquet corrigé et recréez le conteneur ; tirer une nouvelle image sans recréer le conteneur laisse l'ancien processus en place.
  2. Sur un autre système musl, mettez OpenSSH à niveau vers 10.6p2 ou vers le paquet corrigé de la distribution. Les notes de version d'OpenSSH 10.6p2 nomment le correctif, et l'avis d'Alpine liste le paquet corrigé pour chaque branche.
  3. Si vous ne pouvez pas mettre à niveau, désactivez l'authentification par mot de passe. Gardez votre session actuelle ouverte et testez une connexion par clé avant de la fermer. Sur Alpine 3.19 et ultérieur, le fichier drop-in suffit : mkdir -p /etc/ssh/sshd_config.d echo 'PasswordAuthentication no' > /etc/ssh/sshd_config.d/00-no-passwords.conf sshd -t && rc-service sshd restart sshd -T | grep -i passwordauthentication Sur les versions Alpine plus anciennes, qui ignorent le répertoire drop-in, modifiez directement /etc/ssh/sshd_config et redémarrez sshd. Régler PasswordAuthentication no supprime aussi les connexions par mot de passe des comptes qui ont un vrai hachage ; c'est le coût prévu.
  4. Si vous avez besoin de l'authentification par mot de passe et ne pouvez pas mettre à niveau, supprimez les cibles * ou rendez-les injoignables. Verrouillez les comptes inutilisés avec un champ ! au lieu de *, ou supprimez-les. Un champ ! bloque aussi les connexions par clé ; gardez une autre session administrative ouverte. Cela ferme le chemin de ce compte précis mais ne corrige pas la comparaison ; mettez à niveau dès que possible.

Quelle est la cause racine ?

La faille est une comparaison entre deux chaînes qui valent toutes deux *, l'une parce que le compte n'a pas de mot de passe et l'autre parce que crypt() de musl utilise * comme valeur d'erreur. Dans auth-passwd.c, sshd sans PAM prend le champ de mot de passe stocké et hache le mot de passe fourni avec lui :

char *pw_password = authctxt->valid ? shadow_pw(pw) : pw->pw_passwd;

if (pw_password == NULL)
    return 0;

/* Check for users with no password. */
if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0)
    return (1);

/*
 * Encrypt the candidate password using the proper salt, or pass a
 * NULL and let xcrypt pick one.
 */
if (authctxt->valid && pw_password[0] && pw_password[1])
    salt = pw_password;
encrypted_password = xcrypt(password, salt);

/*
 * Authentication is accepted if the encrypted passwords
 * are identical.
 */
return encrypted_password != NULL &&
    strcmp(encrypted_password, pw_password) == 0;

Pour un compte dont le champ vaut *, pw_password[1] est le NUL de fin, donc salt reste NULL. xcrypt() appelle alors pick_salt(), qui parcourt la base des comptes jusqu'à trouver un champ $5$ ou $6$ et renvoie le type et le sel de ce hachage :

if (salt == NULL)
    salt = pick_salt();
...
crypted = crypt(password, salt);

L'implémentation SHA-512 de musl rejette une clé de plus de 256 octets. La limite est une protection contre le déni de service, car le chiffrement SHA-512 ralentit à mesure que la clé grandit :

#define KEY_MAX 256
...
/* reject large keys */
for (i = 0; i <= KEY_MAX && key[i]; i++);
if (i > KEY_MAX)
    return 0;

Lorsque la fonction interne renvoie 0, __crypt_sha512() de musl renvoie la chaîne * :

p = sha512crypt(key, setting, output);
...
if (!p || q != testbuf || memcmp(testbuf, testhash, sizeof testhash))
    return "*";
return p;

sshd compare le * renvoyé au * stocké et accepte la connexion. OpenSSH limite le mot de passe fourni à 1024 octets, donc la plage qui réussit va de 257 à 1024 octets. L'enregistrement CVE la décrit comme 256 à 1024 ; la clé de 256 octets est encore acceptée par musl et produit un vrai hachage, donc 257 est la valeur la plus courte qui déclenche le retour d'erreur.

La faille est devenue atteignable en 2016, lorsque OpenSSH a ajouté pick_salt() comme correctif du canal temporel CVE-2016-6210. Avant ce changement, un compte * était haché avec le sel DES fixe xx, qui ne renvoyait pas *.

Comment la faille est-elle exploitée ?

  1. L'attaquant trouve un service SSH sur un système musl dont l'authentification par mot de passe est active.
  2. La cible possède un compte * joignable par mot de passe : root avec PermitRootLogin yes, un utilisateur de déploiement à clé, un utilisateur d'annuaire, ou l'utilisateur alpine d'une image tiny-cloud.
  3. Un autre compte local possède un hachage $5$ ou $6$, donc sshd peut emprunter son sel.
  4. L'attaquant envoie un mot de passe de 257 à 1024 octets pour le compte *. Les caractères n'ont pas d'importance.
  5. sshd hache le long mot de passe avec le sel emprunté. musl renvoie * ; la comparaison avec le * stocké réussit, et l'attaquant obtient un shell sous ce compte.

Le laboratoire public de sshhole.com permet d'essayer la comparaison dans un navigateur, et l'enregistrement CVE liste deux dépôts de preuve de concept. Aucune exploitation dans la nature n'a été signalée publiquement au 6 novembre 2026.

Comment se déroule l'attaque ?

Un long mot de passe pour un compte sans mot de passe atteint le retour d'erreur * de musl, et sshd l'accepte parce que le champ stocké vaut aussi *.

flowchart LR A["L'attaquant envoie un mot de passe de 257 octets ou plus"] --> B["sshd emprunte un sel $6$ à un autre compte"] B --> C["musl rejette la longue clé et renvoie *"] C --> D["sshd compare * au * stocké"] D --> E["Connexion acceptée sous le compte verrouillé"]

Que peut faire un attaquant ?

Un attaquant peut se connecter à tout compte * joignable par authentification par mot de passe, avec les privilèges de ce compte. L'impact dépend du compte :

  • Root sur Alpine, lorsque PermitRootLogin yes est réglé : contrôle total de l'hôte.
  • L'utilisateur alpine d'une image tiny-cloud, qui dispose de doas sans mot de passe : root sur l'instance.
  • Un utilisateur de déploiement à clé : l'attaquant obtient le shell que cet utilisateur aurait eu, avec ses clés, ses identifiants cloud et son accès à l'application.
  • Un utilisateur d'annuaire sans entrée shadow : l'attaquant usurpe cet utilisateur.

Toutes les conditions de « Suis-je concerné ? » s'appliquent : musl, PAM désactivé, authentification par mot de passe active, un compte *, un hachage $5$ ou $6$ ailleurs, et la joignabilité réseau. La faille ne révèle ni ne casse un vrai hachage de mot de passe, et elle ne touche pas les comptes verrouillés avec !. Ce n'est pas une faille de pré-authentification au sens d'un contournement du protocole SSH ; l'attaquant termine une connexion par mot de passe normale, avec un mot de passe que le serveur aurait dû rejeter.

Pourquoi le correctif fonctionne-t-il ?

Le correctif ajoute une longueur minimale pour un hachage stocké et refuse de comparer un champ d'un seul caractère :

+#define MIN_PASSWORD_HASH_LEN  4
 #define MAX_PASSWORD_LEN   1024
@@
-   return encrypted_password != NULL &&
+   ret = encrypted_password != NULL &&
+       strlen(pw_password) >= MIN_PASSWORD_HASH_LEN &&
        strcmp(encrypted_password, pw_password) == 0;
+   freezero(pw_password, strlen(pw_password));
+   return ret;

Un champ * fait un octet, sous le nouveau minimum de quatre octets, donc la comparaison est fausse même lorsque musl renvoie *. Un vrai champ SHA-512 est bien plus long que quatre octets : $6$, un sel et le hachage. Le même changement est appliqué aux chemins de mot de passe portable et UnixWare, et le correctif libère aussi la copie shadow. Le projet OpenSSH parle d'un contournement parce que la cause racine est la valeur d'erreur de musl, mais il ferme le chemin de sshd. Les paquets stables d'Alpine portent le même correctif.

Comment vérifier si j'ai été compromis ?

Il n'existe aucun indicateur de compromission publié. Une connexion réussie laisse une ligne Accepted password pour un compte qui ne devrait jamais accepter de mot de passe ; commencez par là :

# Alpine and other syslog-based systems
sudo grep -i "Accepted password" /var/log/messages

# Compare the account name with the * accounts on the host
sudo awk -F: '$2=="*"{print $1}' /etc/shadow

Un résultat est une piste, pas une preuve : un compte avec un vrai hachage peut aussi produire une ligne Accepted password. Vérifiez l'adresse source et l'heure par rapport à vos propres connexions. Passez ensuite en revue l'usage de doas et sudo, les utilisateurs récemment créés, les nouvelles entrées authorized_keys, et les fichiers ou services que le compte pouvait atteindre. Sur une image tiny-cloud, vérifiez si l'utilisateur alpine s'est connecté depuis une adresse que vous ne reconnaissez pas.

Une tentative échouée ne laisse pas de trace particulière, et une tentative réussie peut avoir été supprimée des journaux. Si vous ne pouvez pas exclure une connexion, traitez l'hôte comme compromis, reconstruisez-le à partir d'une image de confiance et renouvelez tous les identifiants qu'il pouvait atteindre.

Chronologie

  • 2012-08 : musl modifie crypt() pour renvoyer * au lieu de NULL lorsqu'il ne peut pas calculer de hachage.
  • 2012-08-29 : musl limite les clés SHA-512 crypt à 256 octets, ce qui fait renvoyer * au chemin des longues clés.
  • 2016-07 : OpenSSH ajoute pick_salt() pour les utilisateurs invalides comme correctif temporel de CVE-2016-6210, ce qui rend la comparaison * atteignable.
  • 2026-10-30 : une revue de sécurité d'OpenSSH corrige pick_salt() ; la comparaison vulnérable se trouve quatre lignes plus bas.
  • 2026-11-05 : OpenSSH 10.6p2 est publié, CVE-2026-123158 est publiée, et Alpine publie son avis et ses paquets corrigés.
  • 2026-11-06 : aucune exploitation dans la nature n'a été signalée publiquement ; la CVE n'est pas au catalogue KEV de la CISA.

La faille a vécu dans musl et OpenSSH pendant 14 ans avant le correctif de 2026.
Figure 1 : de la valeur d'erreur de musl en 2012 au correctif OpenSSH de 2026. Source : commits musl b3c4cc12 et 88bf5a8a, notes de version d'OpenSSH 10.6p2 et CVE-2026-123158, vérifiés le 6 novembre 2026

FAQ

Cette faille touche-t-elle Debian, Ubuntu ou Fedora ?

Non. Ces systèmes utilisent glibc et PAM, et le contournement exige le retour d'erreur * de musl avec PAM désactivé. La même version d'OpenSSH sur glibc ne prend pas ce chemin.

J'utilise Alpine mais uniquement des connexions par clé. Suis-je concerné ?

Oui, si PasswordAuthentication est encore actif et qu'un compte * existe. L'attaquant se connecte au compte * avec un long mot de passe ; votre méthode de connexion par clé n'a pas d'importance. Réglez PasswordAuthentication no ou mettez à niveau.

Root est-il exploitable par défaut ?

Non, pas par défaut. Alpine livre root avec un champ *, mais la valeur par défaut PermitRootLogin prohibit-password d'OpenSSH bloque les connexions par mot de passe pour root. Root devient joignable lorsque PermitRootLogin yes est réglé, ou lorsqu'un autre compte * peut s'élever, comme l'utilisateur alpine avec doas sans mot de passe.

Existe-t-il une CVE à suivre ?

Oui. CVE-2026-123158 a été publiée le 5 novembre 2026 avec CVSS v3.1 8,1 High et CWE-394. L'avis d'OpenSSH et l'avis d'Alpine sont les sources de remédiation principales.

La faille a-t-elle été exploitée dans la nature ?

Aucun rapport public d'exploitation n'existe au 6 novembre 2026, et l'évaluation SSVC de la CISA enregistre une preuve de concept publique mais pas d'exploitation active. La faille est assez ancienne pour qu'une connexion discrète ne puisse pas être exclue à partir des données publiques ; vérifiez les journaux.

Dois-je renouveler les clés SSH ?

Seulement si vous trouvez la preuve d'une connexion que vous ne pouvez pas expliquer. Si l'hôte a été accédé, traitez toutes les clés et tous les identifiants qu'il pouvait atteindre comme exposés et renouvelez-les après la reconstruction. Si les journaux sont propres, la mise à niveau et le redémarrage de sshd suffisent.

Trouvez les services SSH exposés avec Ostorlab

La découverte de surface d'attaque d'Ostorlab inventorie vos hôtes exposés à Internet et les services qu'ils exposent. Utilisez-la pour lister les machines qui répondent sur le port TCP 22, puis vérifiez d'abord leur version d'OpenSSH et leur réglage d'authentification par mot de passe.

Références

  • Notes de version d'OpenSSH 10.6p2, 5 novembre 2026, le contournement de l'authentification par mot de passe et le crédit à Özgün Kültekin : https://www.openssh.org/releasenotes.html#10.6p2 (vérifié le 6 novembre 2026)
  • Commit OpenSSH 4353fdc43ef646c43a8dda7025cc1a898caf1482, « avoid password authn bypass », 5 novembre 2026, la vérification MIN_PASSWORD_HASH_LEN : https://github.com/openssh/openssh-portable/commit/4353fdc43ef646c43a8dda7025cc1a898caf1482 (vérifié le 6 novembre 2026)
  • Enregistrement CVE-2026-123158, MITRE, publié le 5 novembre 2026, CVSS v3.1 8.1, CWE-394 et les références de preuve de concept : https://www.cve.org/CVERecord?id=CVE-2026-123158 (vérifié le 6 novembre 2026)
  • Alpine Linux, « OpenSSH password authentication bypass », 5 novembre 2026, les configurations concernées, les versions corrigées et le contournement : https://alpinelinux.org/posts/2026-11-05-openssh-password-authentication-bypass/ (vérifié le 6 novembre 2026)
  • « sshhole », l'analyse de la chercheuse et le laboratoire navigateur, l'histoire de musl et d'OpenSSH et les conditions d'exploitation : https://sshhole.com/ (vérifié le 6 novembre 2026)
  • Commit musl b3c4cc12, « crypt: return "*" instead of NULL on failure », août 2012 : https://git.musl-libc.org/cgit/musl/commit/?id=b3c4cc12 (vérifié le 6 novembre 2026)
  • Commit musl 88bf5a8a, la limite de 256 octets pour les clés SHA-512, 29 août 2012 : https://git.musl-libc.org/cgit/musl/commit/?id=88bf5a8a (vérifié le 6 novembre 2026)
  • Fichier auth-passwd.c d'OpenSSH à l'étiquette 10.6p1, la comparaison vulnérable : https://github.com/openssh/openssh-portable/blob/V_10_6_P1/auth-passwd.c (vérifié le 6 novembre 2026)
  • Fichier openbsd-compat/xcrypt.c d'OpenSSH à l'étiquette 10.6p1, pick_salt() et xcrypt() : https://github.com/openssh/openssh-portable/blob/V_10_6_P1/openbsd-compat/xcrypt.c (vérifié le 6 novembre 2026)
  • Docker Hub, l'image officielle alpine, 12 476 923 091 téléchargements, le chiffre de portée : https://hub.docker.com/_/alpine (vérifié le 6 novembre 2026)
  • Flux JSON du catalogue Known Exploited Vulnerabilities de la CISA, vérifié pour CVE-2026-123158 le 6 novembre 2026 (non listée) : https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json (vérifié le 6 novembre 2026)