2026 年 11 月 5 日,Linux 生态公布了一起打破密码学常识的安全漏洞。在数百万基于 Alpine 的容器中,原本禁止密码登录的管理员账号失守了。攻击者只要在输入框塞进 257 个随机字符,就能直接拿到系统权限。
常识认为密码越长越安全,超长输入理应被防线阻拦。现实却走向了反面。一道严密的门禁,被一串胡乱敲下的长字符顺手推开。
超长密码击穿防线:输入257个字符登入系统
漏洞的触发条件精确而特殊。目标服务器需要运行基于 musl C 库的 OpenSSH 服务,且未开启 PAM 模块。攻击者只要送入 257 到 1024 字节的长密码,认证就会立刻放行。
257 字节远超正常密码的长度。异常数据穿透了比对逻辑,系统把不可登录的账号判定为验证通过。防护设计在此刻失效了。
中招的账号具备明确特征。在影子文件 /etc/shadow 中,账号密码字段必须填着单字符 *。在 UNIX 规范里,星号代表该账号永不接受密码登录。云厂商的默认镜像、只用密钥的部署账号,都属于这类设定。
最省事的靶子在云上:Alpine 官方 AWS 和 Azure 镜像里的默认用户 alpine 就是这种设定,而它带免密 doas。拿下这个账号,等于直接拿到 root。
只要机器上还存在另一个常规哈希账号,攻击就能稳定复现。OpenSSH 会借用该账号的盐值抹平时序。多项防御配置组合在一起,反而送出了通行权限。
三个看似合理的决定,在四十六年后撞成漏洞
翻开系统演进史,这扇后门由三个独立设计拼装而成。它们相隔数十年。每个设计在诞生时都合理周密,组合在一起却成了灾难。
第一个决定发生在 1980 年。Bill Joy 在 3BSD 系统的密码文件里给服务账号 daemon 填入了一个 *。当时的加密算法算不出单字符星号,任何输入的密码都无法匹配。
图:1980 年 3BSD 的 passwd 文件原件截图,daemon 账号的密码字段被填入星号。来源:sshhole.com
这个用星号锁死账号的简易约定,沿用了整整 46 年。整个行业都默认用它标记不可登录账号。
第二个决定出现在 1997 年。UNIX 国际标准规定,密码加密函数 crypt() 运算出错时应当返回空指针。但许多 C 语言程序不检查空指针,遇到 NULL 会触发段错误导致服务崩溃。
2012 年 8 月,轻量级 C 库 musl 做出了调整。为了消除空指针崩溃隐患,代码提交 b3c4cc12 让函数出错时返回单字符 *。提交记录明确删除了不可能出错的注释。
图:musl 头文件注释明确记录,当计算发生错误时直接返回单个星号。来源:sshhole.com
在 musl 开发者眼里,星号代表计算失败。在系统运维眼里,星号代表禁止登录。双方赋予同一个字符截然不同的含义。
防死机设下长度红线,刚好撞上防侧信道假动作
第三个决定把两处星号接在了一起。2012 年 8 月 29 日,musl 库增加了对 SHA-512 算法的支持。这距离上次修改仅过了 20 天。
SHA-512 计算非常消耗资源,耗时会随长度增加。为防范超长密码拖垮服务器,musl 把密码上限卡在 256 字节。输入一旦超限,程序拒绝计算并返回单字符星号。
图:musl libc 在 crypt_sha512.c 中加入 256 字节长度上限,防止超长密码耗尽服务器算力。来源:sshhole.com
256 字节的硬上限防住了算力耗尽攻击。这处防御代码在库中平稳运行了多年。
2016 年 7 月,OpenSSH 修复了时序探测漏洞 CVE-2016-6210。此前系统对不存在用户的响应速度更快,黑客能借此枚举合法用户名。为了抹平耗时差异,OpenSSH 引入了保护动作。
面对没有哈希的账号,系统借用其他账号的盐值算一次密码。这个动作纯粹为了消耗时间。密码标记为星号的禁用账号,同样走进了这趟运算流程。
漏洞链条在此刻扣死。攻击者向 root 账号发送 257 字节的长密码,OpenSSH 借来盐值发起计算。musl 发现长度超限直接拒绝,返回了星号。OpenSSH 拿返回的星号与影子文件比对,两者分毫不差,系统直接放行。
容器轻量化普及,把小众设计推向数百万云端主机
musl 过去常用于路由器等嵌入式设备,攻击面原本有限。容器化浪潮的普及,将这个小众设计推向了服务器前沿。
Alpine Linux 仅有 5MB 大小,迅速成为全球容器镜像的通用基石。2019 年官方镜像修复 root 空密码缺陷,曾用叹号锁定密码。但叹号会阻断非 PAM 环境的密钥登录。各大云主机的公钥认证由此遭遇障碍。
2022 年发布的 Alpine 3.16 做出调整,将 root 密码重新改回星号。密钥登录恢复了正常。这一改动也让后续所有版本的容器与镜像,直接暴露在漏洞触发条件中。
技术社区对受损规模展开了评估。开发者 jbyers 指出,单个容器命中条件的概率并不高。但乘以全球庞大的容器总数,受影响的实例数量相当惊人。数以百万计的线上镜像都在无意中踩中了这块暗礁。
关于规范实现的争议也随之而来。开发者 NewJazz 质疑 musl 偏离了标准规范。有人援引 POSIX 原文反驳,指出规范仅定义了一个错误码,异常处理机制本就缺乏清晰标准。
Lobsters 社区的评论者 mort 则针对披露文风提出批评。他认为安全报告应当开门见山,讲清影响范围与修复方法。
修补漏洞只换安装包没用,必须立刻重启服务
2026 年 11 月 5 日,OpenSSH 上游发布了 10.6p2 版本。新版本增加了针对单字符返回值的过滤规则。应用层不再盲目依赖系统库的返回约定。
更新软件包只是第一步。Linux 进程驻留机制给许多管理员留下了认知盲区。
包管理器更新了磁盘文件,内存里的常驻进程依然保留着旧代码。如果不重启服务,系统依然受制于旧逻辑。运维人员必须重启 sshd 服务或者重建容器,防护才能生效。
纵观整个安全事件,没有任何一处代码由恶意写入。1980 年写入星号锁死权限,1997 年约定返回值规避崩溃。2012 年限制长度防范拒绝服务,2016 年引入伪装运算平抑时间差异。每一项设计都是当时的合理选择。
这些跨越数十年的防御逻辑在同一处汇聚。语义上的微小歧义,拼凑出了越权的隐秘通道。复杂的软件系统里,层层堆叠却彼此误解的防御体系,比单点缺陷更加隐蔽。
参考链接:
- sshhole.com 漏洞披露原文与在线自查页
- Alpine aports 提交 fbe926af:把 root 的密码字段从叹号改成星号
- OpenSSH 10.6p2 官方发布公告与补丁源码
- Hacker News 社区关于 musl crypt 错误返回值的技术辩论
- Lobsters 社区关于容器安全边界与处置方案的讨论