OpenSSH爆高危认证绕过漏洞:仅需一行超长密码,直接秒破Alpine服务器!"

admin 2026-11-10 16:37:43 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

OpenSSH爆高危认证绕过漏洞:仅需一行超长密码,直接秒破Alpine服务器!

原创

Kit Chung
Kit Chung

安全圈动向

2026年11月10日 12:26
广东

去阅读

大家好,如果你手里有跑在 Alpine Linux(或者 OpenWrt、Yocto 等基于 musl libc 的系统)上的服务器,且开启了 OpenSSH 服务,听我一句劝:赶紧去把版本升了,或者把密码登录关了!

OpenSSH 官方火速发布了 10.6p2 紧急更新,修复了一个被定性为 Critical(严重) 级别的认证绕过漏洞。

这个漏洞离谱到什么程度?攻击者甚至不需要爆破,只要知道你服务器上的一个免密账户名(比如专门配置了仅限 SSH 密钥登录的账号),然后随便敲一段 257 到 1024 字节 的超长密码(哪怕全是乱码),就能 100% 稳定绕过认证,单次连接直接登录成功!

OpenSSH 核心开发者 Damien Miller 甚至在通告里咆哮:“请受影响的系统立即设置 PasswordAuthentication=no 或直接禁用 SSH!”

作为一个常年和底层代码打交道的技术人,我第一时间去扒了它的技术细节和源码改动。看完之后我真的哭笑不得——这根本不是什么高深的内存溢出,而是两个写于十年前的“安全防御机制”,在阴差阳错之下碰撞出的“大乌龙”。

今天我就带大家深扒一下这个漏洞的底层原理、复现链路以及修复方案。


底层原理深扒:当 * 撞上 *

很多朋友看到这儿肯定会犯嘀咕:“我明明给账号设置了免密(仅限公私钥登录),为什么还能用密码登进去?”

要搞懂这个漏洞,我们得先把时钟拨回十多年前,看看 OpenSSH (sshd) 和 Alpine 底层 C 库 musl libc 是怎么在各自的逻辑里“埋雷”的。

1. 免密账户在 /etc/shadow 里长啥样?

在 Linux 系统中,用户的密码哈希存在 /etc/shadow 文件里。如果你用 adduser 创建了一个不带密码的纯密钥登录账号,或者执行了 usermod -p '*',甚至是从 Alpine 3.16 开始基础镜像里自带的 root 账号,它们在 /etc/shadow 里的密码字段都是一个孤零零的星号:*。

按照正常逻辑,任何密码经过哈希计算后都不可能是 *(因为正常的哈希值至少几十个字符,还带着 $5$ 或 $6$ 这种算法前缀),所以用密码登录时永远不可能匹配成功。

2. 第一颗雷:OpenSSH 的“借盐”机制(2016年)

在没有启用 可插拔认证模块 的情况下,sshd 会自己调用底层 C 库的 crypt(password, salt) 函数来校验密码:把用户输入的明文密码和存储的“盐”扔进去算一遍,看看算出来的结果和 /etc/shadow 里的字符串一不一致。

但问题来了:如果一个账号的密码字段是 *,长度只有 1 位,根本提取不出合法的 salt。如果 sshd 发现没有 salt 就直接报错返回,耗时就会极其短暂;而有正常密码的账号去跑 SHA-256($5$)或 SHA-512($6$)哈希则会耗时较长。

这就会导致著名的侧信道计时攻击(CVE-2016-6210)——攻击者可以通过响应时间差,轻松枚举出服务器上哪些用户名是真实存在的。

为了堵住这个洞,OpenSSH 在 2016年7月15日 提交了一个修改:如果当前登录的账户密码字段太短、拿不到 salt,那就去系统里“借”另一个真实账户的 salt(比如 $6$xxxx)来跑一遍 crypt(),以此保证所有账户校验耗时一致。

3. 第二颗雷:musl libc 的防 DoS 限制与错误返回值(2012年)

Alpine Linux 之所以体积小巧,是因为它没有用传统的 glibc,而是用了轻量级的 musl libc。

早在 2012年8月9日,musl 的开发者考虑到很多第三方程序在调用 crypt() 时根本不检查 NULL 指针返回值(容易引发空指针崩溃),于是做了一个“贴心”的改动:当 crypt() 计算失败时,不返回 NULL,而是返回一个“理论上绝不可能匹配成功的假哈希值”——也就是 *。

紧接着在 2012年8月29日,为了防止攻击者传入超长密码消耗 CPU 算力发起拒绝服务(DoS)攻击,musl 给 $5$(SHA-256)和 $6$(SHA-512)算法加了个硬性门槛:只要传入的密码长度超过 256 字节,crypt() 直接拒绝计算并报错返回!

4. 惊天大碰撞:负负得正!

现在,把这两颗跨越十年的雷拼在一起,见证奇迹的时刻到了:

  1. 攻击者尝试登录一个密码字段为 * 的免密账户。
  2. sshd

启动防计时攻击机制,从机器上另一个设置了密码的账户那里,借来了一个 $5$ 或 $6$ 开头的 salt。
3. 攻击者故意输入一个长度为 257 到 1024 字节(1024 是 sshd 自身的密码长度上限)的超长密码。
4. sshd

调用 musl 的 crypt(超长密码, 借来的$6$盐)。
5. musl

检测到密码超过 256 字节,触发防 DoS 报错机制,直接返回错误标识符 *。
6. sshd

拿着 crypt() 返回的 *,去和 /etc/shadow 里存储的 * 做字符串比对:
strcmp(\"*\", \"*\") == 0!完全匹配!校验通过!放行!

核心技术复盘:

原本用来代表“禁用密码登录”的占位符 *,和 musl 用来代表“函数执行报错”的返回值 *,在 OpenSSH 借盐机制的撮合下,完成了一次跨越十年的握手。这波操作,简直是教科书级别的“安全机制负负得正”。


攻击链路与中招自查:你的机器安全吗?

看完原理,我们来梳理一下完整的漏洞触发条件。根据 Alpine 官方安全公告,只要你的服务器同时满足以下 4 个条件,就处于完全暴露状态:

  • 条件 1:未使用 PAM 进行密码校验。

运行的是 Alpine 默认的 openssh-server 包(默认编译未开启 PAM),或者装了 openssh-server-pam 但配置了 UsePAM no。
* 条件 2:开启了密码认证。PasswordAuthentication

设置为 yes(这也是 OpenSSH 的默认配置)。
* 条件 3:存在密码字段为 * 的免密账户。
* 条件 4:机器上至少存在一个使用 $5$ 或 $6$ 哈希的正常密码账户。

(只要有一个账户设了密码,全机所有免密账户瞬间全部暴露!)

哪些账户和场景最危险?

在 Alpine 体系下,以下四类账号的密码字段默认就是 *:

  1. 用 adduser 创建且未设密码的纯密钥登录账号,或用 usermod -p '*' 锁定的账号。
  2. 通过 musl-nscd 从目录服务同步过来的账号(本地没有 shadow 记录)。
  3. Alpine 3.16

及更高版本基础镜像里的 root 账号(默认为 root:*)。
4. 官方 tiny-cloud 构建的云镜像中的默认 alpine 账号。

特别警惕云镜像的“提权组合拳”:
虽然 root 默认有 PermitRootLogin prohibit-password 保护,无法直接通过密码登录,但如果普通免密账号能提权,保护就形同虚设!
比如 3.18.11 到 3.24.3 版本的 tiny-cloud 官方云镜像,默认的 alpine 用户拥有免密的 doas(类似 sudo)权限。刚开机时因为全机没有任何密码哈希,它是安全的;但只要管理员给控制台或随便哪个新用户设了一个密码(生成了 $6$ 哈希),攻击者就能立刻用超长密码登录 alpine 账号,然后一行 doas 直接拿下 root 权限!

其他系统受影响吗?

  • 不受影响:

使用 glibc 的常规 Linux 发行版(如 Ubuntu、CentOS、Debian、RHEL)、非 Linux 系统、启用了 PAM 的系统、使用 ! 锁定密码(如 /etc/shadow 中为 !)的账户,以及通过 cloud-init 自动写入了 PasswordAuthentication no 的云主机。
* 需要排查的重灾区:

漏洞发现者 Özgün Kültekin 特别点名了 OpenWrt、Buildroot 和 Yocto 等同样基于 musl 的嵌入式/定制 Linux 系统。不过 OpenWrt 默认用 Dropbear 跑 SSH(不受影响),只有你手动安装了 OpenSSH server 时才需要紧张。


应急修复与入侵排查指南

目前 OpenSSH 10.6p2 的修复方式非常直接粗暴:只要发现存储的密码哈希长度小于 4 个字符,直接拒绝匹配(官方称之为 Workaround,因为根源在 musl 的返回值设计上)。

如果你维护着相关环境,请立刻按以下步骤操作:

方案一:升级软件包并重启服务(推荐)

Alpine 官方已经为 3.16 以来的所有分支(包括已过维护期的版本,以及最新的 3.21.10、3.22.8、3.23.8、3.24.4)推送了补丁包。
切记:升级完包之后,sshd 进程不会自动重启,必须手动重启服务!

# 1. 更新软件源并升级所有包
apk upgrade -U -a

# 2. 重启 sshd 服务使补丁生效
rc-service sshd restart

如果是自行编译 OpenSSH,请直接拉取最新的 10.6p2 源码重新编译部署。

方案二:临时关闭密码登录(无法立即升级时)

如果生产环境不便立刻升级,请立刻禁用密码登录(操作前请务必确保你的 SSH 密钥能正常登录,并保持当前终端连接不要断开,新开窗口测试成功后再退出!)。

在 Alpine 3.19+ 中,可以直接通过 drop-in 配置文件并批量替换主配置来彻底封死(防止 Match 块里有漏网之鱼):

# 写入独立配置并全局替换主配置中的 yes 为 no
mkdir -p /etc/ssh/sshd_config.d
echo \"PasswordAuthentication no\" > /etc/ssh/sshd_config.d/disable_passwd.conf
sed -i 's/^\\([[:space:]]*PasswordAuthentication[[:space:]]\\+\\)yes/\\1no/gi' /etc/ssh/sshd_config

# 检查配置语法并验证最终生效结果(应输出 passwordauthentication no)
sshd -t && sshd -T | grep -i passwordauthentication

# 重启服务
rc-service sshd restart

方案三:入侵痕迹排查(重中之重!)

打完补丁别忘了查日志!去翻一下 /var/log/messages(或系统的 auth 日志),重点搜索是否存在针对免密账户(如 root、alpine 或你的纯密钥账户)的 Accepted password for ... 记录。

如果发现了异常登录,或者机器此前长期暴露在公网且满足上述 4 个条件,请立刻审查 doas 执行记录、近期新建的用户、篡改的文件以及 ~/.ssh/authorized_keys。用官方安全公告的话说:“如果你无法100%排除被登录过的可能,请直接把这台机器当成已失陷处理!”


写在最后:为什么这次连漏洞静默期都没留?

这个潜伏了整整 10 年的漏洞,OpenSSH 团队这周早些时候才刚收到报告,结果第二天就直接公开并发布了补丁,甚至连 CVE 编号都还没来得及分配。

为什么这么急?Damien Miller 在发布公告里说了一句话:

“我们现在认为,漫长的漏洞静默期是非常危险的,它主要是在帮攻击者的忙——因为我们最近多次发现,AI 智能体能够在极短的时间内(有时仅仅几个小时)独立重复挖掘出完全相同的漏洞。”

在 AI 自动化代码审计和漏洞挖掘狂飙突进的今天,传统的“厂商内部捂几个月慢慢修”的节奏已经彻底失效了。防守方和攻击者都在和 AI 赛跑。

赶紧去检查一下手里的 Alpine 容器和软路由吧!如果觉得这篇技术拆解对你有帮助,欢迎点赞、收藏、转发到你的技术群里吧!

Linux运维#网络安全#OpenSSH#Alpine#漏洞复盘


评论:0   参与:  0