SSHhole(CVE-2026-123158)漏洞分析、利用条件与排查指南
又出洞了,还能密码绕过,还是ssh,要开始口吐芬芳了。估计运维老表们这周又是加班的一周了,我也赶忙搞了一下,还好,我用的不多,哈哈哈哈哈。但是排查脚本还是得安排一下,主要还是alpine 和 openwrt,大家还是查查,给运维老表个交代吧。

一、漏洞概述
SSHhole(CVE-2026-123158)是一个影响 OpenSSH SSH 密码认证过程的安全漏洞。漏洞主要涉及使用 musl libc 的 Linux 系统,在特定认证配置下,攻击者可能通过提交特殊构造的超长密码,绕过 SSH 密码认证,登录原本不允许密码登录的账户。漏洞的核心问题是:musl libc 在处理超长密码时,crypt() 函数可能返回 *,而 OpenSSH 在特定认证逻辑中可能将该返回值与 /etc/shadow 中的密码字段进行比较,从而导致错误匹配。
▍漏洞基本信息
二、漏洞原理
▍2.1 正常 SSH 密码认证流程
Linux 系统通常通过 /etc/shadow 保存用户密码哈希。
例如:
root:*
alpine:*
admin:$6$xxxxxxxx$xxxxxxxxxxxxxxxx其中:
root:*:表示该账户没有可用的常规 Unix 密码认证凭据。alpine:*:同样属于密码字段为*的账户。admin:$6$...:表示该账户使用 SHA-512 格式的密码哈希。
在未启用 PAM 的特定 OpenSSH 认证路径中,OpenSSH 会调用系统的 crypt() 函数处理用户输入的密码,并将结果与账户密码哈希进行比较。
▍2.2 漏洞产生的原因
问题出现在 musl libc 对超长密码的处理过程中。
当攻击者提交超过特定长度限制的密码时,crypt() 可能返回特殊值 *,而不是正常的密码哈希。
如果目标账户的 /etc/shadow 密码字段也为 *,就可能出现错误匹配。
* | |
* | |
三、漏洞利用的条件

SSHhole 并不是所有 Linux 系统都能利用,需要同时满足以下五个条件。
▍3.1 必要的条件
UsePAM 和编译配置 | |||
PasswordAuthentication yes | |||
/etc/shadow* | |||
$5$ 或 $6$ 密码哈希账户 |
▍3.2 Donor Hash 是什么?(新知识点出现了,跟着我学更多新知识,哈哈哈哈哈)
Donor Hash 可以理解为提供有效密码哈希信息的账户。
在这个漏洞的认证逻辑中,目标账户密码字段为 *,而另一个具有有效 $5$ 或 $6$ 哈希的账户可能成为 Donor。
例如:
root:*
alpine:*
admin:$6$xxxxxxxx$xxxxxxxxxxxxxxxx这里:
* | ||
* | ||
$6$... |
需要注意:
Donor 账户需要满足有效账户状态要求。 仅仅存在 $5$或$6$字符串,并不能直接认定满足条件。账户锁定、过期、Shell 设置等也需要进一步核实。
▍3.3 哪些 Linux 系统需要重点排查?(windows 暂时不受影响)
注意:Debian、Ubuntu 等默认使用 glibc,并不意味着所有特殊构建环境都可以直接排除。并不是直接利用成功后就直接root权限了,取决于你用的哪个权限账号。
四、漏洞排查脚本(有必要安排一下)
下面提供一个 Shell 脚本,用于检查 Linux 系统是否满足 SSHhole 的五项条件。脚本采用只读检查,不会尝试漏洞利用,也不会修改系统配置。
▍4.1 检查的内容包括:
/etc/os-release | |
ldd | |
sshd -T | |
sshd -T | |
sshd -T | |
/etc/shadow | |
$5$、$6$ |
▍4.2 完整脚本
保存为 sshhole_check.sh:
#!/bin/sh
# SSHhole CVE-2026-123158
# Read-only security detection script
echo "=========================================="
echo " SSHhole Vulnerability Detection"
echo " CVE-2026-123158"
echo "=========================================="
# 1. Operating System
echo
echo "[1] Operating System"
if [ -f /etc/os-release ]; then
grep -E '^(NAME|ID|VERSION_ID)=' /etc/os-release
fi
# 2. Find sshd
echo
echo "[2] SSHD Binary"
SSHD=$(command -v sshd 2>/dev/null)
if [ -z "$SSHD" ]; then
for f in /usr/sbin/sshd /sbin/sshd; do
if [ -x "$f" ]; then
SSHD="$f"
break
fi
done
fi
if [ -z "$SSHD" ]; then
echo "[INFO] sshd not found"
exit 0
fi
echo "SSHD: $SSHD"
# 3. Check libc
echo
echo "[3] libc Detection"
LIBC_INFO=$(ldd "$SSHD" 2>&1)
if echo "$LIBC_INFO" | grep -qi 'musl'; then
echo "[RISK] musl libc detected"
MUSL=1
else
echo "[INFO] musl libc not detected"
MUSL=0
fi
echo "$LIBC_INFO" | grep -Ei 'musl|libc\.so' | head -5
# 4. Effective SSH configuration
echo
echo "[4] SSHD Configuration"
SSHD_CONFIG=$("$SSHD" -T 2>/dev/null)
if [ -z "$SSHD_CONFIG" ]; then
echo "[WARN] Cannot read effective SSHD configuration"
exit 1
fi
USEPAM=$(echo "$SSHD_CONFIG" |
awk '$1=="usepam"{print $2; exit}')
PASSWORD=$(echo "$SSHD_CONFIG" |
awk '$1=="passwordauthentication"{print $2; exit}')
ROOTLOGIN=$(echo "$SSHD_CONFIG" |
awk '$1=="permitrootlogin"{print $2; exit}')
echo "UsePAM: ${USEPAM:-unknown}"
echo "PasswordAuthentication: ${PASSWORD:-unknown}"
echo "PermitRootLogin: ${ROOTLOGIN:-unknown}"
if [ "$USEPAM" = "no" ] || [ -z "$USEPAM" ]; then
echo "[RISK] PAM disabled or unavailable"
PAM_OFF=1
else
echo "[INFO] PAM enabled"
PAM_OFF=0
fi
if [ "$PASSWORD" = "yes" ]; then
echo "[RISK] Password authentication enabled"
PASS_ON=1
else
echo "[INFO] Password authentication disabled"
PASS_ON=0
fi
# 5. Account inspection
echo
echo "[5] Account Inspection"
if [ "$(id -u)" -ne 0 ]; then
echo "[WARN] Please run as root"
exit 1
fi
if [ ! -r /etc/shadow ]; then
echo "[WARN] Cannot read /etc/shadow"
exit 1
fi
TARGETS=""
DONORS=""
while IFS=: read -r user hash rest; do
shell=$(awk -F: -v u="$user" \
'$1==u {print $7; exit}' /etc/passwd)
case "$shell" in
*/nologin|*/false|"")
continue
;;
esac
case "$hash" in
'*')
TARGETS="${TARGETS}${user} "
;;
\$5\$*|\$6\$*)
DONORS="${DONORS}${user} "
;;
esac
done < /etc/shadow
if [ -n "$TARGETS" ]; then
echo "[RISK] Potential target accounts: $TARGETS"
TARGET_FOUND=1
else
echo "[INFO] No target accounts found"
TARGET_FOUND=0
fi
if [ -n "$DONORS" ]; then
echo "[RISK] Potential donor accounts: $DONORS"
DONOR_FOUND=1
else
echo "[INFO] No donor accounts found"
DONOR_FOUND=0
fi
# 6. Root login policy
echo
echo "[6] Root SSH Policy"
case "$ROOTLOGIN" in
yes)
echo "[WARN] Root SSH login is permitted"
;;
prohibit-password|forced-commands-only|no)
echo "[INFO] Root password login restricted"
;;
*)
echo "[WARN] Unknown root login policy"
;;
esac
# 7. Final assessment
echo
echo "=========================================="
echo " Final Assessment"
echo "=========================================="
if [ "$MUSL" -eq 1 ] &&
[ "$PAM_OFF" -eq 1 ] &&
[ "$PASS_ON" -eq 1 ] &&
[ "$TARGET_FOUND" -eq 1 ] &&
[ "$DONOR_FOUND" -eq 1 ]; then
echo "[CRITICAL] ALL FIVE CONDITIONS MATCH"
echo "Potentially vulnerable to SSHhole!"
else
echo "[INFO] Five-condition match not established"
echo "musl=$MUSL"
echo "pam_disabled=$PAM_OFF"
echo "password_auth=$PASS_ON"
echo "target_account=$TARGET_FOUND"
echo "donor_account=$DONOR_FOUND"
fi
echo
echo "[NOTE] Configuration-based assessment only."
echo "Verify patches, account status and running binary."
echo "=========================================="▍4.3 脚本用法
chmod +x sshhole_check.sh
sudo ./sshhole_check.shAlpine Linux 也可以直接执行:
sh sshhole_check.sh▍4.4 脚本的检查结果说明
musl=0 | |
pam_disabled=0 | |
password_auth=0 | |
target_account=0 | |
donor_account=0 | |
1 |
注意啊: 该脚本属于初步配置检查,不等于漏洞利用验证。不等于漏洞利用验证。
五、入侵排查
如果服务器已经满足 SSHhole 的利用条件,还需要进一步判断是否曾经被利用。
最值得关注的现象是:
密码字段为 * 的账户,却出现了 SSH 密码认证成功的日志。
▍5.1 检查 SSH 登录日志
Alpine Linux:
grep "Accepted password" /var/log/messagesDebian / Ubuntu:
grep "Accepted password" /var/log/auth.log使用 systemd 的系统:
journalctl -u sshd --since "7 days ago"重点关注以下日志:
Accepted password for alpine from 192.0.2.100 port 12345 ssh2▍5.2 检查异常账户
例如:
grep '^alpine:' /etc/shadow如果返回:
alpine:*:20125:0:99999:7:::同时 SSH 日志中出现:
Accepted password for alpine则属于高度可疑行为,需要进一步排查确认。
▍5.3 检查异常权限提升
检查是否存在异常用户:
awk -F: '$3 >= 1000 {print $1,$3,$7}' /etc/passwd检查 doas 配置:
cat /etc/doas.conf检查 SSH 公钥是否被植入:
find /root /home -name authorized_keys -type f -ls检查近期修改的系统文件:
find /etc /root /home -type f -mtime -7 -ls▍5.4 入侵排查的重点
注意:Accepted password 本身不能单独证明 SSHhole 被利用,还需要结合账户密码字段、认证配置、登录来源和补丁状态进行关联分析。
六、漏洞修复建议
▍6.1 升级 OpenSSH
推荐优先升级到包含修复补丁的版本。
OpenSSH 官方修复版本:
OpenSSH 10.6p2Alpine Linux 可以使用:
apk update
apk upgrade -U -a升级后重启 SSH:
rc-service sshd restart需要注意,发行版可能通过补丁回移修复漏洞,因此不应只根据版本号判断是否安全,应以发行版安全公告和软件包修复状态为准。
▍6.2 临时关闭密码认证
如果暂时无法升级,可以关闭 SSH 密码认证。
编辑配置文件:
vi /etc/ssh/sshd_config设置:
PasswordAuthentication no检查配置:
sshd -t重启服务:
rc-service sshd restart执行之前应确保 SSH 公钥认证正常,避免远程管理连接中断。
最后给搞安全的兄弟安排的一些资料,请大家自觉遵守网络安全法
漏洞验证的poc:
https://github.com/predkambrij/sshhole-repro
漏洞作者的分析:
https://sshhole.com/
ssh官方修复说明:
https://github.com/openssh/openssh-portable/commit/4353fdc43ef646c43a8dda7025cc1a898caf1482