Blog

SSHole: Ein Passwort mit 257 Bytes öffnet unter Alpine Linux Konten ohne Passwort

Unter Alpine Linux und anderen Systemen, auf denen OpenSSH mit der C-Bibliothek musl und ohne PAM läuft, meldet ein Passwort mit mehr als 256 Bytes bei Konten an, die gar kein Passwort haben. Die Lücke CVE-2026-123158, genannt SSHole, wurde am 5. November behoben, und weniger als einen Tag später hatten Angreifer root auf einem Honeypot. Wer sshd unter Alpine betreibt, sollte jetzt aktualisieren und sshd neu starten.

Was passiert

Konten, die sich nur mit Schlüssel anmelden, haben im Passwortfeld oft einen einzelnen Stern. Nach einer Konvention, die so alt ist wie Unix, ist * nie ein gültiger Hash, also kann kein Passwort dazu passen. Unter Alpine wird root seit etwa Version 3.16 so ausgeliefert, ebenso Benutzer, die mit adduser ohne Passwort angelegt wurden, und der Benutzer alpine der offiziellen Cloud-Images.

Ist sshd ohne PAM gebaut, wie das Paket openssh-server von Alpine, prüft er Passwörter selbst: Er hasht den Versuch mit crypt() und vergleicht das Ergebnis mit dem gespeicherten Feld. Für ein Feld wie *, das kein Salt enthält, leiht er sich das Salt eines anderen Kontos. musls crypt() lehnt bei SHA-256 und SHA-512 Schlüssel mit mehr als 256 Bytes ab und gibt dann als Fehlerzeichen * zurück. Genau das ist für das Konto gespeichert, also geht der Vergleich auf. Gefunden und dem OpenSSH-Projekt gemeldet hat die Lücke Özgün Kültekin von Wakefield.

Diagramm: Der Angreifer schickt für ein Konto, dessen Passwortfeld ein Stern ist, ein Passwort von 257 bis 1024 Bytes; sshd leiht sich das Salt eines anderen Kontos; musls crypt() scheitert an der langen Eingabe und gibt einen Stern zurück; sshd vergleicht Stern mit Stern und lässt den Login zu; der Angreifer hat eine Shell mit den Rechten dieses Kontos. Abgeschaltete Passwort-Anmeldung stoppt den ersten Schritt, OpenSSH 10.6p2 den Vergleich.
Nach den Release Notes von OpenSSH 10.6p2, dem Advisory von Alpine und der Beschreibung des Forschers. Gilt nur für sshd auf musl ohne PAM.

Der Angreifer braucht den Namen eines solchen Kontos, Zugang zum SSH-Port und auf der Maschine mindestens ein weiteres Konto mit echtem $5$- oder $6$-Hash, weil es sonst kein SHA-Salt zum Ausleihen gibt. Alpine sagt es deutlich: Ein einziger Benutzer mit Passwort genügt, damit jedes Konto ohne Passwort erreichbar ist. Es braucht eine Verbindung, klappt jedes Mal und ohne Raten. Passwörter über 1024 Bytes lehnt sshd selbst ab, daher das Fenster von 257 bis 1024 Bytes.

Der Angreifer bekommt eine Shell mit den Rechten dieses Kontos. root ist durch die OpenSSH-Voreinstellung PermitRootLogin prohibit-password vor Passwort-Logins geschützt und nur mit PermitRootLogin yes direkt erreichbar. Das hilft nichts, wenn ein anderes Konto root werden kann. Die Tiny-Cloud-Images von Alpine von 3.18.11 bis 3.24.3 liefern einen Benutzer alpine mit * und doas ohne Passwort aus. Beim ersten Start sind sie sicher, angreifbar werden sie, sobald irgendein $6$-Hash existiert, etwa weil ein Admin ein Konsolen-Passwort gesetzt oder die User-Data einen Benutzer mit gehashtem Passwort angelegt hat.

Wer betroffen ist

Das ist keine Lücke in OpenSSH überall. glibc-Distributionen wie Debian, Ubuntu oder RHEL hashen anders, und mit PAM läuft die Passwortprüfung gar nicht durch diesen Code. Betroffen sind Linux-Systeme, auf denen sshd mit musl läuft und Passwörter selbst prüft. Alpine ist der bekannteste Fall, weil das Standardpaket ohne PAM gebaut ist und OpenSSH Passwort-Logins standardmässig erlaubt. Alpine hat jede Version von 3.16 bis 3.24 und edge geprüft, alle sind betroffen.

Zwei Karten. Betroffen nur, wenn alles zutrifft: sshd läuft auf musl, zum Beispiel Alpine, OpenWrt, Buildroot oder Yocto; er prüft Passwörter ohne PAM; PasswordAuthentication steht auf yes; und es gibt ein Konto mit einem Stern als Passwort und mindestens ein Konto mit einem $5$- oder $6$-Hash. Nicht betroffen: glibc-Distributionen, sshd mit UsePAM yes, Dropbear, OpenBSD und andere Nicht-Linux-Systeme, Container ohne sshd, PasswordAuthentication no und gesperrte Konten mit Ausrufezeichen.

musl steckt nicht nur in Alpine. Es ist auch die C-Bibliothek von OpenWrt und eine häufige Wahl in Firmware, die mit Buildroot oder Yocto gebaut wird, also in Routern, Appliances und eingebetteten Geräten. OpenWrt nutzt standardmässig Dropbear, das nicht betroffen ist, aber jedes Gerät, das OpenSSH mit musl und ohne PAM mitbringt, verdient einen Blick. Container auf Basis von Alpine sind nur gefährdet, wenn darin sshd läuft, was bei den meisten nicht der Fall ist.

Wie es dazu kam

Das OpenSSH-Projekt sieht die eigentliche Ursache ausserhalb von sshd, umgeht sie mit Version 10.6p2 aber dort. Interessant an dem Fehler ist, dass jedes Teil für sich ein vernünftiger Entscheid war. musl entschied 2012, statt NULL einen Hash zurückzugeben, der zu nichts passt, damit Programme ohne Fehlerprüfung nicht abstürzen. OpenSSH hasht seit 2016 jeden Versuch mit echtem Salt, nachdem ein Forscher gezeigt hatte, dass lange Passwörter bei existierenden Benutzern messbar länger brauchten als bei unbekannten. Und Alpine gab root 2022 einen * statt eines gesperrten Felds, damit Logins mit Schlüssel weiter funktionieren. Erst zusammen machen sie aus einem Fehlerzeichen ein gültiges Passwort.

Chronologie: August 2012 gibt musls crypt() bei Fehlern einen Stern statt NULL zurück und begrenzt SHA-crypt auf 256 Bytes; Juli 2016 leiht sich OpenSSH für Konten ohne Hash ein Salt, gegen das Erraten von Benutzernamen; 2019 liefert Alpine Docker-Images mit root ohne Passwort aus, CVE-2019-5021, und root wird gesperrt; 2022 setzt Alpine 3.16 root auf einen Stern; 5. November 2026 OpenSSH 10.6p2 und die korrigierten Pakete von Alpine.
Daten aus der Beschreibung des Forschers, den Release Notes von OpenSSH und dem Advisory von Alpine. Jeder Schritt war für sich genommen sinnvoll.

Angegriffen innert Stunden

OpenSSH 10.6p2 und das Advisory von Alpine erschienen am 5. November, mit korrigierten Paketen für jeden Alpine-Zweig bis zurück zu 3.16, auch für die nicht mehr unterstützten. Am Nachmittag folgte das CVE, keine zwei Stunden später der erste öffentliche Proof of Concept. Laut der Threat-Intelligence-Firma Previdian sahen ihre Sensoren die ersten Angriffsversuche weniger als neun Stunden nach der Veröffentlichung des CVE. Gegenüber The Hacker News sagte Previdian, sie habe Root-Zugriff auf einem Honeypot mit Alpine und OpenSSH bestätigt: Eine Adresse in Japan schickte überlange Passwörter und führte danach in nicht interaktiven Sitzungen id, uname und hostname aus. Angriffe auf echte Opfer sind bisher nicht bekannt, und Safe Security schrieb am 6. November noch, Angriffe in freier Wildbahn seien nicht bestätigt.

Chronologie: 5. November OpenSSH 10.6p2 und das Advisory von Alpine mit korrigierten Paketen bis zurück zu 3.16; 15:46 UTC CVE-2026-123158 veröffentlicht; 17:30 UTC erster öffentlicher Proof of Concept; 6. November 00:05 UTC erste Angriffsversuche auf den Sensoren von Previdian, rund acht Stunden nach dem CVE; später am 6. November bestätigt Previdian Root-Zugriff auf einem Alpine-Honeypot, der Angreifer führte id, uname und hostname aus.
Zeiten von der CVE-Seite von Previdian, die Angaben zum Honeypot aus der Stellungnahme von Previdian gegenüber The Hacker News. Safe Security schrieb am 6. November noch, Angriffe in freier Wildbahn seien nicht bestätigt.

Der Angriff ist trivial. Keine Speicherkorruption, keine Race Condition, nur eine Verbindung mit einem langen String, und wer ohnehin SSH-Ports scannt, kann es ausprobieren. Die üblichen sshd-Logs halten die Länge eines Passworts nicht fest, ein erfolgreicher Angriff sieht also aus wie ein gewöhnlicher Passwort-Login. Genau das ist auch der Hinweis: ein Passwort-Login bei einem Konto, das gar kein Passwort hat.

Was jetzt zu tun ist

  1. Aktualisieren und sshd neu starten. Unter Alpine apk upgrade -U -a und danach rc-service sshd restart. Das Paket-Update allein ersetzt den laufenden Daemon nicht. Behoben ist der Fehler in OpenSSH 10.6p2 und in den Alpine-Paketen aus dem Advisory, zum Beispiel 10.3_p1-r2 unter 3.24, 10.2_p1-r1 unter 3.23 und 10.0_p1-r11 unter 3.22; die Point-Releases 3.21.10, 3.22.8, 3.23.8 und 3.24.4 enthalten sie.
  2. Wer noch nicht aktualisieren kann, schaltet Passwort-Logins ab. PasswordAuthentication no setzen, sshd neu starten und die wirksame Einstellung mit sshd -T | grep -i passwordauthentication prüfen. Vorher sicherstellen, dass der Login mit Schlüssel funktioniert, und die laufende Sitzung offen lassen, bis eine neue getestet ist. Das Advisory von Alpine hat Befehle, die auch Versionen vor 3.19 abdecken, die sshd_config.d ignorieren.
  3. Images und laufende Instanzen nicht vergessen. Cloud-Images und Golden Images, die vor den korrigierten Point-Releases gebaut wurden, enthalten den Fehler. Baue sie neu und aktualisiere jede Instanz, die schon läuft.
  4. Über Alpine hinausschauen. Erstelle eine Liste der Geräte und Systeme, auf denen OpenSSH mit musl läuft: Appliances, Router, Firmware aus Buildroot oder Yocto, Container mit sshd. Auf einem laufenden System zeigt ldd /usr/sbin/sshd den Eintrag ld-musl, wenn sshd musl verwendet. Frag deine Hersteller, ob sie einen Fix ausliefern.
  5. Prüfen, ob jemand drin war. Durchsuche /var/log/messages nach Accepted password for und vergleiche die Konten mit denen ohne Passwort, etwa alpine, root oder Benutzer nur mit Schlüssel. Schau dir die Nutzung von doas, neue Benutzer, geänderte Dateien und authorized_keys an. Lässt sich ein Login nicht ausschliessen, behandle die Maschine als kompromittiert, setze sie neu auf und tausche die Schlüssel und Geheimnisse aus, die darauf lagen.
  6. Konten nur mit Schlüssel nicht als Schnellschuss sperren. * durch ! zu ersetzen, schliesst die Lücke für dieses Konto zwar, aber sshd verweigert dann auch den Login mit Schlüssel. Die richtigen Massnahmen sind das Update oder PasswordAuthentication no.
  7. SSH vom offenen Internet fernhalten. Ein Port, den nur ein VPN oder ein Bastion-Host erreicht, macht aus der nächsten Lücke vor der Anmeldung eine Wartungsaufgabe statt eines Notfalls.

Weisst du, auf welchen eurer Systeme sshd mit musl läuft? Pentesting und Beratung →