From 9032e60e13feed11be16abc7abc08d64361f5897 Mon Sep 17 00:00:00 2001 From: djm Date: Sun, 31 May 2026 04:44:38 +0000 Subject: [PATCH] make the transport protocol stricter by disconnecting if the peer sends non-KEX messages during a key re-exchange. Previously an evil peer could continue sending non-KEX messages without penalty, causing memory to be wasted up until the connection terminated or the server/client hit a OOM limit. reported by Marko Jevtic; ok markus@ --- usr.bin/ssh/kex.c | 9 +++++++-- usr.bin/ssh/kex.h | 3 ++- usr.bin/ssh/packet.c | 9 ++++++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/usr.bin/ssh/kex.c b/usr.bin/ssh/kex.c index c95010a44b3..12ca0458805 100644 --- a/usr.bin/ssh/kex.c +++ b/usr.bin/ssh/kex.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kex.c,v 1.193 2026/03/05 05:40:35 djm Exp $ */ +/* $OpenBSD: kex.c,v 1.194 2026/05/31 04:44:38 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * @@ -565,7 +565,7 @@ kex_input_newkeys(int type, uint32_t seq, struct ssh *ssh) kex->done = 1; kex->flags &= ~KEX_INITIAL; sshbuf_reset(kex->peer); - kex->flags &= ~KEX_INIT_SENT; + kex->flags &= ~(KEX_INIT_SENT|KEX_INIT_RECVD); return 0; } @@ -623,6 +623,11 @@ kex_input_kexinit(int type, uint32_t seq, struct ssh *ssh) } free(kex->name); kex->name = NULL; + if ((kex->flags & KEX_INIT_RECVD) != 0) { + ssh_packet_disconnect(ssh, + "multiple KEXINIT received from peer"); + } + kex->flags |= KEX_INIT_RECVD; ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_protocol_error); ptr = sshpkt_ptr(ssh, &dlen); if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) diff --git a/usr.bin/ssh/kex.h b/usr.bin/ssh/kex.h index ccc6538a94a..da0356c9f7a 100644 --- a/usr.bin/ssh/kex.h +++ b/usr.bin/ssh/kex.h @@ -1,4 +1,4 @@ -/* $OpenBSD: kex.h,v 1.129 2026/03/05 05:40:36 djm Exp $ */ +/* $OpenBSD: kex.h,v 1.130 2026/05/31 04:44:38 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -108,6 +108,7 @@ enum kex_exchange { #define KEX_HAS_PING 0x0020 #define KEX_HAS_EXT_INFO_IN_AUTH 0x0040 #define KEX_HAS_NEWAGENT 0x0080 /* only set in client */ +#define KEX_INIT_RECVD 0x0100 /* kex->pq */ #define KEX_NOT_PQ 0 diff --git a/usr.bin/ssh/packet.c b/usr.bin/ssh/packet.c index 8aec8fd9736..29e6b71f438 100644 --- a/usr.bin/ssh/packet.c +++ b/usr.bin/ssh/packet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.c,v 1.337 2026/05/31 04:37:56 djm Exp $ */ +/* $OpenBSD: packet.c,v 1.338 2026/05/31 04:44:38 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1929,6 +1929,13 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, uint32_t *seqnr_p) DBG(debug("Received SSH2_MSG_PONG len %zu", len)); break; default: + if (ssh->kex != NULL && + (ssh->kex->flags & KEX_INIT_RECVD) != 0 && + !ssh_packet_type_is_kex(*typep)) { + error("non-transport message %u received " + "from peer during key exchange", *typep); + return SSH_ERR_PROTOCOL_ERROR; + } return 0; } }