Hi all, In case it helps, below is a brief analysis of this vulnerability: ======================================================================== On February 2, 2023, OpenSSH version 9.2 was released: it fixes a pre-authentication vulnerability (a double free) in the OpenSSH server version 9.1 (only this specific version, which was released in October 2022). Affected users are urged to upgrade, as this vulnerability can be triggered in the default configuration of the OpenSSH server (sshd). This double free was introduced in July 2022 by the following commit: https://github.com/openssh/openssh-portable/commit/486c4dc3b83b4b67d663fb0fa62bc24138ec3946 and was reported to the OpenSSH Bugzilla in January 2023 by Mantas Mikulenas: https://bugzilla.mindrot.org/show_bug.cgi?id=3522 The chunk of memory that is freed twice is "options.kex_algorithms"; it is freed once via do_ssh2_kex(), which calls compat_kex_proposal(): ------------------------------------------------------------------------ 2374 do_ssh2_kex(struct ssh *ssh) .... 2381 myproposal[PROPOSAL_KEX_ALGS] = prop_kex = compat_kex_proposal(ssh, 2382 options.kex_algorithms); ------------------------------------------------------------------------ 191 compat_kex_proposal(struct ssh *ssh, char *p) ... 198 if ((ssh->compat & SSH_BUG_CURVE25519PAD) != 0) 199 if ((p = match_filter_denylist(p, ... 202 if ((ssh->compat & SSH_OLD_DHGEX) != 0) { 203 cp = p; 204 if ((p = match_filter_denylist(p, ... 208 free(cp); ------------------------------------------------------------------------ - if at line 198 the "SSH_BUG_CURVE25519PAD" compatibility bit is *not* set, - and if at line 202 the "SSH_OLD_DHGEX" compatibility bit *is* set, - then at line 203 "cp" becomes equal to "p", which is still equal to "options.kex_algorithms", - and at line 208 "cp" is freed, i.e. "options.kex_algorithms" is freed and becomes a dangling pointer. (Note: the "SSH_BUG_CURVE25519PAD" and "SSH_OLD_DHGEX" compatibility bits depend only on the client version, not on the server configuration; for example, the bug report mentioned earlier uses "PuTTY_Release_0.64", and we will use "FuTTY" for the ssh client version later in this post.) "options.kex_algorithms" is then freed a second time via do_authentication2(), which calls input_userauth_request(), which calls mm_getpwnamallow(), which calls copy_set_server_options(), which calls assemble_algorithms(), which calls kex_assemble_names() with "listp" equal to "&options.kex_algorithms", which therefore double-frees "options.kex_algorithms" at line 315: ------------------------------------------------------------------------ 225 kex_assemble_names(char **listp, const char *def, const char *all) ... 240 list = *listp; ... 315 free(list); ------------------------------------------------------------------------ To reproduce this vulnerability, we installed a Debian testing (bookworm, which ships OpenSSH 9.1p1 at the time of writing this post) and we simply modified the banner of the ssh client to pretend that it is a "FuTTY" client (to force the "SSH_OLD_DHGEX" compatibility bit in sshd): ------------------------------------------------------------------------ $ cp -i /usr/bin/ssh ./ssh $ sed -i s/OpenSSH_9.1p1/FuTTYSH_9.1p1/g ./ssh $ ./ssh -v 127.0.0.1 ... debug1: Local version string SSH-2.0-FuTTYSH_9.1p1 Debian-2 debug1: Remote protocol version 2.0, remote software version OpenSSH_9.1p1 Debian-2 ... debug1: SSH2_MSG_SERVICE_ACCEPT received Connection closed by 127.0.0.1 port 22 ------------------------------------------------------------------------ This connection immediately triggered a double free in the unprivileged sshd process, as shown by the "Connection closed by 127.0.0.1 port 22" message above and by the strace output below: ------------------------------------------------------------------------ writev(2, [{iov_base="free(): double free detected in tcache 2", iov_len=40}, {iov_base="\n", iov_len=1}], 2) = 20 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f093649e1f5, si_syscall=__NR_writev, si_arch=AUDIT_ARCH_X86_64} --- write(8, "\0\0\0g\0\0\0\1\0\0\0\0\0\0\0[ssh_sandbox_violation: unexpected system call (arch:0xc000003e,syscall:20 @ 0x7f093649e1f5)", 107) = 107 exit_group(1) = ? +++ exited with 1 +++ ------------------------------------------------------------------------ Exploiting this vulnerability will not be easy: modern memory allocators provide protections against double frees, and the impacted sshd process is unprivileged and heavily sandboxed. Once again we thank OpenSSH's developers for their outstanding work and for their implementation of these defense-in-depth mechanisms (privilege separation, sandboxing) that make it so much harder to exploit such a vulnerability. ======================================================================== With best regards, -- the Qualys Security Advisory team