From d1b196e9d1e575fe1b0c64f6041d173f19a7d1ed Mon Sep 17 00:00:00 2001 From: omni <omni+alpine@hack.org> Date: Tue, 19 Dec 2023 13:00:07 +0000 Subject: [PATCH] main/dropbear: add mitigations for CVE-2023-48795 --- main/dropbear/APKBUILD | 6 +- main/dropbear/Implement-Strict-KEX-mode.patch | 227 ++++++++++++++++++ 2 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 main/dropbear/Implement-Strict-KEX-mode.patch diff --git a/main/dropbear/APKBUILD b/main/dropbear/APKBUILD index 92a588699e0d..41091cecbe35 100644 --- a/main/dropbear/APKBUILD +++ b/main/dropbear/APKBUILD @@ -3,7 +3,7 @@ # Maintainer: Natanael Copa <ncopa@alpinelinux.org> pkgname=dropbear pkgver=2022.83 -pkgrel=0 +pkgrel=1 pkgdesc="small SSH 2 client/server designed for small memory environments" url="https://matt.ucc.asn.au/dropbear/dropbear.html" arch="all" @@ -21,9 +21,12 @@ source="https://matt.ucc.asn.au/dropbear/releases/dropbear-$pkgver.tar.bz2 dropbear.confd dropbear-options_sftp-server_path.patch dropbear-fix-utmp.patch + Implement-Strict-KEX-mode.patch " # secfixes: +# 2022.83-r1: +# - CVE-2023-48795 # 2020.79-r0: # - CVE-2018-20685 # 2018.76-r2: @@ -92,4 +95,5 @@ c63afa615d64b0c8c5e739c758eb8ae277ecc36a4223b766bf562702de69910904cbc3ea98d22989 83f2c1eaf7687917a4b2bae7d599d4378c4bd64f9126ba42fc5d235f2b3c9a474d1b3168d70ed64bb4101cc251d30bc9ae20604da9b5d819fcd635ee4d0ebb0f dropbear.confd df3fa2c64665b669257ec511afa2e04107eb6b0a2a4238ad9b33db3d322b90854b00506e14a09b648fe2d716dc6c140212cc1739f7cd03088f9b7b9781aaa499 dropbear-options_sftp-server_path.patch e143b8b2083c96fdf425fbe179aa43892e44b95734686a57ae5d5612778f1bd7e78a725d8413c1701d37dcf1b24986b1faa7365eb039789e2204320272fed7a3 dropbear-fix-utmp.patch +d747d4b083255634962ee0d42454093564930555b5f8bff1fff64e2e5e399c47d3b53ddb54356bb3ad2cc7d8b7f017193dcd889ff49021b3d43d3f38b5b0d616 Implement-Strict-KEX-mode.patch " diff --git a/main/dropbear/Implement-Strict-KEX-mode.patch b/main/dropbear/Implement-Strict-KEX-mode.patch new file mode 100644 index 000000000000..02c8a1ebe1bf --- /dev/null +++ b/main/dropbear/Implement-Strict-KEX-mode.patch @@ -0,0 +1,227 @@ +From the CHANGES file, Fixes: + + Add "Strict KEX" support. This mitigates a SSH protocol flaw which lets + a MITM attacker silently remove packets immediately after the + first key exchange. At present the flaw does not seem to reduce Dropbear's + security (the only packet affected would be a server-sig-algs extension, + which is used for compatibility not security). + For Dropbear, chacha20-poly1305 is the only affected cipher. + Both sides of the connection must support Strict KEX for it to be used. + + The protocol flaw is tracked as CVE-2023-48795, details + at https://terrapin-attack.com . Thanks to the researchers Fabian Bäumer, + Marcus Brinkmann, and Jörg Schwenk. Thanks to OpenSSH for specifying + strict KEX mode. + +diff --git a/cli-session.c b/cli-session.c +index 5981b247..d261c8f8 100644 +--- a/cli-session.c ++++ b/cli-session.c +@@ -46,6 +46,7 @@ static void cli_finished(void) ATTRIB_NORETURN; + static void recv_msg_service_accept(void); + static void cli_session_cleanup(void); + static void recv_msg_global_request_cli(void); ++static void cli_algos_initialise(void); + + struct clientsession cli_ses; /* GLOBAL */ + +@@ -117,6 +118,7 @@ void cli_session(int sock_in, int sock_out, struct dropbear_progress_connection + } + + chaninitialise(cli_chantypes); ++ cli_algos_initialise(); + + /* Set up cli_ses vars */ + cli_session_init(proxy_cmd_pid); +@@ -487,3 +489,12 @@ void cli_dropbear_log(int priority, const char* format, va_list param) { + fflush(stderr); + } + ++static void cli_algos_initialise(void) { ++ algo_type *algo; ++ for (algo = sshkex; algo->name; algo++) { ++ if (strcmp(algo->name, SSH_STRICT_KEX_S) == 0) { ++ algo->usable = 0; ++ } ++ } ++} ++ +diff --git a/common-algo.c b/common-algo.c +index 378f0ca8..f9d46ebb 100644 +--- a/common-algo.c ++++ b/common-algo.c +@@ -307,6 +307,12 @@ algo_type sshkex[] = { + /* Set unusable by svr_algos_initialise() */ + {SSH_EXT_INFO_C, 0, NULL, 1, NULL}, + #endif ++#endif ++#if DROPBEAR_CLIENT ++ {SSH_STRICT_KEX_C, 0, NULL, 1, NULL}, ++#endif ++#if DROPBEAR_SERVER ++ {SSH_STRICT_KEX_S, 0, NULL, 1, NULL}, + #endif + {NULL, 0, NULL, 0, NULL} + }; +diff --git a/common-kex.c b/common-kex.c +index ac884424..8e33b12a 100644 +--- a/common-kex.c ++++ b/common-kex.c +@@ -183,6 +183,10 @@ void send_msg_newkeys() { + gen_new_keys(); + switch_keys(); + ++ if (ses.kexstate.strict_kex) { ++ ses.transseq = 0; ++ } ++ + TRACE(("leave send_msg_newkeys")) + } + +@@ -193,7 +197,11 @@ void recv_msg_newkeys() { + + ses.kexstate.recvnewkeys = 1; + switch_keys(); +- ++ ++ if (ses.kexstate.strict_kex) { ++ ses.recvseq = 0; ++ } ++ + TRACE(("leave recv_msg_newkeys")) + } + +@@ -550,6 +558,10 @@ void recv_msg_kexinit() { + + ses.kexstate.recvkexinit = 1; + ++ if (ses.kexstate.strict_kex && !ses.kexstate.donefirstkex && ses.recvseq != 1) { ++ dropbear_exit("First packet wasn't kexinit"); ++ } ++ + TRACE(("leave recv_msg_kexinit")) + } + +@@ -859,6 +871,18 @@ static void read_kex_algos() { + } + #endif + ++ if (!ses.kexstate.donefirstkex) { ++ const char* strict_name; ++ if (IS_DROPBEAR_CLIENT) { ++ strict_name = SSH_STRICT_KEX_S; ++ } else { ++ strict_name = SSH_STRICT_KEX_C; ++ } ++ if (buf_has_algo(ses.payload, strict_name) == DROPBEAR_SUCCESS) { ++ ses.kexstate.strict_kex = 1; ++ } ++ } ++ + algo = buf_match_algo(ses.payload, sshkex, kexguess2, &goodguess); + allgood &= goodguess; + if (algo == NULL || algo->data == NULL) { +diff --git a/kex.h b/kex.h +index 77cf21a3..7fcc3c25 100644 +--- a/kex.h ++++ b/kex.h +@@ -83,6 +83,9 @@ struct KEXState { + + unsigned our_first_follows_matches : 1; + ++ /* Boolean indicating that strict kex mode is in use */ ++ unsigned int strict_kex; ++ + time_t lastkextime; /* time of the last kex */ + unsigned int datatrans; /* data transmitted since last kex */ + unsigned int datarecv; /* data received since last kex */ +diff --git a/process-packet.c b/process-packet.c +index 94541602..133a152d 100644 +--- a/process-packet.c ++++ b/process-packet.c +@@ -44,6 +44,7 @@ void process_packet() { + + unsigned char type; + unsigned int i; ++ unsigned int first_strict_kex = ses.kexstate.strict_kex && !ses.kexstate.donefirstkex; + time_t now; + + TRACE2(("enter process_packet")) +@@ -54,22 +55,24 @@ void process_packet() { + now = monotonic_now(); + ses.last_packet_time_keepalive_recv = now; + +- /* These packets we can receive at any time */ +- switch(type) { + +- case SSH_MSG_IGNORE: +- goto out; +- case SSH_MSG_DEBUG: +- goto out; ++ if (type == SSH_MSG_DISCONNECT) { ++ /* Allowed at any time */ ++ dropbear_close("Disconnect received"); ++ } + +- case SSH_MSG_UNIMPLEMENTED: +- /* debugging XXX */ +- TRACE(("SSH_MSG_UNIMPLEMENTED")) +- goto out; +- +- case SSH_MSG_DISCONNECT: +- /* TODO cleanup? */ +- dropbear_close("Disconnect received"); ++ /* These packets may be received at any time, ++ except during first kex with strict kex */ ++ if (!first_strict_kex) { ++ switch(type) { ++ case SSH_MSG_IGNORE: ++ goto out; ++ case SSH_MSG_DEBUG: ++ goto out; ++ case SSH_MSG_UNIMPLEMENTED: ++ TRACE(("SSH_MSG_UNIMPLEMENTED")) ++ goto out; ++ } + } + + /* Ignore these packet types so that keepalives don't interfere with +@@ -98,7 +101,8 @@ void process_packet() { + if (type >= 1 && type <= 49 + && type != SSH_MSG_SERVICE_REQUEST + && type != SSH_MSG_SERVICE_ACCEPT +- && type != SSH_MSG_KEXINIT) ++ && type != SSH_MSG_KEXINIT ++ && !first_strict_kex) + { + TRACE(("unknown allowed packet during kexinit")) + recv_unimplemented(); +diff --git a/ssh.h b/ssh.h +index 1b4fec65..ef3efdca 100644 +--- a/ssh.h ++++ b/ssh.h +@@ -100,6 +100,10 @@ + #define SSH_EXT_INFO_C "ext-info-c" + #define SSH_SERVER_SIG_ALGS "server-sig-algs" + ++/* OpenSSH strict KEX feature */ ++#define SSH_STRICT_KEX_S "kex-strict-s-v00@openssh.com" ++#define SSH_STRICT_KEX_C "kex-strict-c-v00@openssh.com" ++ + /* service types */ + #define SSH_SERVICE_USERAUTH "ssh-userauth" + #define SSH_SERVICE_USERAUTH_LEN 12 +diff --git a/svr-session.c b/svr-session.c +index 769f0731..a538e2c5 100644 +--- a/svr-session.c ++++ b/svr-session.c +@@ -370,6 +370,9 @@ static void svr_algos_initialise(void) { + algo->usable = 0; + } + #endif ++ if (strcmp(algo->name, SSH_STRICT_KEX_C) == 0) { ++ algo->usable = 0; ++ } + } + } + -- GitLab