
这是 云栈社区 近期关注的一个典型跨组件认证绕过案例。如果你只记住一句话:这个漏洞只打“musl + 没开 PAM 的 OpenSSH + 开着密码登录”这一小撮配置,但它能让本应“禁用密码”的账户被直接登进去,而且不需要密钥、不需要爆破。
2026 年 11 月 5 日,OpenSSH 发布紧急版本 10.6p2,同一天 Alpine 把修复回溯到 3.16 及之后所有分支。漏洞编号 CVE-2026-123158,发现者 Özgün Kültekin(Wakefield)给它起名 sshole。它的利用方式简单到反常识:朝一个本应禁止密码登录的账户,发送一段超过 256 字节的密码(实测可用 257 至 1024 字节,例如几百个重复的 A),就可能直接拿到 shell。
这不是 OpenSSH 写错了一行鉴权代码,而是三次年代各异的改动叠在一起,把一个“报错星号”和“密码禁用星号”撞出了相等的巧合。下面拆开看。
一、先看问题:能打穿的是“一小撮”配置,不是所有 SSH
1.1 官方记录与评分
- 编号与昵称:CVE-2026-123158,昵称 sshole(写作 *sshole),由 Özgün Kültekin 发现并公开在 sshhole.com。
- 评分:CVSS 3.1 8.1 High。部分媒体称其为 critical,但公开评分值为 8.1;评级未到 critical 的原因是攻击需要多条本地配置同时对齐,复杂度高,而一旦条件满足即可完整远程登录。
- CWE:公开记录未给出统一 CWE 编号(多家通报以“认证绕过 / 限制绕过”描述)。
- 受影响组件:OpenSSH 10.6p2 之前,且部署在 musl libc + 未使用 PAM 的形态下。
- 修复时间:OpenSSH 10.6p2 与 Alpine 全分支回溯包均于 2026 年 11 月 5 日 发布。
1.2 四个条件必须同时成立
Alpine 与 OpenSSH 的公告都强调,下面四条必须同时为真,缺一不可:
- musl,且未走 PAM:sshd 链接 musl,并以
--without-pam 构建,或运行时 UsePAM no。Alpine 默认的 openssh-server 包正是这种形态。
- 开启密码认证:
PasswordAuthentication yes,这是 OpenSSH 的默认值,除非被改过。
- *存在一个 `
账户**:某可命名账户的 shadow 密码字段为*(仅密钥用户、目录用户,以及 Alpine 3.16 起默认的root`)。
- 存在一个 donor 哈希:至少一名其他本地账户拥有
$5$ 或 $6$ 格式的密码哈希,供借用 salt;有一个就足以暴露所有 * 账户。
四条里只要断掉任意一条(例如开了 PAM、关了密码登录、没有 * 账户、或完全没有 $5$/$6$ 哈希),利用就失效。
1.3 信源能证明到哪一步
本文交叉核对了源站技术分析、阿里云漏洞库、HKCERT、CSO Online、Digital Advisors、CyberSecurityWaala,以及 OpenSSH 10.6p2 发布说明、Alpine 官方公告、musl 邮件列表。其中可以确定的是:
- 不受影响的范围:使用 glibc 的主流发行版(Debian、Ubuntu、RHEL/Fedora、SUSE)不受影响,因为 glibc 的
crypt() 在失败场景下返回 *0 而非 *,不会与存储的 * 相等;使用 PAM 的 sshd 不受影响;改用 Dropbear 等其它 SSH 服务端的嵌入式系统不受影响;不运行 sshd 的容器不受影响。
- 需要自查的范围:OpenWrt、Buildroot、Yocto 等同样基于 musl 的构建,以及各类 musl 容器镜像,应按上述四条条件逐项排查。OpenWrt 默认使用 Dropbear,不受影响;但其 OpenSSH 包若在,需看配置。
- 在野利用:截至检索(2026-11-06),Detectify 表示尚未看到公开的实际利用报告;watchTowr 则判断,既然互联网上的 SSH 爆破 从不停歇,攻击者只需把“超长密码尝试”加进爆破字典,周末前就可能被广泛滥用。因此“暂无在野”不能当作“不用修”的理由。
二、漏洞不是“OpenSSH 写错了”:三次改动叠出来的
这个洞最值得记的地方,是它没有任何一方愿意认领“这是我代码的 bug”。三次彼此独立的改动,分别解决的是不同的老问题,时间跨度从 2012 到 2022,直到组合到一起才变成认证绕过。
2.1 2012,musl 给 crypt() 加了“长度上限 + 报错星号”
musl 的 crypt() 在处理 $5$(SHA-256)和 $6$(SHA-512)salt 时,把密码长度限制为 256 字节,目的是防止攻击者用超长密码拖垮服务端哈希资源。同时,当密码超长导致哈希无法进行时,crypt() 不再返回 NULL,而是返回一个字面字符串 "*" 表示“处理失败”。这恰好和 Unix 自 1980 年代起用来标记“该账户不应匹配任何密码”的 * 是同一个字符。
2.2 2016,OpenSSH 为防用户名枚举,给 * 账户也走哈希
CVE-2016-6210 的修复目标是阻止攻击者通过“用户名存在与否导致响应耗时不同”来枚举账号。做法是:当目标账户的密码字段本身没有提供 salt(比如字段是 *)时,sshd 借用系统上另一个真实账户的 salt 来计算哈希,使所有登录尝试的耗时趋同。这一步让 * 账户也进入了“调用 crypt() 做哈希比较”的路径。
2.3 2022,Alpine 把 root 改成 root:*
Alpine 将 root 的密码字段设为 *,以便 root 仍能通过 SSH 密钥登录,同时显式禁止密码登录。这把“系统上存在 * 账户”从个别现象变成了 Alpine 的默认事实。
2.4 责任归属:两边都说“不是我”
OpenSSH 维护者(Damien Miller)称 10.6p2 的修复是一个 workaround,因为“该漏洞的根因在 sshd 之外”。musl 维护者 Rich Felker 也同意这是 caller(调用方)的问题,而非 musl 的 bug,但同时表示 musl 的相关行为很可能在下个发布周期改变。这种“互相甩锅但都动手修”的状态,正是这类跨组件漏洞的典型特征:单看每个组件的行为都合理,组合后的语义冲突才是问题。
三、绕过到底怎么发生:把“报错星号”当成了“密码星号”

图 1:本文依据公开技术分析绘制的机制示意,不是原始攻击截图。
把三件事连起来,绕过就成立了:
- 攻击者针对一个 shadow 密码字段为
* 的账户(例如仅用密钥登录的 bob)发起 SSH 连接,发送一段 257 至 1024 字节 的密码(如 300 个字母 A)。
- sshd(无 PAM)按 2016 年的逻辑,借用本机某个
$5$/$6$ 账户的 salt 对该超长密码调用 crypt()。
- 在 musl 上,因为密码超过 256 字节,
crypt() 直接返回 "*"。
- 目标账户存储的字段也是
"*",字符串比较相等,sshd 于是记录 Accepted password 并给出 shell。
公开报告对“是否一次成功”有两种说法:Alpine 与多家媒体称“一次连接、每次成功、无需重试”;源站技术分析则观察到首次尝试有时因 donor salt 扫描覆盖密码缓冲区而失败,第二次 salt 已缓存、读取干净后匹配成功。两种情形都说明利用门槛极低,不需要任何漏洞利用工程。
需要明确:攻击者仍需要知道一个有效的账户名,并且网络要能触达该 SSH 服务。它不是“互联网上任意 IP 输入超长密码就能进所有服务器”,而是“已知用户名 + 命中四条条件 + 可达 SSH”时的认证绕过。
四、谁真正踩雷:Alpine 默认中招,glibc 系统安全

图 2:本文依据 Alpine 与 OpenSSH 公告整理的“我是否受影响”判定,非官方流程图。
4.1 Alpine 默认配置开箱即中
Alpine 的标准 openssh-server 包以 --without-pam 构建,且 PasswordAuthentication 默认开启,因此默认形态同时满足前两条。再加上 Alpine 3.16 起 root 为 *,以及任意一台装过真实密码账户(几乎必然存在 $6$ 哈希)的机器,四条常常同时成立。这是本次受影响最集中的环境,也是云上 Docker 镜像最常用的基础系统之一。
4.2 PAM 形态安全,但别配反
若使用 openssh-server-pam 且配置 UsePAM yes,则不受影响。但如果同一包被显式设为 UsePAM no,仍会回到无 PAM 路径,继续受影响。排查时只看“装了哪个包”不够,还要确认实际运行配置。
4.3 云镜像陷阱:tiny-cloud 的 alpine 用户
Alpine 官方 tiny-cloud 镜像(3.18.11 至 3.24.3 的 qcow2、VHD、AMI)内置一个 alpine 用户,其密码字段为 *,且拥有免密 doas 提权权限。Alpine 公告指出:这些镜像首次启动时是安全的,但一旦机器上出现任意一个 $6$ 哈希(比如管理员设了控制台密码,或 user-data 添加带 hashed_passwd 的用户),攻击者就能以 alpine 身份拿到 shell,再用 doas 升到 root。也就是说,一个低权限账户的登录绕过,在暴露的云主机上可以直接演变成整机失陷。
4.4 其它 musl 环境逐个排查
OpenWrt、Buildroot、Yocto 以及各类 musl 容器镜像,只要满足四条条件就同样暴露。OpenWrt 默认用 Dropbear 不受影响;但其 OpenSSH 包若存在,仍需看 libc、PAM 与账户配置。Ars Technica 报道称,目前尚未确认还有哪些具体产品受影响,所以“非 Alpine 就安全”是错误结论,应基于四条条件做实证排查。
五、修复与重启:升级不重启,banner 会骗人
5.1 修复版本与逻辑
上游修复在 OpenSSH 10.6p2,代码逻辑为“当存储字段短于 4 个字符时拒绝匹配”,本质上把 * 这种禁用标记排除出比较。Alpine 将修复回溯到 3.16 及以上全部分支,关键包版本如下(节选自 Alpine 公告):
| 分支 |
修复包版本 |
对应点版本 |
| edge |
10.6_p2-r0 |
— |
| 3.24 |
10.6_p2-r0 |
3.24.4 |
| 3.23 |
10.3_p1-r2 |
3.23.8 |
| 3.22 |
10.2_p1-r1 |
3.22.8 |
| 3.21 |
10.0_p1-r11 |
3.21.10 |
| 3.20 |
9.9_p2-r1 |
— |
| 3.19 |
9.7_p1-r6 |
— |
| 3.18 |
9.6_p1-r3 |
— |
| 3.17 |
9.3_p2-r4 |
— |
| 3.16 |
9.1_p1-r7 |
— |
5.2 两个容易踩的坑
坑一:升级不重启运行中的守护进程。 apk upgrade -U -a 替换的是磁盘上的二进制,不会自动重启已经在跑的 sshd。Alpine 明确要求随后执行 rc-service sshd restart。不重启,漏洞仍在内存里生效。
坑二:banner 会显示旧版本。 打过补丁的机器,sshd -V 或握手 banner 仍可能报旧的 OpenSSH 版本号。排查应以包版本(apk info openssh)为准,而不是只看 SSH 横幅。
5.3 暂时不能升级的缓解
立刻在服务端关闭密码认证即可封堵利用通道:
# 3.19 及以上支持 drop-in 目录
echo 'PasswordAuthentication no' > /etc/ssh/sshd_config.d/00-no-passwords.conf
# 3.16-3.18 忽略该目录,需直接写入 /etc/ssh/sshd_config
sshd -t && rc-service sshd restart
前提是先确认密钥登录可用,否则把自己锁在门外。云镜像若依赖密码做初始接入,应先配置好密钥再关密码。
六、企业怎么查:版本、账户、日志、网络一起上
6.1 资产侧先收敛
至少回答:哪些主机是 Alpine/musl 环境,当前 openssh 包版本是多少;sshd 是否以无 PAM 形态运行(UsePAM 实际值);是否开启 PasswordAuthentication;是否存在 tiny-cloud 镜像的 alpine 用户。
6.2 账户侧提取 * 账户
awk -F: '$2=="*"{print $1}' /etc/shadow
输出即为“禁用密码”的潜在目标账户集合,应重点核对其中是否有可被网络触及的 SSH 登录名。
6.3 日志侧检索 IoC
核心指标是“针对 * 账户的 Accepted password”。可这样检索:
nopass=$(awk -F: '$2=="*"{print $1}' /etc/shadow | paste -sd'|' -)
grep -hE "Accepted password for ($nopass) " /var/log/messages /var/log/auth.log /var/log/secure
Alpine 的 SSH 日志通常在 /var/log/messages。匹配到即应视为强失陷信号。
6.4 网络与行为侧
在堡垒机、WAF 或 EDR 上监测异常长度的密码登录尝试(257 至 1024 字节)以及针对 * 账户的成功登录。由于攻击者可能在周末前把超长密码加进爆破字典,这类尝试会混入常规爆破流量,建议把“超长密码 + 禁用账户名”作为更高优先级告警。
6.5 一旦命中,按失陷处置
隔离主机、保全 EDR 时间线与认证日志、评估已登录账户是否具备 doas/sudo 提权、轮换可能暴露的凭据,并在全网检索同版本、同配置、同行为的主机,而非只处理单机。
七、结束语:一个“*”的歧义,十年才暴露
这个漏洞没有炫技的内存破坏,也没有复杂的利用链。它只是三个各自合理的设计选择,在十年里慢慢靠拢,把一个“函数报错的星号”和“账户禁用的星号”撞成了同一个字符串。攻击者要的只是一段够长的密码和一个已知用户名。
对应地,防守也不能只押“升级 OpenSSH”一个点。glibc 系统天然免疫,但 musl 世界的排查要落到四条条件上:是否无 PAM、是否开密码登录、是否有 * 账户、是否有 donor 哈希。对跑 Alpine 容器和云镜像的团队,真正的优先级是:升到 10.6p2 或对应回溯包、重启 sshd、确认包版本而非 banner、临时关掉密码认证、再回头查日志看是否已经被打过。
仍有开放问题需要跟踪:除 Alpine 外还有哪些具体 musl 产品实际受影响,以及周末之后是否会出现规模化在野利用。公开信息没有回答的部分,本文不作补写。后续 云栈社区 会持续整理这类跨组件漏洞的排查笔记。