257 个字符撬开 root:Alpine Linux 藏了十年的 SSH 认证绕过

导语:11 月 5 日,OpenSSH 罕见地发了一个紧急补丁版本 10.6p2,修掉的是一个藏了十年的老洞——CVE-2026-123158。在用了 musl 库又没开 PAM 的 Linux 上,攻击者连密码都不用知道,发一串 257 字节的字符,就能登录那些本该只认密钥的账号。


CVE-2026-123158 OpenSSH 认证绕过

一颗星号,和一串 257 个字符

MITRE 给 CVE-2026-123158 的评分是 CVSS 3.1 8.1(High):走网络,不需要登录,不需要用户交互。发现者是独立研究员 Özgün Kültekin(Wakefield),他给这个洞起名 *sshole(星号洞)。

条件苛刻,但凑齐了就是 100% 成功。OpenSSH 负责人 Damien Miller 的原话:能连上 SSH 端口的攻击者”不需要知道任何密码”,一次连接就成。

Alpine 官方公告里那句话更直接——官方 AWS 和 Azure 云镜像上那个默认就叫 alpine 的账号带免密 doas 权限,拿到它就是拿到 root。

一颗星号的十年流浪史

根子不在 OpenSSH,在 Unix 用了几十年的一个约定:/etc/shadow 里密码位写一个星号,意思是”这账号没有密码,别拿口令登”。

1980 年 Bill Joy 往 3BSD 的 /etc/passwd 里塞星号时,这只是占位符。2012 年 musl 改了 crypt():以前哈希算不出来返回 NULL,很多程序不检查,撞上就崩;musl 改成返回单个字符——星号。从那以后,”哈希失败”和”没有密码”在 musl 上是同一个字符串。

2016 年 OpenSSH 修 CVE-2016-6210(用户名枚举)时加了一段逻辑:账号没有可用哈希,也借别人的盐算一遍,把响应时间拉平。问题就埋在这——连星号账号也一起拿去哈希了。

再叠加 musl 的另一个特性:sha512 太慢,口令长度被卡在 256 字节,超出直接失败。失败返回什么?星号。sshd 拿”“和 shadow 里的”“做字符串比较,比中了。

*sshole 十年时间线

最扎心的一处:OpenSSH 在 2026 年 10 月 30 日刚修过一次 pick_salt(),这个洞就在那段代码下面四行,四天后才被人发现。

攻击链:一串字符怎么进门

完整利用链只有五步,全程不需要试错:

CVE-2026-123158 攻击链

触发这个洞需要四个条件同时成立:

  • 跑在 musl 上——Alpine、OpenWrt、Buildroot、Yocto,以及你从 Docker Hub 拉回来的那一堆镜像
  • 没走 PAM——Alpine 的 openssh-server 默认不走,或者你自设了 UsePAM no
  • PasswordAuthentication yes——OpenSSH 的默认值
  • 机器上同时存在两类账号:一个密码位是 * 的,和至少一个哈希以 $5$/$6$ 开头的

最后一条最反直觉:一个带密码的账号,就能让所有没密码的账号沦陷。那个 $5$/$6$ 账号只是提供一把盐,而 sshd 恰恰要借盐给”假用户”算哈希。

攻击要的东西很简单:一个 * 账号的用户名,加一条 257 到 1024 字节的口令(1024 是 OpenSSH 的 MAX_PASSWORD_LEN),一次即中。

有正常密码的账号不受影响——它的哈希是 $6$... 长串,算出来不会等于星号。受害的只有被标记为”无密码”的:key-only 用户、root,以及 Alpine 云镜像里的 alpine 用户。

谁在暴露面上

Alpine 官方公告说得很清楚:检查过的每个版本都中招,3.21 到 3.24、edge,以及已停更的 3.16 到 3.20。受影响的账号包括:

  • 自 3.16 起就以 root:* 存在于基础镜像的 root(默认 PermitRootLogin prohibit-password 挡住直接登录,但挡不住一个能 doas 提权的账号)
  • adduser 建了没设密码的 key-only 用户,或 usermod -p '*' 改过的
  • 通过 musl-nscd 从 nslcd、winbind、sssd 拉进来的目录服务用户——他们没有 shadow 条目
  • tiny-cloud 云镜像(3.18.11 到 3.24.3)里的 alpine 用户,带免密 doas

不受影响的:glibc 系统(Debian、Ubuntu、Fedora)、走 PAM 的配置(openssh-server-pam 且 UsePAM yes)、密码位写成 ! 的锁定账号、PasswordAuthentication no 的机器、没有任何 $ 哈希的机器、没跑 sshd 的容器。OpenWrt 默认用 Dropbear,不受影响,除非你自己装了 OpenSSH。

补丁只加了三行

OpenSSH 10.6p2 的提交是 4353fdc,Damien Miller 亲自写的。核心改动小得有点好笑,auth-passwd.c 里多了这么个判断:

#define MIN_PASSWORD_HASH_LEN	4
...
ret = encrypted_password != NULL &&
    strlen(pw_password) >= MIN_PASSWORD_HASH_LEN &&
    strcmp(encrypted_password, pw_password) == 0;

存储的密码字段不到 4 个字符一律不接受——星号只有一个字符,直接出局。其余改动是 shadow_pw() 返回堆副本、认证完 freezero() 擦干净,顺带修掉 pick_salt()。

Damien Miller 在提交说明里很坦率:根因不在 OpenSSH,但 OpenSSH 有能力绕开,所以绕了。

Alpine 的修复包覆盖所有分支——edge 10.6_p2-r0,3.24 是 10.3_p1-r2,一路修到 3.16 的 9.0_p1-r6。有个坑必须提:升级包不会重启正在跑的 sshd,升级完得手动 rc-service sshd restart。

检测与止血

先查有没有被登过:

grep "Accepted password" /var/log/messages
grep '^alpine:' /etc/shadow

如果 shadow 里密码位是 *,日志里却有这个账号的密码登录成功记录,就该好好查一查了。

来不及打补丁,PasswordAuthentication no 能立刻止血。改之前先确认密钥登录能用、保持当前会话别断,验证新连接能进来再重启 sshd——Alpine 从 3.19 开始读 /etc/ssh/sshd_config.d 目录,旧版本得改主配置文件。

三件值得记住的事

第一,这个洞是AI 找出来的。Kültekin 用一批 agent 智能体把 sshd 按 glibc、musl、PAM、有无 shadow 的组合全编译了一遍,往里扔了约 17600 次畸形登录。OpenSSH 团队自己在 10.6 发布说明里也承认,最近大量安全报告来自 AI 模型——不向开源项目报告漏洞的攻击者,同样有能力挖出这些洞。

第二,“没有密码”从来不等价于”不能登录”。用星号表达不可登录的约定写在 Unix 的血液里,却从没被当成一条安全边界。

第三,这十年不是运气。OpenSSH 的测试覆盖 OpenBSD 和 glibc,musl 这边不测 sshd;大多数发行版走 PAM,而 PAM 对 账号压根不调 crypt。2013 年就有人要求 glibc 抄 musl 的做法,Debian 拖到 2024 年才换 libxcrypt——而它失败时返回 0。差一个字符,这个洞本来就没了。

总结

CVE-2026-123158,CVSS 8.1,修复版 OpenSSH 10.6p2,Alpine 各分支同步发包。目前没有任何野外利用报告,这跟它条件苛刻有关:四个前置条件必须同时成立。

但别当成安全保证。这个洞不需要爆破、不需要撞库、一次连接直接进门,而 Alpine 又是容器和云镜像的顶流底座。自己扫一遍:升级 OpenSSH,把 PasswordAuthentication no 写进配置,检查日志。

SSH 的老规矩是”没密码就别登”,这条规矩在 musl 上守了十年没守住。修它的方式朴素到有点心酸——数一下密码位有几个字符。


资料来源

  • sshhole.com:*sshole 研究者技术复盘
  • Alpine Linux 官方安全公告(2026-11-05)
  • OpenSSH 10.6p2 发布说明与提交 4353fdc
  • BleepingComputer / The Hacker News 报道
  • CVE-2026-123158 官方记录

版权声明:本文由华盟网原创发布,保留所有权利。漏洞利用仅用于授权测试与防御研究。

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容