SSHhole: OpenSSH root login with any 257+ char password on musl
- YT :: https://www.youtube.com/watch?v=B3_Ftfhkzz0
- Original title :: well this is bad
Prime walks through "SSHhole", a vulnerability found by Ozgun (sshhole.com): on Alpine, OpenWrt or any musl-based box running sshd with password auth and without PAM, anyone can log in as root by sending a password longer than 256 characters. The bug is not one mistake but three independently reasonable decisions, spread over 40 years, that line up.
Who is affected
- sshd on musl (Alpine - including the default Alpine Docker image - OpenWrt, etc.), password authentication enabled, PAM disabled.
- With PAM, OpenSSH delegates the check (and gets 2FA etc. for free); without PAM it uses its own hand-rolled password comparison - that is the vulnerable path.
The ingredients
- Asterisk as "no login" (1980): Bill Joy set the
daemonaccount's password field to*; no real hash can equal*, so nobody can log in. Password check =crypt(password, salt)compared with the hash in/etc/shadow. - crypt returns
*on failure (~2012): crypt used to return NULL on errors (unknown algorithm etc.), crashing callers; it switched to returning*. - musl's crypt rejects long passwords: hashing is CPU-heavy, so a 10,000-char password could pin a core per request (a DoS similar to ReDoS). musl caps input at 256 chars and returns
*("bad password") above that. - Fake-user timing defence (CVE-2016-6210): non-existent users returned instantly while real ones took a slow hash, enabling user enumeration. OpenSSH now hashes the supplied password with some other user's algorithm to simulate real timing.
- Root password set to
*(2022): a 2019 change put!in root's password field without PAM, which broke sshd; in 2022 it became*.
The exploit
- Log in as root with a password longer than 256 chars.
- Root has no usable hash, so sshd borrows another user's algorithm and calls crypt.
- musl crypt sees >256 chars and returns
*. - sshd string-compares the result with root's stored "hash" - also
*- match, root shell.
Takeaways
- Patch/update any Alpine/OpenWrt host or container exposing sshd with password auth; prefer key-only auth and PAM.
- The discoverer reportedly found it by throwing ~17,000 weird logins at OpenSSH with an agent swarm.
- Prime's point: none of the pieces is obviously wrong in isolation; sentinel values (
*) reused across layers turned "failure" into "match".