From 120312ff70746c47e6e2e649b9f8877b555d40c5 Mon Sep 17 00:00:00 2001 From: wk333 <13474090681@163.com> Date: Tue, 16 Jul 2024 10:23:54 +0800 Subject: [PATCH] Fix CVE-2024-3596 (cherry picked from commit 787bff134fff876532bb8344e0ded6570a2aa0c0) --- CVE-2024-3596.patch | 788 ++++++++++++++++++++++++++++++++++++++++++++ freeradius.spec | 6 +- 2 files changed, 793 insertions(+), 1 deletion(-) create mode 100644 CVE-2024-3596.patch diff --git a/CVE-2024-3596.patch b/CVE-2024-3596.patch new file mode 100644 index 0000000..9b2b865 --- /dev/null +++ b/CVE-2024-3596.patch @@ -0,0 +1,788 @@ +Origin: https://build.opensuse.org/projects/SUSE:SLE-15-SP4:Update/packages/freeradius-server/files/CVE-2024-3596.patch?expand=1 +Index: freeradius-server-3.0.25/raddb/radiusd.conf.in +=================================================================== +--- freeradius-server-3.0.25.orig/raddb/radiusd.conf.in ++++ freeradius-server-3.0.25/raddb/radiusd.conf.in +@@ -593,6 +593,64 @@ security { + # + status_server = yes + ++ # ++ # Global configuration for requiring Message-Authenticator ++ # in all Access-* packets sent over UDP or TCP. This flag ++ # is ignored for TLS. ++ ++ # ++ # This flag sets the global default for all clients and home ++ # servers. It can be over-ridden in an individual client or ++ # home server definition by adding a flag to that section: ++ # ++ # require_message_authenticator = no ++ # ++ # If the server produces error message which says "Packet ++ # does not contain required Message-Authenticator attribute", ++ # then this configuration item has to be updated. ++ # ++ # WARNING: This item should always be left as "yes", ++ # otherwise it is possible for MITM attackers to create fake ++ # Access-Accept packets to the NAS! ++ # ++ require_message_authenticator = yes ++ ++ # ++ # Global configuration for requiring Message-Authenticator ++ # Access-Request packets from a NAS, but only if those ++ # packets also contain Proxy-State. This flag only applies ++ # to packets sent over UDP or TCP. This flag is ignored for ++ # TLS. ++ # ++ # This flag sets the global default for all clients. It can ++ # be over-ridden in an individual client definition by adding ++ # a flag to that section: ++ # ++ # limit_proxy_state = no ++ # ++ # If "require_message_authenticator" is set to "yes", this ++ # configuration item is ignored. ++ # ++ # If "require_message_authenticator" is set to "no", this ++ # configuration item is checked. ++ # ++ # This configuration item should ALWAYS be set to "yes". ++ # ++ # The only reason to set it to "no" is when the client is a ++ # proxy, AND the proxy does not send Message-Authenticator in ++ # Access-Request packets. Even then, the best approach to ++ # fix the issue is to (1) update the proxy to send ++ # Message-Authenticator, and if that can't be done, then (2) ++ # set this flag to "no", but ONLY on a per-client basis. ++ # ++ # WARNING: Setting both this flag and the ++ # "require_message_authenticator" flag to "no" will allow ++ # MITM attackers to create fake Access-Accept packets to the ++ # NAS! At least one of them MUST be set to "yes" for the ++ # system to have any protection against the attack. ++ # ++ limit_proxy_state = yes ++ + @openssl_version_check_config@ + } + +Index: freeradius-server-3.0.25/src/include/radiusd.h +=================================================================== +--- freeradius-server-3.0.25.orig/src/include/radiusd.h ++++ freeradius-server-3.0.25/src/include/radiusd.h +@@ -174,6 +174,9 @@ typedef struct main_config { + + bool exiting; //!< are we exiting? + ++ bool require_ma; //!< global configuration for all clients and home servers ++ ++ bool limit_proxy_state; //!< global configuration for all clients + + #ifdef ENABLE_OPENSSL_VERSION_CHECK + char const *allow_vulnerable_openssl; //!< The CVE number of the last security issue acknowledged. +Index: freeradius-server-3.0.25/src/main/mainconfig.c +=================================================================== +--- freeradius-server-3.0.25.orig/src/main/mainconfig.c ++++ freeradius-server-3.0.25/src/main/mainconfig.c +@@ -160,6 +160,8 @@ static const CONF_PARSER security_config + { "max_attributes", FR_CONF_POINTER(PW_TYPE_INTEGER, &fr_max_attributes), STRINGIFY(0) }, + { "reject_delay", FR_CONF_POINTER(PW_TYPE_TIMEVAL, &main_config.reject_delay), STRINGIFY(0) }, + { "status_server", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.status_server), "no"}, ++ { "require_message_authenticator", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.require_ma), "yes"}, ++ { "limit_proxy_state", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.limit_proxy_state), "yes"}, + #ifdef ENABLE_OPENSSL_VERSION_CHECK + { "allow_vulnerable_openssl", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.allow_vulnerable_openssl), "no"}, + #endif +Index: freeradius-server-3.0.25/src/include/clients.h +=================================================================== +--- freeradius-server-3.0.25.orig/src/include/clients.h ++++ freeradius-server-3.0.25/src/include/clients.h +@@ -43,7 +43,9 @@ typedef struct radclient { + + char const *secret; //!< Secret PSK. + +- bool message_authenticator; //!< Require RADIUS message authenticator in requests. ++ bool require_ma; //!< Require RADIUS message authenticator in requests. ++ ++ bool limit_proxy_state; //!< Limit Proxy-State in requests + + char const *nas_type; //!< Type of client (arbitrary). + +Index: freeradius-server-3.0.25/src/main/client.c +=================================================================== +--- freeradius-server-3.0.25.orig/src/main/client.c ++++ freeradius-server-3.0.25/src/main/client.c +@@ -327,7 +327,8 @@ check_list: + (old->coa_home_server == client->coa_home_server) && + (old->coa_home_pool == client->coa_home_pool) && + #endif +- (old->message_authenticator == client->message_authenticator)) { ++ (old->require_ma == client->require_ma) && ++ (old->limit_proxy_state == client->limit_proxy_state)) { + WARN("Ignoring duplicate client %s", client->longname); + client_free(client); + return true; +@@ -511,7 +512,8 @@ static const CONF_PARSER client_config[] + + { "src_ipaddr", FR_CONF_POINTER(PW_TYPE_STRING, &cl_srcipaddr), NULL }, + +- { "require_message_authenticator", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, RADCLIENT, message_authenticator), "no" }, ++ { "require_message_authenticator", FR_CONF_OFFSET(PW_TYPE_BOOLEAN | PW_TYPE_IGNORE_DEFAULT, RADCLIENT, require_ma), NULL }, ++ { "limit_proxy_state", FR_CONF_OFFSET(PW_TYPE_BOOLEAN | PW_TYPE_IGNORE_DEFAULT, RADCLIENT, limit_proxy_state), NULL }, + + { "secret", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, RADCLIENT, secret), NULL }, + { "shortname", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, shortname), NULL }, +@@ -719,7 +721,7 @@ static const CONF_PARSER dynamic_config[ + { "FreeRADIUS-Client-Src-IP-Address", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, RADCLIENT, src_ipaddr), NULL }, + { "FreeRADIUS-Client-Src-IPv6-Address", FR_CONF_OFFSET(PW_TYPE_IPV6_ADDR, RADCLIENT, src_ipaddr), NULL }, + +- { "FreeRADIUS-Client-Require-MA", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, RADCLIENT, message_authenticator), NULL }, ++ { "FreeRADIUS-Client-Require-MA", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, RADCLIENT, require_ma), NULL }, + + { "FreeRADIUS-Client-Secret", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, secret), "" }, + { "FreeRADIUS-Client-Shortname", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, shortname), "" }, +@@ -901,6 +903,15 @@ RADCLIENT *client_afrom_cs(TALLOC_CTX *c + c = talloc_zero(ctx, RADCLIENT); + c->cs = cs; + ++ /* ++ * Set the "require message authenticator" and "limit ++ * proxy state" flags from the global default. If the ++ * configuration item exists, AND is set, it will ++ * over-ride the flag. ++ */ ++ c->require_ma = main_config.require_ma; ++ c->limit_proxy_state = main_config.limit_proxy_state; ++ + memset(&cl_ipaddr, 0, sizeof(cl_ipaddr)); + cl_netmask = 255; + +@@ -1214,7 +1225,7 @@ RADCLIENT *client_afrom_query(TALLOC_CTX + if (shortname) c->shortname = talloc_typed_strdup(c, shortname); + if (type) c->nas_type = talloc_typed_strdup(c, type); + if (server) c->server = talloc_typed_strdup(c, server); +- c->message_authenticator = require_ma; ++ c->require_ma = require_ma; + + return c; + } +Index: freeradius-server-3.0.25/src/main/listen.c +=================================================================== +--- freeradius-server-3.0.25.orig/src/main/listen.c ++++ freeradius-server-3.0.25/src/main/listen.c +@@ -1757,7 +1757,7 @@ static int auth_socket_recv(rad_listen_t + * Now that we've sanity checked everything, receive the + * packet. + */ +- packet = rad_recv(ctx, listener->fd, client->message_authenticator); ++ packet = rad_recv(ctx, listener->fd, client->require_ma | (((int) client->limit_proxy_state) << 2)); + if (!packet) { + FR_STATS_INC(auth, total_malformed_requests); + if (DEBUG_ENABLED) ERROR("Receive - %s", fr_strerror()); +@@ -2153,7 +2153,7 @@ static int coa_socket_recv(rad_listen_t + * Now that we've sanity checked everything, receive the + * packet. + */ +- packet = rad_recv(ctx, listener->fd, client->message_authenticator); ++ packet = rad_recv(ctx, listener->fd, client->require_ma); + if (!packet) { + FR_STATS_INC(coa, total_malformed_requests); + if (DEBUG_ENABLED) ERROR("Receive - %s", fr_strerror()); +Index: freeradius-server-3.0.25/src/include/conffile.h +=================================================================== +--- freeradius-server-3.0.25.orig/src/include/conffile.h ++++ freeradius-server-3.0.25/src/include/conffile.h +@@ -140,6 +140,7 @@ typedef struct timeval _timeval_t; + #define PW_TYPE_MULTI (1 << 18) //!< CONF_PAIR can have multiple copies. + #define PW_TYPE_NOT_EMPTY (1 << 19) //!< CONF_PAIR is required to have a non zero length value. + #define PW_TYPE_FILE_EXISTS ((1 << 20) | PW_TYPE_STRING) //!< File matching value must exist ++#define PW_TYPE_IGNORE_DEFAULT (1 << 21) //!< don't set from .dflt if the CONF_PAIR is missing + /* @} **/ + + #define FR_INTEGER_COND_CHECK(_name, _var, _cond, _new)\ +Index: freeradius-server-3.0.25/src/main/conffile.c +=================================================================== +--- freeradius-server-3.0.25.orig/src/main/conffile.c ++++ freeradius-server-3.0.25/src/main/conffile.c +@@ -1423,6 +1423,7 @@ int cf_item_parse(CONF_SECTION *cs, char + { + int rcode; + bool deprecated, required, attribute, secret, file_input, cant_be_empty, tmpl, multi, file_exists; ++ bool ignore_dflt; + char **q; + char const *value; + CONF_PAIR *cp = NULL; +@@ -1446,6 +1447,7 @@ int cf_item_parse(CONF_SECTION *cs, char + cant_be_empty = (type & PW_TYPE_NOT_EMPTY); + tmpl = (type & PW_TYPE_TMPL); + multi = (type & PW_TYPE_MULTI); ++ ignore_dflt = (type & PW_TYPE_IGNORE_DEFAULT); + + if (attribute) required = true; + if (required) cant_be_empty = true; /* May want to review this in the future... */ +@@ -1469,7 +1471,7 @@ int cf_item_parse(CONF_SECTION *cs, char + * section, use the default value. + */ + if (!cp) { +- if (deprecated) return 0; /* Don't set the default value */ ++ if (deprecated || ignore_dflt) return 0; /* Don't set the default value */ + + rcode = 1; + value = dflt; +Index: freeradius-server-3.0.25/raddb/clients.conf +=================================================================== +--- freeradius-server-3.0.25.orig/raddb/clients.conf ++++ freeradius-server-3.0.25/raddb/clients.conf +@@ -100,15 +100,30 @@ client localhost { + secret = testing123 + + # +- # Old-style clients do not send a Message-Authenticator +- # in an Access-Request. RFC 5080 suggests that all clients +- # SHOULD include it in an Access-Request. The configuration +- # item below allows the server to require it. If a client +- # is required to include a Message-Authenticator and it does +- # not, then the packet will be silently discarded. ++ # The global configuration "security.require_message_authenticator" ++ # flag sets the default for all clients. That default can be ++ # over-ridden here, by setting it to "no". ++ # ++ # This flag exists solely for legacy clients which do not send ++ # Message-Authenticator in all Access-Request packets. We do not ++ # recommend setting it to "no". ++ # ++ # allowed values: yes, no ++ # ++# require_message_authenticator = yes ++ ++ # ++ # The global configuration "security.limit_proxy_state" ++ # flag sets the default for all clients. That default can be ++ # over-ridden here, by setting it to "no". ++ # ++ # This flag exists solely for legacy clients which do not send ++ # Message-Authenticator in all Access-Request packets. We do not ++ # recommend setting it to "no". + # + # allowed values: yes, no +- require_message_authenticator = no ++ # ++# limit_proxy_state = yes + + # + # The short name is used as an alias for the fully qualified +Index: freeradius-server-3.0.25/src/include/libradius.h +=================================================================== +--- freeradius-server-3.0.25.orig/src/include/libradius.h ++++ freeradius-server-3.0.25/src/include/libradius.h +@@ -412,6 +412,7 @@ typedef struct radius_packet { + size_t partial; + int proto; + #endif ++ bool tls; //!< uses secure transport + } RADIUS_PACKET; + + typedef enum { +@@ -519,6 +520,11 @@ DICT_VENDOR *dict_vendorbyvalue(int vend + /* radius.c */ + int rad_send(RADIUS_PACKET *, RADIUS_PACKET const *, char const *secret); + bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason); ++/* ++ * 1 == require_ma ++ * 2 == msg_peek ++ * 3 == limit_proxy_state ++ */ + RADIUS_PACKET *rad_recv(TALLOC_CTX *ctx, int fd, int flags); + ssize_t rad_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, int *code); + void rad_recv_discard(int sockfd); +Index: freeradius-server-3.0.25/src/main/tls_listen.c +=================================================================== +--- freeradius-server-3.0.25.orig/src/main/tls_listen.c ++++ freeradius-server-3.0.25/src/main/tls_listen.c +@@ -592,6 +592,8 @@ read_application_data: + packet->vps = NULL; + PTHREAD_MUTEX_UNLOCK(&sock->mutex); + ++ packet->tls = true; ++ + if (!rad_packet_ok(packet, 0, NULL)) { + if (DEBUG_ENABLED) ERROR("Receive - %s", fr_strerror()); + DEBUG("(TLS) Closing TLS socket from client"); +@@ -1144,6 +1146,8 @@ int proxy_tls_recv(rad_listen_t *listene + memcpy(packet->data, data, packet->data_len); + memcpy(packet->vector, packet->data + 4, 16); + ++ packet->tls = true; ++ + /* + * FIXME: Client MIB updates? + */ +@@ -1179,7 +1183,6 @@ int proxy_tls_recv(rad_listen_t *listene + break; + #endif + #endif +- + default: + #ifdef WITH_COA_TUNNEL + bad_packet: +@@ -1230,6 +1233,7 @@ int proxy_tls_send(rad_listen_t *listene + * if there's no packet, encode it here. + */ + if (!request->proxy->data) { ++ request->reply->tls = true; + request->proxy_listener->proxy_encode(request->proxy_listener, + request); + } +@@ -1289,6 +1293,8 @@ int proxy_tls_send_reply(rad_listen_t *l + if ((listener->status != RAD_LISTEN_STATUS_INIT && + (listener->status != RAD_LISTEN_STATUS_KNOWN))) return 0; + ++ request->reply->tls = true; ++ + /* + * Pack the VPs + */ +Index: freeradius-server-3.0.25/src/lib/radius.c +=================================================================== +--- freeradius-server-3.0.25.orig/src/lib/radius.c ++++ freeradius-server-3.0.25/src/lib/radius.c +@@ -1797,6 +1797,7 @@ int rad_encode(RADIUS_PACKET *packet, RA + uint16_t total_length; + int len; + VALUE_PAIR const *reply; ++ bool seen_ma = false; + + /* + * A 4K packet, aligned on 64-bits. +@@ -1861,6 +1862,27 @@ int rad_encode(RADIUS_PACKET *packet, RA + */ + + /* ++ * Always add Message-Authenticator for replies to ++ * Access-Request packets. ++ * ++ * It must be the FIRST attribute in the packet. ++ */ ++ if (!packet->tls && ++ ((original && (original->code == PW_CODE_ACCESS_REQUEST)) || ++ (packet->code == PW_CODE_ACCESS_REQUEST))) { ++ seen_ma = true; ++ ++ packet->offset = RADIUS_HDR_LEN; ++ ++ ptr[0] = PW_MESSAGE_AUTHENTICATOR; ++ ptr[1] = 18; ++ memset(ptr + 2, 0, 16); ++ ++ ptr += 18; ++ total_length += 18; ++ } ++ ++ /* + * Loop over the reply attributes for the packet. + */ + reply = packet->vps; +@@ -1917,6 +1939,11 @@ int rad_encode(RADIUS_PACKET *packet, RA + * length and initial value. + */ + if (!reply->da->vendor && (reply->da->attr == PW_MESSAGE_AUTHENTICATOR)) { ++ // don't encode Message-Authenticator twice ++ if (seen_ma) { ++ reply = reply->next; ++ continue; ++ } + if (room < 18) break; + + /* +@@ -2408,6 +2435,8 @@ bool rad_packet_ok(RADIUS_PACKET *packet + radius_packet_t *hdr; + char host_ipaddr[128]; + bool require_ma = false; ++ bool limit_proxy_state = false; ++ bool seen_proxy_state = false; + bool seen_ma = false; + uint32_t num_attributes; + decode_fail_t failure = DECODE_FAIL_NONE; +@@ -2458,13 +2487,14 @@ bool rad_packet_ok(RADIUS_PACKET *packet + /* + * Message-Authenticator is required in Status-Server + * packets, otherwise they can be trivially forged. +- */ +- if (hdr->code == PW_CODE_STATUS_SERVER) require_ma = true; +- +- /* ++ * + * It's also required if the caller asks for it. ++ * ++ * We only limit Proxy-State if we're not requiring ++ * Message-Authenticator. + */ +- if (flags) require_ma = true; ++ require_ma = ((flags & 0x01) != 0) || (hdr->code == PW_CODE_STATUS_SERVER); ++ limit_proxy_state = ((flags & 0x04) != 0) & !require_ma; + + /* + * Repeat the length checks. This time, instead of +@@ -2627,6 +2657,10 @@ bool rad_packet_ok(RADIUS_PACKET *packet + non_eap = true; + break; + ++ case PW_PROXY_STATE: ++ seen_proxy_state = true; ++ break; ++ + case PW_MESSAGE_AUTHENTICATOR: + if (attr[1] != 2 + AUTH_VECTOR_LEN) { + FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: Message-Authenticator has invalid length %d", +@@ -2698,6 +2732,18 @@ bool rad_packet_ok(RADIUS_PACKET *packet + inet_ntop(packet->src_ipaddr.af, + &packet->src_ipaddr.ipaddr, + host_ipaddr, sizeof(host_ipaddr))); ++ failure = DECODE_FAIL_MA_MISSING; ++ goto finish; ++ } ++ ++ /* ++ * The client is a NAS which shouldn't send Proxy-State, but it did! ++ */ ++ if (limit_proxy_state && seen_proxy_state && !seen_ma) { ++ FR_DEBUG_STRERROR_PRINTF("Insecure packet from host %s: Packet does not contain required Message-Authenticator attribute, but still has one or more Proxy-State attributes", ++ inet_ntop(packet->src_ipaddr.af, ++ &packet->src_ipaddr.ipaddr, ++ host_ipaddr, sizeof(host_ipaddr))); + failure = DECODE_FAIL_MA_MISSING; + goto finish; + } +Index: freeradius-server-3.0.25/raddb/proxy.conf +=================================================================== +--- freeradius-server-3.0.25.orig/raddb/proxy.conf ++++ freeradius-server-3.0.25/raddb/proxy.conf +@@ -239,6 +239,20 @@ home_server localhost { + # + secret = testing123 + ++ # The global configuration "security.require_message_authenticator" ++ # flag sets the default for all home servers. That default can be ++ # over-ridden here, by setting it to "no". ++ # ++ # This flag exists solely for legacy home servers which do ++ # not send Message-Authenticator in all Access-Accept, ++ # Access-Reject, or Access-Challenge packets. We do not ++ # recommend setting it to "no". ++ # ++ # allowed values: yes, no ++ # ++ #require_message_authenticator = no ++ ++ + ############################################################ + # + # The rest of the configuration items listed here are optional, +Index: freeradius-server-3.0.25/src/include/realms.h +=================================================================== +--- freeradius-server-3.0.25.orig/src/include/realms.h ++++ freeradius-server-3.0.25/src/include/realms.h +@@ -66,6 +66,7 @@ typedef struct home_server { + + bool dual; //!< One of a pair of homeservers on consecutive ports. + bool dynamic; //!< is this a dynamically added home server? ++ bool require_ma; //!< for all replies to Access-Request and Status-Server + #ifdef WITH_COA_TUNNEL + bool recv_coa; //!< receive CoA packets, too + #endif +Index: freeradius-server-3.0.25/src/main/process.c +=================================================================== +--- freeradius-server-3.0.25.orig/src/main/process.c ++++ freeradius-server-3.0.25/src/main/process.c +@@ -2725,11 +2725,32 @@ int request_proxy_reply(RADIUS_PACKET *p + * ignore it. This does the MD5 calculations in the + * server core, but I guess we can fix that later. + */ +- if (!request->proxy_reply && +- (rad_verify(packet, request->proxy, +- request->home_server->secret) != 0)) { +- DEBUG("Ignoring spoofed proxy reply. Signature is invalid"); +- return 0; ++ if (!request->proxy_reply) { ++ decode_fail_t reason; ++ ++ /* ++ * If the home server configuration requires a Message-Authenticator, then set the flag, ++ * but only if the proxied packet is Access-Request or Status-Sercer. ++ * ++ * The realms.c file already clears require_ma for TLS connections. ++ */ ++ bool require_ma = request->home_server->require_ma && (request->proxy->code == PW_CODE_ACCESS_REQUEST); ++ ++ if (!request->home_server) { ++ proxy_reply_too_late(request); ++ return 0; ++ } ++ ++ if (!rad_packet_ok(packet, require_ma, &reason)) { ++ DEBUG("Ignoring invalid packet - %s", fr_strerror()); ++ return 0; ++ } ++ ++ if (rad_verify(packet, request->proxy, ++ request->home_server->secret) != 0) { ++ DEBUG("Ignoring spoofed proxy reply. Signature is invalid"); ++ return 0; ++ } + } + + /* +Index: freeradius-server-3.0.25/src/main/realms.c +=================================================================== +--- freeradius-server-3.0.25.orig/src/main/realms.c ++++ freeradius-server-3.0.25/src/main/realms.c +@@ -450,6 +450,7 @@ static CONF_PARSER home_server_recv_coa[ + #endif + + static CONF_PARSER home_server_config[] = { ++ { "require_message_authenticator", FR_CONF_OFFSET(PW_TYPE_BOOLEAN | PW_TYPE_IGNORE_DEFAULT, home_server_t, require_ma), NULL }, + { "ipaddr", FR_CONF_OFFSET(PW_TYPE_COMBO_IP_ADDR, home_server_t, ipaddr), NULL }, + { "ipv4addr", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, home_server_t, ipaddr), NULL }, + { "ipv6addr", FR_CONF_OFFSET(PW_TYPE_IPV6_ADDR, home_server_t, ipaddr), NULL }, +@@ -740,6 +741,7 @@ home_server_t *home_server_afrom_cs(TALL + home->cs = cs; + home->state = HOME_STATE_UNKNOWN; + home->proto = IPPROTO_UDP; ++ home->require_ma = main_config.require_ma; + + /* + * Parse the configuration into the home server +@@ -1074,6 +1076,11 @@ home_server_t *home_server_afrom_cs(TALL + * Parse the SSL client configuration. + */ + if (tls) { ++ /* ++ * We don't require this for TLS connections. ++ */ ++ home->require_ma = false; ++ + home->tls = tls_client_conf_parse(tls); + if (!home->tls) { + goto error; +Index: freeradius-server-3.0.25/man/man1/radclient.1 +=================================================================== +--- freeradius-server-3.0.25.orig/man/man1/radclient.1 ++++ freeradius-server-3.0.25/man/man1/radclient.1 +@@ -5,6 +5,7 @@ radclient - send packets to a RADIUS ser + .B radclient + .RB [ \-4 ] + .RB [ \-6 ] ++.RB [ \-b ] + .RB [ \-c + .IR count ] + .RB [ \-d +@@ -52,6 +53,13 @@ automatically encrypted before the packe + Use IPv4 (default) + .IP \-6 + Use IPv6 ++.IP \-b ++Enforce the Blast RADIUS checks. All replies to an Access-Request packet ++must contain a Message-Authenticator as the first attribute. ++ ++For compatibility with old servers, this flag is not set by default. ++However, radclient still checks for the Blast RADIUS signature, and ++discards packets which match the attack. + .IP \-c\ \fIcount\fP + Send each packet \fIcount\fP times. + .IP \-d\ \fIraddb_directory\fP +Index: freeradius-server-3.0.25/src/main/radclient.c +=================================================================== +--- freeradius-server-3.0.25.orig/src/main/radclient.c ++++ freeradius-server-3.0.25/src/main/radclient.c +@@ -54,6 +54,7 @@ static fr_ipaddr_t server_ipaddr; + static int resend_count = 1; + static bool done = true; + static bool print_filename = false; ++static bool blast_radius = false; + + static fr_ipaddr_t client_ipaddr; + static uint16_t client_port = 0; +@@ -89,6 +90,7 @@ static void NEVER_RETURNS usage(void) + fprintf(stderr, " One of auth, acct, status, coa, disconnect or auto.\n"); + fprintf(stderr, " -4 Use IPv4 address of server\n"); + fprintf(stderr, " -6 Use IPv6 address of server.\n"); ++ fprintf(stderr, " -b Mandate checks for Blast RADIUS issue (this is not set by default).\n"); + fprintf(stderr, " -c Send each packet 'count' times.\n"); + fprintf(stderr, " -d Set user dictionary directory (defaults to " RADDBDIR ").\n"); + fprintf(stderr, " -D Set main dictionary directory (defaults to " DICTDIR ").\n"); +@@ -1001,6 +1003,131 @@ static int send_one_packet(rc_request_t + } + + /* ++ * Do Blast RADIUS checks. ++ * ++ * The request is an Access-Request, and does NOT contain Proxy-State. ++ * ++ * The reply is a raw packet, and is NOT yet decoded. ++ */ ++static int blast_radius_check(rc_request_t *request, RADIUS_PACKET *reply) ++{ ++ uint8_t *attr, *end; ++ VALUE_PAIR *vp; ++ bool have_message_authenticator = false; ++ ++ /* ++ * We've received a raw packet. Nothing has (as of yet) checked ++ * anything in it other than the length, and that it's a ++ * well-formed RADIUS packet. ++ */ ++ switch (reply->data[0]) { ++ case PW_CODE_ACCESS_ACCEPT: ++ case PW_CODE_ACCESS_REJECT: ++ case PW_CODE_ACCESS_CHALLENGE: ++ if (reply->data[1] != request->packet->id) { ++ ERROR("Invalid reply ID %d to Access-Request ID %d", reply->data[1], request->packet->id); ++ return -1; ++ } ++ break; ++ ++ default: ++ ERROR("Invalid reply code %d to Access-Request", reply->data[0]); ++ return -1; ++ } ++ ++ /* ++ * If the reply has a Message-Authenticator, then it MIGHT be fine. ++ */ ++ attr = reply->data + 20; ++ end = reply->data + reply->data_len; ++ ++ /* ++ * It should be the first attribute, so we warn if it isn't there. ++ * ++ * But it's not a fatal error. ++ */ ++ if (blast_radius && (attr[0] != PW_MESSAGE_AUTHENTICATOR)) { ++ RDEBUG("WARNING The %s reply packet does not have Message-Authenticator as the first attribute. The packet may be vulnerable to Blast RADIUS attacks.", ++ fr_packet_codes[reply->data[0]]); ++ } ++ ++ /* ++ * Set up for Proxy-State checks. ++ * ++ * If we see a Proxy-State in the reply which we didn't send, then it's a Blast RADIUS attack. ++ */ ++ vp = fr_pair_find_by_num(request->packet->vps, PW_PROXY_STATE, 0, TAG_ANY); ++ ++ while (attr < end) { ++ /* ++ * Blast RADIUS work-arounds require that ++ * Message-Authenticator is the first attribute in the ++ * reply. Note that we don't check for it being the ++ * first attribute, but simply that it exists. ++ * ++ * That check is a balance between securing the reply ++ * packet from attacks, and not violating the RFCs which ++ * say that there is no order to attributes in the ++ * packet. ++ * ++ * However, no matter the status of the '-b' flag we ++ * still can check for the signature of the attack, and ++ * discard packets which are suspicious. This behavior ++ * protects radclient from the attack, without mandating ++ * new behavior on the server side. ++ * ++ * Note that we don't set the '-b' flag by default. ++ * radclient is intended for testing / debugging, and is ++ * not intended to be used as part of a secure login / ++ * user checking system. ++ */ ++ if (attr[0] == PW_MESSAGE_AUTHENTICATOR) { ++ have_message_authenticator = true; ++ goto next; ++ } ++ ++ /* ++ * If there are Proxy-State attributes in the reply, they must ++ * match EXACTLY the Proxy-State attributes in the request. ++ * ++ * Note that we don't care if there are more Proxy-States ++ * in the request than in the reply. The Blast RADIUS ++ * issue requires _adding_ Proxy-State attributes, and ++ * cannot work when the server _deletes_ Proxy-State ++ * attributes. ++ */ ++ if (attr[0] == PW_PROXY_STATE) { ++ if (!vp || (vp->length != (size_t) (attr[1] - 2)) || (memcmp(vp->vp_octets, attr + 2, vp->length) != 0)) { ++ ERROR("Invalid reply to Access-Request ID %d - Discarding packet due to Blast RADIUS attack being detected.", request->packet->id); ++ ERROR("We received a Proxy-State in the reply which we did not send, or which is different from what we sent."); ++ return -1; ++ } ++ ++ vp = fr_pair_find_by_num(vp->next, PW_PROXY_STATE, 0, TAG_ANY); ++ } ++ ++ next: ++ attr += attr[1]; ++ } ++ ++ /* ++ * If "-b" is set, then we require Message-Authenticator in the reply. ++ */ ++ if (blast_radius && !have_message_authenticator) { ++ ERROR("The %s reply packet does not contain Message-Authenticator - discarding packet due to Blast RADIUS checks.", ++ fr_packet_codes[reply->data[0]]); ++ return -1; ++ } ++ ++ /* ++ * The packet doesn't look like it's a Blast RADIUS attack. The ++ * caller will now verify the packet signature. ++ */ ++ return 0; ++} ++ ++ ++/* + * Receive one packet, maybe. + */ + static int recv_one_packet(int wait_time) +@@ -1052,6 +1179,20 @@ static int recv_one_packet(int wait_time + request = fr_packet2myptr(rc_request_t, packet, packet_p); + + /* ++ * We want radclient to be able to send any packet, including ++ * imperfect ones. However, we do NOT want to be vulnerable to ++ * the "Blast RADIUS" issue. Instead of adding command-line ++ * flags to enable/disable similar flags to what the server ++ * sends, we just do a few more smart checks to double-check ++ * things. ++ */ ++ if ((request->packet->code == PW_CODE_ACCESS_REQUEST) && ++ blast_radius_check(request, reply) < 0) { ++ rad_free(&reply); ++ return -1; ++ } ++ ++ /* + * Fails the signature validation: not a real reply. + * FIXME: Silently drop it and listen for another packet. + */ +@@ -1183,7 +1324,7 @@ int main(int argc, char **argv) + exit(1); + } + +- while ((c = getopt(argc, argv, "46c:d:D:f:Fhn:p:qr:sS:t:vx" ++ while ((c = getopt(argc, argv, "46bc:d:D:f:Fhn:p:qr:sS:t:vx" + #ifdef WITH_TCP + "P:" + #endif +@@ -1196,6 +1337,10 @@ int main(int argc, char **argv) + force_af = AF_INET6; + break; + ++ case 'b': ++ blast_radius = true; ++ break; ++ + case 'c': + if (!isdigit((int) *optarg)) usage(); + + diff --git a/freeradius.spec b/freeradius.spec index c22ed8f..7d8865f 100644 --- a/freeradius.spec +++ b/freeradius.spec @@ -4,7 +4,7 @@ Name: freeradius Version: 3.0.25 -Release: 2 +Release: 3 Summary: Remote Authentication Dial-In User Service License: GPLv2+ and LGPLv2+ @@ -18,6 +18,7 @@ patch0000: CVE-2022-41859-pre.patch patch0001: CVE-2022-41859.patch patch0002: CVE-2022-41860.patch patch0003: CVE-2022-41861.patch +patch0004: CVE-2024-3596.patch BuildRequires: autoconf gdbm-devel openssl openssl-devel pam-devel zlib-devel net-snmp-devel BuildRequires: net-snmp-utils readline-devel libpcap-devel systemd-units libtalloc-devel @@ -493,6 +494,9 @@ exit 0 %attr(640,root,radiusd) %config(noreplace) /etc/raddb/mods-available/ldap %changelog +* Tue Jul 16 2024 wangkai <13474090681@163.com> - 3.0.25-3 +- Fix CVE-2024-3596 + * Wed Dec 21 2022 jiangpeng - 3.0.25-2 - Fix CVE-2022-41859 and CVE-2022-41860 and CVE-2022-41861 -- Gitee