当社のAIエンジンNeutronが、UCバークレーのCyberGymベンチマークで97.1%のスコアを記録しました。 詳細を見る

ディープダイブ

ディープダイブ

musl 上の OpenSSH パスワード回避、10.6p2 で修正 (CVE-2026-123158)

musl 上で PAM なしの OpenSSH はロックされたアカウントに 257 バイトのパスワードを受け付けます。10.6p2 と Alpine のパッケージで修正されました。

要点

  • musl libc で PAM を無効にしてビルドした OpenSSH の sshd は、shadow のパスワード欄が * のアカウントに 256 バイトを超える任意のパスワードを受け付けます。OpenSSH プロジェクトは 2026 年 11 月 5 日に CVE-2026-123158 を公開し、10.6p2 をリリースしました。
  • Alpine Linux で sshd をパスワード認証ありで実行しているサーバーは、別のローカルアカウントに $5$ または $6$ のハッシュがある場合に影響を受けます。Alpine の公式イメージは広く導入されています。sshd を実行しないコンテナは影響を受けません。
  • MITRE は CVSS v3.1 8.1 High (CWE-394) と評価しています。公開ラボと 2 つの概念実証リポジトリがあり、現実の悪用は報告されておらず、2026 年 11 月 6 日時点で CISA の KEV カタログには掲載されていません。
  • OpenSSH 10.6p2、または各ブランチの修正済み Alpine パッケージに更新し、sshd を再起動してください。更新できない場合は PasswordAuthentication no を設定します。「修正方法」を参照してください。

影響を受けますか?

次のすべてに当てはまる場合にのみ影響を受けます。

  • ホストが 10.6p2 より前の OpenSSH、または表の修正版より古い Alpine の openssh パッケージを実行している。
  • sshd が musl で PAM を無効にしてビルドされ、実行されている。Alpine の openssh-server は PAM なしでビルドされています。openssh-server-pam と UsePAM yes の組み合わせは影響を受けませんが、同じパッケージで UsePAM no の場合は影響を受けます。
  • PasswordAuthentication yes が有効である。これは OpenSSH の既定値です。
  • パスワードで到達できる少なくとも 1 つのアカウントの shadow パスワード欄が * である。Alpine では、およそ Alpine 3.16 以降のベースイメージで root:* として提供される root、パスワードなしで adduser により作成された鍵専用ユーザー、shadow エントリを持たないディレクトリサービスユーザー、公式 tiny-cloud イメージの alpine ユーザーが該当します。
  • 少なくとも 1 つのローカルアカウントに $5$ または $6$ の crypt ハッシュがある。sshd がソルトを借用するために必要です。SHA-256 も SHA-512 もハッシュを持たないマシンでは、この不具合には到達しません。

root については、既定の PermitRootLogin prohibit-password がパスワードログインを引き続きブロックします。PermitRootLogin yes を設定した場合、またはログインできる別の * アカウントが root への経路を持つ場合、たとえば tiny-cloud イメージのパスワードなし doas がある場合に root へ到達できます。

sshd を実行しないコンテナは影響を受けません。! でロックされたアカウントはパスワードでも鍵でもログインできないため、標的になりません。PasswordAuthentication no のシステム、openssh-server-pam と UsePAM yes を使うシステム、$ 形式のハッシュがないシステムもこの不具合の対象外です。

ブランチ 影響を受けるバージョン 修正バージョン
OpenSSH 本家 (musl、PAM 無効) 10.6p1 以前 10.6p2 (2026 年 11 月 5 日公開)
Alpine edge 10.6_p2-r0 より前 10.6_p2-r0
Alpine 3.24 10.3_p1-r2 より前 10.3_p1-r2 (ポイントリリース 3.24.4)
Alpine 3.23 10.2_p1-r1 より前 10.2_p1-r1 (ポイントリリース 3.23.8)
Alpine 3.22 10.0_p1-r11 より前 10.0_p1-r11 (ポイントリリース 3.22.8)
Alpine 3.21 9.9_p2-r1 より前 9.9_p2-r1 (ポイントリリース 3.21.10)
Alpine 3.20 9.7_p1-r6 より前 9.7_p1-r6
Alpine 3.19 9.6_p1-r3 より前 9.6_p1-r3
Alpine 3.18 9.3_p2-r4 より前 9.3_p2-r4
Alpine 3.17 9.1_p1-r7 より前 9.1_p1-r7
Alpine 3.16 9.0_p1-r6 より前 9.0_p1-r6

Alpine は 3.16 から 3.24 までの各ブランチと edge に修正済みパッケージを公開しました。定期更新が終了したリリースも含まれます。修正を含む現在のポイントリリースは 3.21.10、3.22.8、3.23.8、3.24.4 の 4 つです。

ホストの状態を確認します。

# 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 には root 権限と読み取り可能な設定が必要です。OpenWrt、Buildroot、Yocto など Alpine 以外の musl システムでは、ディストリビューションのパッケージマネージャーと ssh -V で OpenSSH のビルドを特定し、ベンダーの修正済みパッケージと比較してください。

修正方法

  1. Alpine ではパッケージを更新し、sshd を再起動します。 apk upgrade -U -a rc-service sshd restart 更新だけでは実行中の sshd は再起動されないため、再起動が必要です。コンテナイメージは修正済みのベースまたはパッケージから再構築し、コンテナを再作成してください。新しいイメージを取得してもコンテナを再作成しなければ、古いプロセスが動き続けます。
  2. 他の musl システムでは、OpenSSH 10.6p2 またはディストリビューションの修正済みパッケージに更新します。OpenSSH 10.6p2 のリリースノートが修正を示し、Alpine のアドバイザリが各ブランチの修正済みパッケージを一覧にしています。
  3. 更新できない場合はパスワード認証を無効にします。現在のセッションを開いたままにし、閉じる前に鍵ログインをテストしてください。Alpine 3.19 以降では drop-in ファイルで足ります。 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 drop-in ディレクトリを読まない古い Alpine では、/etc/ssh/sshd_config を直接編集して sshd を再起動します。PasswordAuthentication no は本物のハッシュを持つアカウントのパスワードログインも無効にします。それが意図したコストです。
  4. パスワード認証が必要で更新できない場合は、* の対象を削除するか到達不能にします。未使用のアカウントを * ではなく ! でロックするか、削除します。! は鍵によるログインも拒否するため、別の管理セッションを開いたままにしてください。これは特定のアカウント経路を閉じますが、比較そのものは修正しないため、できるだけ早く更新してください。

根本原因は何ですか?

この不具合は、どちらも * になる 2 つの文字列の比較です。一方はアカウントにパスワードがないため、もう一方は musl の crypt() がエラー値として * を返すためです。PAM なしの sshd は auth-passwd.c で保存されたパスワード欄を取り出し、入力されたパスワードをその欄でハッシュします。

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;

欄が * のアカウントでは pw_password[1] が終端の NUL なので、salt は NULL のままです。すると xcrypt() が pick_salt() を呼び、アカウントデータベースを走査して $5$ または $6$ の欄を見つけ、そのハッシュの種類とソルトを返します。

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

musl の SHA-512 実装は 256 バイトを超える鍵を拒否します。この上限はサービス拒否への対策で、SHA-512 crypt は鍵が長くなるほど遅くなるためです。

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

内部関数が 0 を返すと、musl の __crypt_sha512() は文字列 * を返します。

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

sshd は返された * を保存された * と比較し、ログインを受け付けます。OpenSSH は入力パスワードを 1024 バイトに制限しているため、成功する範囲は 257 から 1024 バイトです。CVE レコードは 256 から 1024 と表現しています。256 バイトの鍵は musl にまだ受け付けられ、本物のハッシュを生成するため、エラー戻り値を引き起こす最短の値は 257 です。

この不具合が到達可能になったのは 2016 年です。OpenSSH が CVE-2016-6210 のタイミング攻撃修正として pick_salt() を追加したためです。それ以前は * のアカウントを固定の DES ソルト xx でハッシュしており、* は返りませんでした。

どのように悪用されますか?

  1. 攻撃者はパスワード認証が有効な musl システムの SSH サービスを見つけます。
  2. 対象にはパスワードでログインできる * アカウントがあります。PermitRootLogin yes の root、鍵専用のデプロイユーザー、ディレクトリユーザー、または tiny-cloud イメージの alpine ユーザーです。
  3. 別のローカルアカウントに $5$ または $6$ のハッシュがあり、sshd がそのソルトを借用できます。
  4. 攻撃者は * アカウントに対して 257 から 1024 バイトのパスワードを送ります。文字の内容は問いません。
  5. sshd は借用したソルトで長いパスワードをハッシュします。musl は * を返し、保存された * との比較が成功して、攻撃者はそのアカウントのシェルを得ます。

sshhole.com の公開ラボではブラウザーで比較を試せます。CVE レコードには 2 つの概念実証リポジトリが掲載されています。2026 年 11 月 6 日時点で、現実の悪用は公に報告されていません。

攻撃の流れは?

パスワードのないアカウントに対する長いパスワードが musl の * エラー戻り値に到達し、保存された欄も * であるため sshd が受け付けます。

flowchart LR A["攻撃者が 257 バイト以上のパスワードを送信"] --> B["sshd が別アカウントの $6$ ソルトを借用"] B --> C["musl が長い鍵を拒否して * を返す"] C --> D["sshd が * と保存された * を比較"] D --> E["ロックされたアカウントとしてログイン成功"]

攻撃者に何ができますか?

攻撃者はパスワード認証で到達できる任意の * アカウントに、そのアカウントの権限でログインできます。影響はどのアカウントかによって変わります。

  • PermitRootLogin yes の Alpine の root: ホストの完全な制御。
  • パスワードなし doas を持つ tiny-cloud イメージの alpine ユーザー: インスタンスの root。
  • 鍵専用のデプロイユーザー: そのユーザーが持つシェル、鍵、クラウド認証情報、アプリケーションへのアクセス。
  • shadow エントリのないディレクトリサービスユーザー: そのユーザーへのなりすまし。

「影響を受けますか?」の条件はすべて適用されます。musl、PAM 無効、パスワード認証有効、* アカウント、別の $5$ または $6$ ハッシュ、ネットワーク到達性です。この不具合は本物のパスワードハッシュを明らかにしたり解読したりせず、! でロックされたアカウントには影響しません。SSH プロトコルを回避する意味の事前認証不具合ではなく、攻撃者はサーバーが拒否すべきパスワードで通常のパスワードログインを完了します。

修正が機能する理由

修正は保存されたハッシュに最小長を設け、1 文字の欄を比較しないようにします。

+#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;

* の欄は 1 バイトで、新しい最小長 4 バイトを下回るため、musl が * を返しても比較は偽になります。本物の SHA-512 の欄は $6$、ソルト、ハッシュで 4 バイトよりはるかに長くなります。同じ変更が portable と UnixWare のパスワード経路に適用され、修正は shadow のコピーも解放します。OpenSSH プロジェクトは根本原因が musl のエラー値であるため回避策と呼んでいますが、sshd の経路は閉じます。Alpine の安定版パッケージも同じ修正を含みます。

侵害されたかどうかを確認するには?

公開された侵害指標はありません。ログインに成功すると、本来パスワードを受け付けないアカウントに Accepted password の行が残るため、そこから確認します。

# 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

ヒットは手がかりであり、証明ではありません。本物のハッシュを持つアカウントも Accepted password の行を出します。送信元アドレスと時刻を自分のログインと照合してください。次に doas と sudo の使用、最近作成されたユーザー、新しい authorized_keys の項目、そのアカウントが到達できたファイルやサービスを確認します。tiny-cloud イメージでは、alpine ユーザーが身に覚えのないアドレスからログインしていないか確認します。

失敗した試行は特別な痕跡を残さず、成功した試行がログから削除されている可能性もあります。ログインを排除できない場合は、ホストを侵害されたものとして扱い、信頼できるイメージから再構築し、到達できたすべての認証情報を更新してください。

年表

  • 2012-08: musl が crypt() を変更し、ハッシュを計算できないときに NULL ではなく * を返すようになる。
  • 2012-08-29: musl が SHA-512 crypt の鍵を 256 バイトに制限し、長い鍵の経路が * を返すようになる。
  • 2016-07: OpenSSH が CVE-2016-6210 のタイミング修正として無効ユーザー向けの pick_salt() を追加し、* の比較が到達可能になる。
  • 2026-10-30: OpenSSH のセキュリティレビューが pick_salt() を修正する。脆弱な比較はその 4 行下にある。
  • 2026-11-05: OpenSSH 10.6p2 がリリースされ、CVE-2026-123158 が公開され、Alpine がアドバイザリと修正済みパッケージを公開する。
  • 2026-11-06: 現実の悪用は公に報告されておらず、CVE は CISA の KEV カタログにない。

この不具合は 2026 年の修正まで 14 年間 musl と OpenSSH に存在しました。
図 1: 2012 年の musl のエラー値から 2026 年の OpenSSH 修正まで。出典: musl のコミット b3c4cc12 と 88bf5a8a、OpenSSH 10.6p2 のリリースノート、CVE-2026-123158、2026 年 11 月 6 日確認

よくある質問

Debian、Ubuntu、Fedora は影響を受けますか?

いいえ。これらのシステムは glibc と PAM を使用しており、この回避には PAM を無効にした musl の * エラー戻り値が必要です。glibc 上の同じ OpenSSH バージョンはこの経路を通りません。

Alpine を使っていますが鍵ログインだけです。影響を受けますか?

はい。PasswordAuthentication が有効で * アカウントが存在する場合です。攻撃者は長いパスワードで * アカウントにログインするため、鍵ログインの方法は関係ありません。PasswordAuthentication no を設定するか更新してください。

root は既定で悪用できますか?

既定ではできません。Alpine は root を * の欄で提供しますが、OpenSSH の既定 PermitRootLogin prohibit-password が root のパスワードログインをブロックします。PermitRootLogin yes を設定した場合、またはパスワードなし doas を持つ alpine ユーザーのように別の * アカウントが昇格できる場合に root へ到達できます。

追跡できる CVE はありますか?

はい。CVE-2026-123158 は 2026 年 11 月 5 日に CVSS v3.1 8.1 High、CWE-394 で公開されました。OpenSSH のアドバイザリと Alpine のアドバイザリが主な修正情報源です。

現実の悪用はありましたか?

2026 年 11 月 6 日時点で公開された悪用報告はなく、CISA の SSVC 評価は公開された概念実証を記録していますが、活発な悪用は記録していません。この不具合は古いため、公開データだけでは静かなログインを排除できません。ログを確認してください。

SSH 鍵を更新する必要がありますか?

説明できないログインの証拠を見つけた場合だけです。ホストにアクセスされた場合は、到達できたすべての鍵と認証情報を露出したものとして扱い、再構築後に更新してください。ログがきれいなら、更新と sshd の再起動で十分です。

Ostorlab で公開 SSH サービスを見つける

Ostorlab の攻撃対象領域の検出は、インターネットに公開されたホストとそのサービスを一覧化します。TCP 22 番ポートで応答するマシンを洗い出し、まず OpenSSH のビルドとパスワード認証の設定を確認してください。

参考資料

  • OpenSSH 10.6p2 リリースノート、2026 年 11 月 5 日、パスワード認証回避と Özgün Kültekin へのクレジット: https://www.openssh.org/releasenotes.html#10.6p2 (2026 年 11 月 6 日確認)
  • OpenSSH コミット 4353fdc43ef646c43a8dda7025cc1a898caf1482、「avoid password authn bypass」、2026 年 11 月 5 日、MIN_PASSWORD_HASH_LEN のチェック: https://github.com/openssh/openssh-portable/commit/4353fdc43ef646c43a8dda7025cc1a898caf1482 (2026 年 11 月 6 日確認)
  • CVE-2026-123158 レコード、MITRE、2026 年 11 月 5 日公開、CVSS v3.1 8.1、CWE-394、概念実証の参照: https://www.cve.org/CVERecord?id=CVE-2026-123158 (2026 年 11 月 6 日確認)
  • Alpine Linux、「OpenSSH password authentication bypass」、2026 年 11 月 5 日、影響する設定、修正済みパッケージ、回避策: https://alpinelinux.org/posts/2026-11-05-openssh-password-authentication-bypass/ (2026 年 11 月 6 日確認)
  • 「sshole」、研究者の解説とブラウザーラボ、musl と OpenSSH の経緯、悪用条件: https://sshhole.com/ (2026 年 11 月 6 日確認)
  • musl コミット b3c4cc12、「crypt: return "*" instead of NULL on failure」、2012 年 8 月: https://git.musl-libc.org/cgit/musl/commit/?id=b3c4cc12 (2026 年 11 月 6 日確認)
  • musl コミット 88bf5a8a、SHA-512 鍵の 256 バイト上限、2012 年 8 月 29 日: https://git.musl-libc.org/cgit/musl/commit/?id=88bf5a8a (2026 年 11 月 6 日確認)
  • OpenSSH の auth-passwd.c、10.6p1 タグ、脆弱な比較: https://github.com/openssh/openssh-portable/blob/V_10_6_P1/auth-passwd.c (2026 年 11 月 6 日確認)
  • OpenSSH の openbsd-compat/xcrypt.c、10.6p1 タグ、pick_salt() と xcrypt(): https://github.com/openssh/openssh-portable/blob/V_10_6_P1/openbsd-compat/xcrypt.c (2026 年 11 月 6 日確認)
  • Docker Hub、公式 alpine イメージ、12,476,923,091 回のプル、到達規模の指標: https://hub.docker.com/_/alpine (2026 年 11 月 6 日確認)
  • CISA Known Exploited Vulnerabilities カタログの JSON フィード、2026 年 11 月 6 日に CVE-2026-123158 を確認 (未掲載): https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json (2026 年 11 月 6 日確認)