300 个 a 就能登进你的服务器?CVE-2026-123158 拆解与排查实操
原创
维度攻防
维度攻防
维度攻防
2026年11月9日 10:09
安徽
去阅读
先说结论:CVE-2026-123158,SSH 密码认证绕过,影响 OpenSSH 7.3p1 至 10.6p1,修复版 10.6p2,CVSS 8.1。
它专挑你觉得最安全的地方生效——那些密码字段写着 *、你以为永远登不进去的账户。
前提是 musl libc + 未启用 PAM。所以 Debian、Ubuntu 基本无事,但 Alpine 容器、OpenWrt 路由器、Buildroot / Yocto 设备全在靶心上。
仅作防御性分析,请勿对未授权系统测试。
原理:* 撞上了 *
shadow 里的 *,意思不是「密码是星号」,而是一个永远算不出来的占位符。任何输入经 crypt() 都不可能得到 *,比较必然失败。这是出厂默认设置,也是运维心里的安全底线。
但 musl 的 crypt() 有个坑:输入超长时,它不返回哈希,直接返回 *。
于是比较就变成了:
| 正常 | 异常 |
crypt(输入) → $6$... |
crypt(超长输入) → * |
shadow 字段 → $6$... |
shadow 字段 → * |
| 不等,拒绝 | 相等,放行 |
攻击者不用猜密码,只要让 crypt() 放弃计算。所谓「输 300 个 a 就能登进去」,就是这么来的。
一句话:「算不出来」和「没有密码」被当成了同一件事。
五个条件,缺一不可
- musl libc
—— sshd 链接的是 musl
- PAM 未启用
—— 走非 PAM 认证路径
- 开着密码认证
—— PasswordAuthentication yes
- 有目标账户
—— shadow 里密码字段为 *
- 有 Donor Hash
—— 系统里另一个 $5$ / $6$ 的有效哈希账户
第五条最容易被忽略。musl 的 crypt() 放弃之前,得先知道「该算哪种算法」,这个信息来自另一个真实设了密码的账户。没有 Donor,它走不到返回 * 的分支,洞就打不动。
先自查,有没有被打过
盯一个信号:密码字段是 * 的账户,却出现了 Accepted password 日志。
Alpine
grep \"Accepted password\" /var/log/messages
Debian / Ubuntu
grep \"Accepted password\" /var/log/auth.log
systemd
journalctl -u sshd --since \"7 days ago\"
顺着再查四样:authorized_keys 有没有被植入、有没有新增可登录用户、/etc/doas.conf 有没有异常、/etc 近七天有没有被改。
单条日志不能定性,要跟账户状态、来源 IP、补丁情况一起看。
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论