影响范围
Openssh Server 9.1
漏洞触发
漏洞利用很简单,在连接建立与版本协商的时候将 softwareid 设置成特定版本(如 PuTTY_Release_0.64
)即可触发。
漏洞分析
这个漏洞的成因位于算法协商与密钥交换阶段:
// sshd.c
do_ssh2_kex(ssh); # First Free
do_authentication2(ssh); # Double Free
首先查看上游修复位置,主要修复了这一段代码,根据 BugZilla 中的报告,这里应该是第一次被 free 的位置:
char *
compat_kex_proposal(struct ssh *ssh, char *p)
{
char *cp = NULL;
if ((ssh->compat & (SSH_BUG_CURVE25519PAD|SSH_OLD_DHGEX)) == 0)
return xstrdup(p);
debug2_f("original KEX proposal: %s", p);
if ((ssh->compat & SSH_BUG_CURVE25519PAD) != 0)
if ((p = match_filter_denylist(p,
"[email protected]")) == NULL)
fatal("match_filter_denylist failed");
if ((ssh->compat & SSH_OLD_DHGEX) != 0) {
cp = p;
if ((p = match_filter_denylist(p,
"diffie-hellman-group-exchange-sha256,"
"diffie-hellman-group-exchange-sha1")) == NULL)
fatal("match_filter_denylist failed");
free(cp);
}
debug2_f("compat KEX proposal: %s", p);
if (*p == '\0')
fatal("No supported key exchange algorithms found");
return p;
}
在 SSH_OLD_DHGEX
被设置时,会将字符串 p 赋值给 cp 然后释放掉。此时传进来的字符串 p 是 option->kex_algorithms
。此时这个指针已经变成了一个悬空指针。
崩溃现场位于 kex_assemble_names
函数。kex_assemble_names
函数在 assemble_algorithms
中被调用,传进来的参数也是 option->kex_algorithms
导致了 double free。
接下来看一下漏洞路径,重点在于 SSH_OLD_DHGEX
这个参数,这个参数是在 compat_banner
函数中定义的:
static struct {
char *pat;
int bugs;
} check[] = {
... ...
{ "PuTTY_Local:*," /* dev versions < Sep 2014 */
... ...
"PuTTY_Release_0.64*",
SSH_OLD_DHGEX },
... ...
};
除了 PuTTY 的旧版本外,理论上其它带有 SSH_OLD_DHGEX
标志的客户端也能触发漏洞。
补丁分析
补丁的做法很简单,删去了 cp=p
这一行,并修改了 check 逻辑,避免传入的 p
成为悬空指针。