dspinellis

Activity

Stars and mentions · Last 30 days, Oct 8 – Nov 6

GitHub stars34
Mentions6
036912Oct 8Oct 22Nov 6
UTC days · repositories dspinellis owns6 repositories

Top repositories

dspinellis’s repositories ranked by pull request authors, as on trending.

Loading

Contributes to

Repositories outside dspinellis’s account where dspinellis opened or reviewed pull requests in the past 365 days.

Who noticed dspinellis

Everyone who starred or forked dspinellis’s repositories since the archive began in 2011.

Notable accounts

Ordered by the stars their own repositories have received.

Biggest fans

Accounts that starred the most of these repositories.

Breakout weeks

Each repository’s best week of new stars, with the release published around it.

Mentions

6posts
Nov 70 posts
  1. @kazuho musl libcの仕様だと、cryptの元々の利用方法である github.com/dspinellis/unix-history-repo/blob/Rese… が、パスワード無効なアカウント(すなわち strecmp(pwd->pw_passwd, "*")==0)について成功してしまいます。従ってopensshの実装とは無関係にmusl libcの仕様は問題です。

    1 like · 419 views
  2. @kazuho UNIX v7 のcrypt(3)の利用方法は github.com/dspinellis/unix-history-repo/blob/Rese… みたいに戻り値がパスワード欄と一致していたら認証成功ってだけであり、その後互換性を保ったまま建て増し建て増しで仕様が変化してきました。

    7 likes · 6 reposts · 390 views
  3. Hacker News · · on sshole · JdeBP · dspinellis/unix-history-repo

    I suggest finding a code path where FreeBSD crypt() ever returns NULL, which would mean one of its internal functions returning non-zero, before getting too excited. They all end in return (0) . (-: * cgit.freebsd.org As I said, the callers of crypt() have for a long time been using the knowledge that crypt() on their platform simply never returns NULL. Unix has never been returning NULL from crypt() as far back as 7th Edition, when it simply always returned a pointer to a single internal static buffer. * github.com/dspinellis/unix-history-repo/blob/Rese… The reality is that all C library people have to work with a corpus of Unix applications that do not check for crypt() returning NULL that goes back almost 50 years, and an error return mechanism that barely exists outwith the pages of the SUS. That includes callers in single-user mode in process 1 in some configurations. * cvsweb.netbsd.org

  4. 【CVE-2026-123158 (*sshole)】: OpenSSHの257文字以上のパスワードで認証可能な脆弱性 2026年11月5日、OpenSSHのポータブル版において、特定のLinux環境下でパスワード認証を完全にバイパス可能な脆弱性(CVE-2026-123158、通称「*sshole」)が公表され、修正版となるOpenSSH 10.6p2がリリースされた12。 本脆弱性は、musl libcを採用しPAM(Pluggable Authentication Modules)が無効化されたLinux環境(Alpine Linux標準構成など)において、パスワード欄が *(ログイン不可)に設定されたアカウントに対し、257文字以上のパスワードを入力すると認証が成功してしまうという論理バグである3。 ! Alpine Linuxなどで標準の openssh-server を運用しており、パスワード認証を有効(PasswordAuthentication yes)にしているサーバーは脆弱である。速やかに apk upgrade openssh による更新を実施するか、設定ファイルで PasswordAuthentication no を指定してsshdを再起動する必要がある13。 概要と成立条件 影響を受ける条件 本脆弱性はOpenSSH単体の不具合というよりも、OpenSSHとmusl libcの振る舞いが特定のビルド構成において噛み合った結果として生じる2。悪用が成立するためには、以下の5つの条件がすべて同時に満たされている必要がある13。 # 条件 詳細・デフォルト値 1 C標準ライブラリが musl libc である Alpine Linux、OpenWrt、Buildroot、Yoctoなどが該当 2 sshdが PAM無効 で動作している Alpine Linuxの標準パッケージ(openssh-server)はPAM無効でビルドされている(openssh-server-pam で UsePAM yes の場合は対象外) 3 パスワード認証が有効 である PasswordAuthentication yes(sshdのデフォルト値) 4 標的アカウントのパスワード欄が * である /etc/shadow のパスワードハッシュ欄が単一文字 *(SSH公開鍵専用アカウント、Alpineクラウドイメージの初期ユーザー、root等) 5 システム内に 有効なパスワードハッシュを持つ別アカウント が存在する /etc/shadow に $5$(SHA-256)や $6$(SHA-512)等のハッシュを持つアカウントが1つ以上存在する 上記すべての条件が揃った場合、攻撃者は257文字以上1024文字以下の任意の文字列をパスワードとして入力することで、パスワードが設定されていないはずのアカウントへ認証を突破してログイン可能となる13。 パスワード欄が '*' になる典型例 初期ユーザー alpine 以外にも、Linux環境では以下のようなケースで日常的にパスワード欄が * のアカウントが作成される。 adduser -D で作成したSSH公開鍵専用アカウント: Alpine Linux等で「パスワード認証を禁止し公開鍵認証のみで運用する」方針に基づき、-D(--disabled-password)オプションでユーザーを作成して passwd を設定しなかった場合、パスワード欄は * になる。デプロイ用ワーカーや開発者個別アカウントで多用される。 Alpine 3.16 以降の初期状態の root アカウント: 公式Dockerイメージやクラウドイメージにおいて、鍵認証を阻害しないようパスワード欄が * に設定されている。 パッケージ導入時に生成されるサービスアカウント(特にGit over SSH): apk add 等で作成されるデーモンアカウントのうち、ログインシェルが /bin/sh や /usr/bin/git-shell などに設定されているアカウント(例: git)。 LDAP / Active Directory / NSS 連携のローカルアカウント: 外部認証を前提とし、ローカルパスワードを持たせない設定のアカウント。 特に「安全のためにパスワードログインを無効化し、公開鍵認証のみで運用していたつもりの環境」ほど、標的となる * アカウントが存在しやすくなる点に注意が必要である。 影響を受けない環境 以下の環境では本脆弱性の悪用条件が成立しないため、影響を受けない13。 glibcを採用しているディストリビューション: Debian、Ubuntu、RHEL、AlmaLinux、Rocky Linux、Amazon Linux、Fedora、Arch Linuxなど PAM経由で認証している環境: UsePAM yes で動作しているOpenSSH(PAMモジュールが * を早期に拒否するため) パスワード認証を無効化している環境: PasswordAuthentication no(公開鍵認証のみ許可) OpenBSD / FreeBSD / macOS: musl libcを使用していないため対象外 Dropbear: OpenSSH特有のソルト借用ロジックを持たないため対象外 関連仕様の変遷と時系列 本脆弱性は、UNIXの初期仕様から近年のセキュリティ対策に至るまで、それぞれ異なる目的で行われた仕様変更が複合的に組み合わさった結果として発生した1。 1. 1980年: ログイン無効を表すマーカーとしての * UNIX初期の3BSD(1980年)において、Bill Joyが daemon アカウントのパスワード欄に * を設定した14。 暗号学的ハッシュ関数が生成する文字列の中に単一の * は存在し得ないため、「パスワード欄が * であれば誰もパスワードではログインできない(ログイン無効)」という慣例が成立し、現代の /etc/shadow に至るまで受け継がれてきた1。 2. 2012年: musl libcにおけるクラッシュ防止とエラー値 * Single UNIX Specificationなどの規格において、crypt() 関数は処理に失敗した場合(未対応のアルゴリズムが指定された場合など)に NULL を返すことと定められている1。 しかし、世の中に存在する多くのソフトウェアは crypt() の戻り値が NULL であることをチェックせずに strcmp() などの文字列比較関数に渡しており、NULLポインタデリファレンスによるクラッシュ(SEGV)を引き起こす問題が存在した。 これに対し、musl libcは2012年8月のコミットにおいて、「crypt() は失敗時に NULL を返さず、どのような正当なパスワードハッシュとも一致しない安全なダミー文字列を返す」方針を採用した1。その際に選ばれたダミー文字が、UNIXの伝統的な無効値である "*" であった。 /* musl libc の crypt 実装概念 */ char *crypt(const char *key, const char *setting) { /* 処理に失敗した場合は NULL ではなく "*" を返す */ if (failure) return "*"; ... } 3. 2012年: SHA-512 cryptにおける256バイト長制限 musl libcにSHA-512 cryptアルゴリズムが追加された際、長大なパスワードハッシュ計算に伴うCPUリソース枯渇(DoS攻撃)を防ぐ目的で、入力キーの長さに上限(KEY_MAX = 256 バイト)が設定された1。 256バイトを超えるパスワードが crypt() に渡されると、musl libcはハッシュ計算を中断してエラー処理を行い、前述の仕様に従って文字列 "*" を返す。 4. 2016年: OpenSSHのタイミング攻撃対策(CVE-2016-6210) 2016年、OpenSSHにおいてユーザー名の列挙を可能にするタイミング攻撃の脆弱性(CVE-2016-6210)が報告された。存在しないユーザー名に対して認証を試みた際、ハッシュ計算を行わずに即座に認証拒否を返すと、実在するユーザー名との応答時間の差からユーザーの存在有無が推測できてしまう問題である5。 OpenSSHはこの対策として、対象アカウントに有効なハッシュが存在しない場合(無効なユーザー名、またはパスワード欄が * のアカウント)であっても、システム内の他の実在アカウントからソルトを借用(pick_salt())し、ダミーのハッシュ計算を実行して応答時間を均一化する仕組みを導入した15。 5. 2022年: Alpine Linuxにおける * の採用 2019年、Alpine LinuxのDocker公式イメージにおいてrootアカウントにパスワードが設定されていなかった問題(CVE-2019-5021)の対策として、rootアカウントを !(アカウントロック)に設定する変更が行われた。 しかし、PAMを使用しないAlpine環境において ! を設定すると、パスワードログインだけでなくSSH公開鍵認証まで拒否されてしまう問題が発生した。そのため、2022年リリースのAlpine 3.16において、公開鍵認証を許可しつつパスワードログインを無効化する目的で、rootやデフォルトユーザーのパスワード欄が * に変更された1。 脆弱性の発現メカニズム これらの仕様が重なり合うことで、以下のような認証バイパスのシーケンスが発生する。 攻撃の入力: 攻撃者は、パスワードが無効化されているアカウント(例: alice、shadow上の値は *)に対し、257文字以上(例: A を300文字)のパスワードを送信する。 ソルトの借用: sshdは alice のパスワード欄が * であることを確認する。有効なソルトが含まれていないため、CVE-2016-6210のタイミング対策ロジック(pick_salt())が発動し、システム内の別アカウント(例: bob)のソルト($6$abc$...)を借用する13。 muslの crypt() 呼び出し: sshdは crypt("AAA... (300文字)", "$6$abc$...") を実行する。 muslのエラー返却: musl libcのSHA-512 crypt実装は、入力が256バイトを超えているため処理を打ち切り、エラーマーカーである文字列 "*" を返す1。 文字列比較の成立: sshdは crypt() の返却値("")と、shadowファイルに保存されている値("")を strcmp() で比較する。 両者が完全に一致("" == "")するため、sshdは「正しいパスワードが入力された」と判断し、認証を許可する13。 修正パッチの技術的解説 OpenSSH開発チーム(Damien Miller氏)は、2026年11月5日に修正パッチをコミットし、OpenSSH 10.6p2をリリースした26。 コミット差分(auth-passwd.c) 修正は非常に簡潔であり、比較対象となる保存パスワード文字列の最小長(MIN_PASSWORD_HASH_LEN)を検査するガード節が追加された6。 --- a/auth-passwd.c +++ b/auth-passwd.c @@ -67,6 +67,7 @@ extern login_cap_t *lc; #define DAY (24L * 60 * 60) /* 1 day in seconds */ #define TWO_WEEKS (2L * 7 * DAY) /* 2 weeks in seconds */ +#define MIN_PASSWORD_HASH_LEN 4 #define MAX_PASSWORD_LEN 1024 /* @@ -198,16 +200,20 @@ sys_auth_passwd(struct ssh *ssh, const char *password) Authctxt *authctxt = ssh->authctxt; struct passwd *pw = authctxt->pw; char *encrypted_password, *salt = NULL; - int ret; /* Just use the supplied fake password if authctxt is invalid */ - char *pw_password = authctxt->valid ? shadow_pw(pw) : pw->pw_passwd; - char *pw_password = authctxt->valid ? - shadow_pw(pw) : xstrdup(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); - if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0) { - free(pw_password); - return 1; - } /* - Encrypt the candidate password using the proper salt, or pass a @@ -221,7 +227,10 @@ sys_auth_passwd(struct ssh *ssh, const char *password) - Authentication is accepted if the encrypted passwords - are identical. */ - 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; } #endif 修正の要点 MIN_PASSWORD_HASH_LEN の導入: 有効なパスワードハッシュは暗号化アルゴリズム識別子やソルトを含むため、通常数十文字以上の長さを持つ。定数として 4 バイト以上の長さを要求することで、"*" や "!" などの1文字で構成されるプレースホルダとの一致判定を根本的に除外した6。 メモリ管理の安全性向上: shadow_pw() の返却値が従来は静的バッファへのポインタだった箇所を xstrdup() で明示的に動的確保し、比較終了後に freezero() で安全にメモリをゼロクリア・解放するようリファクタリングされた6。 ディストリビューション別の影響と対応状況 ディストリビューション 影響有無 修正版バージョン 補足 Alpine Linux あり 10.6p2 相当パッケージ v3.20〜v3.24およびedge向けに修正版パッケージが緊急リリース13 OpenWrt あり 更新パッケージ準備中 musl採用かつOpenSSH使用環境で影響あり(Dropbear環境は対象外) Buildroot / Yocto あり 各自パッチ適用 muslベースでビルドしたイメージにおいてパッチの適用が必要3 Debian / Ubuntu なし - glibcを採用しているため影響を受けない1 RHEL / Rocky / Alma なし - glibcを採用しているため影響を受けない1 Amazon Linux なし - glibcを採用しているため影響を受けない1 自環境の確認方法と対策 1. 影響診断スクリプトによる確認 脆弱性の発見者であるÖzgün Kültekin氏が公開した診断スクリプト(check.sh)を用いて、自環境が影響を受けるか確認できる3。 ! スクリプトの安全性について: check.sh のコードは全86行のシンプルなシェルスクリプトであり、外部への通信やシステムファイルの改変処理は一切含まれていない(/etc/shadow や sshd -T の読み取り判定のみを実行する)。ただし、root権限で外部スクリプトを実行するリスクを避けるため、内容を一度確認してから実行するか、後述の手動確認コマンドの利用を推奨する。 スクリプトをダウンロードして内容を確認 curl -sO raw.githubusercontent.com less check.sh 安全性を確認した上で実行 sudo sh check.sh 出力例(脆弱な環境の場合): libc musl sshd OpenSSH_10.3p1, OpenSSL 3.5.9 29 Sep 2026 pam off (not built in) PasswordAuthentication yes accounts with '*' root alice deploy sha-crypt hash present yes (bob) EXPOSED. anyone can log in as: root alice deploy fix: apk upgrade openssh (10.6p2), or set PasswordAuthentication no until you can. 2. 手動での設定確認(推奨) 外部スクリプトを実行せずに確認する場合、以下の4項目を順に確認する。 C標準ライブラリの確認:ldd --version 2>&1 | head -n 1 出力に musl が含まれるかを確認する(glibc の場合は対象外)。 sshdの設定確認:sshd -T | grep -E '^(passwordauthentication|usepam)' passwordauthentication yes かつ usepam no(またはPAM非対応)となっているかを確認する。 パスワード欄が * のアカウントの有無:sudo awk -F: '$2 == "*" {print $1}' /etc/shadow adduser -D で作成したSSH鍵専用ユーザー、git などのサービスアカウント、初期状態の root や alpine ユーザーが存在するかを確認する。 ソルト借用元となる別アカウントのハッシュの有無:sudo awk -F: '$2 ~ /^\$[56]\$/ {print $1; exit}' /etc/shadow システム内に $5$(SHA-256)や $6$(SHA-512)のパスワードハッシュを持つ実在アカウントが1つでも存在するかを確認する。 3. 対策手順 恒久対策: パッケージの更新 Alpine Linux環境では、パッケージインデックスを更新してOpenSSHを最新版にアップグレードし、sshdを再起動する13。 apk update apk upgrade openssh rc-service sshd restart 即時緩和策: パスワード認証の無効化 直ちにパッケージの更新やサーバー再起動が行えない環境では、sshdの設定でパスワード認証を無効化(公開鍵認証専用)とすることで、本脆弱性を完全に防ぐことができる13。 パスワード認証を無効化する設定を追加 echo "PasswordAuthentication no" > /etc/ssh/sshd_config.d/00-no-passwords.conf sshd の設定を再読み込みまたは再起動 rc-service sshd restart ! 設定変更後に現在の接続を切断する前に、必ず別の端末からSSH公開鍵によるログインが正常に行えることを確認すること。 AIエージェントを活用した脆弱性発見とエコシステムの反応 本脆弱性の発見経緯において、発見者のÖzgün Kültekin氏は、並列動作する多数のAIエージェントを活用した差分テスト(差分ファジング)によって本バグを検出したと述べている1。 OpenSSHとlibc(glibc / musl)、PAMの有無、shadow構成などの組み合わせに対し、17,000通り以上のエッジケースログインを自動生成して検証した結果、musl環境のみが異常な挙動を示したことで発見に至った1。 また、OpenSSH公式チームも10.6p2のリリースノートにおいて、昨今AIを活用した脆弱性報告が急増している点に言及している2。「AIによって発見された脆弱性が、直後に別の研究者によって独自に再発見されるケースが増加している。これは攻撃者側も同様の手法で未報告の脆弱性を発見可能であることを示唆している」として、OpenSSHプロジェクトは従来の計画的リリース間隔にとらわれず、修正パッチをより迅速にリリースする方針への転換を表明している2。 参考資料・出典一覧 sshhole.com (*sshole 解説サイト) OpenSSH 10.6p2 リリースノート (2026-11-05) GitHub リポジトリ (oz9un/sshole) 3BSD /etc/passwd (dspinellis/unix-history-repo) OpenSSH commits: Timing attack mitigation for invalid users (CVE-2016-6210) OpenSSH upstream patch: avoid password authn bypass

  5. Musl libc: un reporte halla un asterisco que abre cuentas SSH bloqueadas Un servidor SSH sobre Alpine Linux puede dejar entrar a una cuenta marcada como bloqueada si la contraseña que enviás supera los 256 bytes. No hace falta adivinar ningún secreto: alcanza con que el campo de esa cuenta en /etc/shadow sea un simple asterisco y con que el sistema use musl libc sin PAM. El hallazgo, publicado en sshhole.com, apunta a una vulnerabilidad en musl libc que lleva catorce años escondida. Desde 2012, la función crypt() de musl devuelve el mismo carácter que marca las cuentas bloqueadas cuando falla, y hasta ahora nadie lo había conectado con sshd. TL;DR - En Alpine con musl y sshd sin PAM, una contraseña de más de 256 bytes abre cualquier cuenta bloqueada en /etc/shadow. - El fallo nace en 2012: crypt() de musl devuelve '*' al fallar, igual que el símbolo de cuentas bloqueadas desde 1980. - Musl limita sha512crypt a 256 bytes desde el 29 de agosto de 2012, y al superar ese límite crypt() devuelve ese mismo '*'. - El hallazgo surgió al probar 17.600 logins contra seis builds de sshd; solo musl sin PAM aceptó entradas que debía rechazar. - La falla pasó 10 años inadvertida: OpenSSH se prueba en OpenBSD y glibc, y la mayoría de distros usan PAM, que evita el bug. Qué es musl Musl es la biblioteca C estándar (libc) minimalista que usa Alpine Linux y muchas imágenes de Docker, pensada para producir binarios pequeños y estáticos. Implementa las funciones POSIX que un programa en C necesita, entre ellas crypt(), la que sshd llama para comparar la contraseña escrita con el hash guardado en el sistema. Qué pasó La prueba fue simple en su planteo y enorme en escala: compilar sshd de seis formas distintas (con glibc o musl, con o sin PAM, con o sin /etc/shadow) y lanzarle cerca de 17.600 intentos de login con hashes raros, cuentas rotas y contraseñas demasiado largas. Según sshhole.com, el autor usó enjambres de agentes automatizados para generar y correr esos intentos en paralelo. Cinco de las seis combinaciones coincidieron en cada resultado. El patrón era siempre el mismo: una cuenta con '*' en el campo de contraseña de /etc/shadow, la marca estándar de cuenta bloqueada desde 1980, dejaba entrar a cualquiera que enviara una contraseña de más de 256 bytes, pero solo en la build de musl sin PAM. El hallazgo se publicó en noviembre de 2026, apenas cuatro días después de que una revisión de seguridad de OpenSSH, fechada el 30 de octubre de 2026, corrigiera una función vecina (pick_salt()) sin tocar el bug real, que vivía cuatro líneas más abajo en el mismo archivo. El asterisco marca cuentas bloqueadas en Unix desde 1980. Cómo surge la vulnerabilidad en musl libc La marca de cuenta bloqueada nació en 1980, cuando Bill Joy la agregó en 3BSD para la cuenta daemon, con un detalle curioso: el nombre real que anotó para ese usuario fue "the devil himself". Un asterisco no es un hash válido, así que ninguna contraseña puede coincidir con él, y por eso durante 46 años funcionó como un candado seguro. En los noventa, el hash se mudó a /etc/shadow con el formato $6$sal$hash (sha512crypt). sshd toma la contraseña escrita, la cifra con la misma sal guardada y compara el resultado contra ese campo; si coinciden, el login entra. La especificación Single UNIX de 1997 estableció que, si crypt() no puede hacer su trabajo, debe devolver NULL. Muchos programas nunca revisaron ese caso y terminaban comparando contra NULL, lo que los hacía crashear. musl resolvió eso en agosto de 2012 con el commit b3c4cc12: en vez de NULL, crypt() devuelve un carácter que ninguna contraseña real puede producir. Ese carácter es '*', el mismo símbolo que desde 1980 marca una cuenta bloqueada. Veinte días más tarde, el commit 88bf5a8a sumó sha512crypt a musl y le puso un límite de 256 bytes (constante KEY_MAX), porque sha512crypt se vuelve más lento cuanto más larga es la entrada, y una contraseña gigante podría ocupar el servidor por un rato largo. Pasado ese límite, crypt() falla y, por el cambio de veinte días antes, devuelve '*'. En 2016 llegó el CVE-2016-6210: preguntarle a sshd por un usuario que no existe respondía más rápido que por uno real, porque no había ningún hash que calcular, y cronometrando esa diferencia un atacante podía enumerar cuentas válidas. El parche de OpenSSH hizo que, ante un usuario inválido, sshd tome la sal de otra cuenta cualquiera y cifre la contraseña igual, solo para gastar el mismo tiempo; el mensaje del commit decía "for invalid users", pero terminó aplicándose también a cuentas reales con '*' en el campo. En 2019, Alpine enfrentó el CVE-2019-5021: sus imágenes oficiales de Docker no traían contraseña de root. La primera corrección bloqueó la cuenta con '!', pero sin PAM ese símbolo también tumbaba el login por llave SSH, que es como se accede a casi todas las imágenes en la nube. En 2022, Alpine 3.16 volvió a usar '*' para bloquear root (commit fbe926af), lo que restauró el acceso por llave. Diez años después de b3c4cc12, el root de Alpine volvía a depender del mismo asterisco. Hubo quienes estuvieron cerca de notarlo. En 2013, un desarrollador de Debian le pidió a glibc copiar el '*' de musl en la lista libc-alpha; seis años después, Debian migró a libxcrypt, que usa '0' (un carácter distinto), y cerró el pedido ahí. En diciembre de 2024, un hilo de la lista de musl discutió un bug de busybox passwd con contraseñas de 257 caracteres, el mismo límite y el mismo '', pero nadie mencionó a sshd. Detalles técnicos: el mecanismo detrás del bug El mecanismo es una colisión de representación, no una falla criptográfica. sshd, cuando no usa PAM, llama directamente a crypt() con la contraseña y el campo de shadow, y compara el resultado contra ese mismo campo tratando ambos como simples cadenas de texto. Si el campo guardado ya es '' y crypt() también devuelve '' porque la entrada es demasiado larga, la comparación de strings da verdadero, aunque ninguno de los dos lados sea un hash real. char *computed = crypt(password, shadow_field); if (strcmp(computed, shadow_field) == 0) { // acceso concedido } Si password mide más de 256 bytes, crypt() devuelve "". Si shadow_field ya es "" porque la cuenta está bloqueada, strcmp("", "") da 0 y la condición se cumple sin que exista ningún hash de verdad detrás. sequenceDiagram participant C as Cliente SSH participant S as sshd sin PAM participant M as crypt de musl C->>S: envia una contrasena de 300 bytes S->>M: pide el crypt de la contrasena M-->>S: responde con el caracter asterisco Note over S: el asterisco de shadow coincide con el de crypt S-->>C: acceso concedido La ruta con PAM nunca pasa por ahí. PAM intercepta la autenticación antes de llegar a crypt(), y cuando el campo de la cuenta ya es '*' ni siquiera intenta calcular un hash; por eso la colisión solo aparece en builds sin PAM, que son comunes en contenedores Alpine mínimos. La tabla siguiente resume qué combinación de libc y PAM resultó vulnerable en las pruebas descritas en sshhole.com. Configuración de sshd¿Usa PAM?Resultado con contraseña mayor a 256 bytes glibc con PAMSíRechaza el login; PAM nunca llama a crypt() para un campo '*' glibc sin PAMNoRechaza el login; crypt() de glibc no devuelve '*' al fallar musl con PAMSíRechaza el login, por el mismo motivo que glibc con PAM musl sin PAMNoAcepta el login en cuentas bloqueadas con '*' musl limita sha512crypt a 256 bytes desde agosto de 2012. Impacto y análisis La vulnerabilidad en musl libc tiene un alcance acotado, porque solo afecta a cuentas marcadas como bloqueadas y a builds de sshd sin PAM, no a los inicios de sesión normales con contraseña real. Aun así, Alpine es la base de una enorme cantidad de imágenes Docker, y muchas de ellas corren sin PAM por diseño, para mantenerse livianas. En la práctica, el riesgo depende de qué cuentas tengan ese asterisco y de si sshd las deja intentar login. Muchas cuentas de servicio usan un shell /sbin/nologin que corta el acceso igual, y root suele tener PermitRootLogin en no. El caso más sensible es un contenedor Alpine con PAM deshabilitado donde alguien reactivó el login por contraseña para una cuenta pensada para quedar bloqueada. > ⚠️ Ojo: el bug no requiere adivinar ninguna contraseña real: alcanza con mandar cualquier cadena de más de 256 bytes contra una cuenta con '*' en /etc/shadow. Qué sigue Mientras tanto, la vulnerabilidad en musl libc sigue documentada pero sin parche oficial confirmado, ya que ni musl ni OpenSSH publicaron todavía un commit que la cierre. La revisión de OpenSSH del 30 de octubre de 2026 corrigió pick_salt() sin tocar el bug, que según sshhole.com está apenas cuatro líneas más abajo en el mismo archivo. Tampoco hay, por ahora, un identificador CVE asignado a este hallazgo puntual. Los administradores de sistemas Alpine pueden mitigarlo revisando si PAM está activo, confirmando que las cuentas de servicio usen un shell sin login y verificando el estado de PermitRootLogin en su configuración de sshd. 📖 Resumen en Telegram: Ver resumen Probalo vos: revisá el campo de contraseña de tus cuentas de servicio en /etc/shadow y confirmá si tu sshd corre con PAM antes de confiar en que un asterisco te protege. Preguntas frecuentes ¿Qué distribuciones usan musl libc y podrían verse afectadas? Alpine Linux es la distribución más extendida con musl como libc por defecto, y por eso domina las imágenes base de contenedores Docker; también la usan Void Linux y algunos sistemas embebidos. El bug solo se dispara en builds de sshd sin PAM. ¿Alpine Linux con PAM también queda expuesto? No, según las pruebas de sshhole.com: PAM nunca llega a llamar a crypt() cuando el campo de la cuenta ya es '*', así que esa ruta de autenticación nunca produce la colisión. ¿Ya existe un CVE para este bug de musl? No hay uno asignado públicamente al momento de escribir esto. Sí existen CVEs relacionados con el mismo asterisco en Alpine, como el CVE-2016-6210 de OpenSSH y el CVE-2019-5021 del root sin contraseña en Docker. ¿Qué cuentas suelen tener '*' en /etc/shadow? Tradicionalmente, cuentas de sistema que no deben iniciar sesión interactiva, como daemon, bin o mail; en Alpine 3.16 en adelante, también root cuando está bloqueado. ¿Cómo se relaciona esto con el CVE-2016-6210 de OpenSSH? Ese CVE de 2016 ya forzaba a sshd a llamar a crypt() incluso para usuarios sin hash real, para evitar que el tiempo de respuesta delatara si la cuenta existía. Esa misma llamada es la que, en musl sin PAM, termina comparando dos asteriscos. ¿musl ya lanzó un parche para esta vulnerabilidad en musl libc? No hay confirmación pública de un commit que lo corrija. La revisión de seguridad de OpenSSH del 30 de octubre de 2026 arregló pick_salt() sin tocar el bug, que queda cuatro líneas más abajo en el mismo archivo. Referencias - sshhole.com: artículo original con el hallazgo y una demo interactiva de Debian y Alpine. - git.musl-libc.org: commit de 2012 que hace que crypt() devuelva '*' en lugar de NULL. - git.musl-libc.org: commit que agrega sha512crypt y el límite de 256 bytes. - lists.mindrot.org: parche de OpenSSH de 2016 para el CVE-2016-6210. - gitlab.alpinelinux.org: commit de Alpine 3.16 que vuelve a usar '*' para root. - pubs.opengroup.org: especificación Single UNIX de 1997 sobre crypt(). - lists.mindrot.org: revisión de seguridad de OpenSSH del 30 de octubre de 2026. 📱 ¿Te gusta este contenido? Únete a nuestro canal de Telegram @programacion donde publicamos a diario lo más relevante de tecnología, IA y desarrollo. Resúmenes rápidos, contenido fresco todos los días.

  6. Yeah the historical question still interests me. Did V9 really originate negative pid killing via /bin/kill, or did System V or SunOS already have it? If the main use case was shell job control, maybe there wasn't yet a good reason to expose it. The extent of my spelunking for the post was TUHS, the unix-history-repo, and playing around with kill on old unixes in the browser via v86.

    9 points

Achievements

Awards earned by the repositories dspinellis owns. Select an award to embed its badge.

No awards yet

Repositories earn awards by reaching the top three in a completed trending day or week.

A repository earns an award for finishing first, second or third in a completed trending day or week, ranked by new stars, new forks or pull request authors. Awards follow a repository through renames and transfers and count toward its current owner. Weeks run Monday to Sunday, UTC.