From 83045b0443e47ba57f2235cdfa13a72c84de1e55 Mon Sep 17 00:00:00 2001 From: Vladimir Dubrovin <3proxy@3proxy.ru> Date: Fri, 30 Oct 2026 13:47:12 +0300 Subject: [PATCH] radius: the reply hashed with the secret, and taken only from the server asked The reply digest copied the shared secret right after the received bytes, so a reply of 4100 bytes with a secret of 17 or more characters wrote up to 47 bytes of it past the reply buffer on the stack, before the reply was authenticated. The digest is now taken over the reply and the secret in place, with nothing written past the reply, and it fails closed when the hash cannot be made. A reply is also taken only from the address and port of the server the request went to, and only when its identifier and length field match the request, all before any digest work; the reply's sender was never checked before. --- src/authradius.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/authradius.c b/src/authradius.c index e3c30b0..293006c 100644 --- a/src/authradius.c +++ b/src/authradius.c @@ -194,12 +194,20 @@ static int calc_replydigest(char *packet, char *original, const char *secret, in int secretlen; uint8_t calc_digest[AUTH_VECTOR_LEN]; uint8_t calc_vector[AUTH_VECTOR_LEN]; + unsigned int dlen = AUTH_VECTOR_LEN; + mdh_ctx *ctx; memcpy(calc_vector, packet + 4, AUTH_VECTOR_LEN); memcpy(packet + 4, original, AUTH_VECTOR_LEN); secretlen = strlen(secret); - memcpy(packet + len, secret, secretlen); - md5_calc(calc_digest, (u_char *)packet, len + secretlen); + /* hash the reply, then the secret: nothing is written past the reply */ + if(!(ctx = mdh_init(MDH_MD5, 16))) return 2; + if(!mdh_update(ctx, packet, len) || !mdh_update(ctx, secret, secretlen) || + !mdh_final(ctx, calc_digest, &dlen)) { + mdh_free(ctx); + return 2; + } + mdh_free(ctx); /* * Return 0 if OK, 2 if not OK. @@ -294,6 +302,7 @@ int radsend(struct clientparam * param, int auth, int stop){ int total_length; int len; PROXYSOCKADDRTYPE saremote; + PROXYSOCKADDRTYPE safrom; char vector[AUTH_VECTOR_LEN]; radius_packet_t packet, rpacket; int data_len; @@ -550,13 +559,23 @@ int radsend(struct clientparam * param, int auth, int stop){ continue; } - data_len = sockrecvfrom(NULL, remsock, (struct sockaddr *)&saremote, (unsigned char *)&rpacket, + data_len = sockrecvfrom(NULL, remsock, (struct sockaddr *)&safrom, (unsigned char *)&rpacket, sizeof(packet)-16, param->srv->config->timeouts[SINGLEBYTE_L]*1000); if (data_len < 20) { continue; } + /* the reply must come from the server we asked */ + if(*SAFAMILY(&safrom) != *SAFAMILY(&saremote) || + memcmp(SAADDR(&safrom), SAADDR(&saremote), SAADDRLEN(&saremote)) || + *SAPORT(&safrom) != *SAPORT(&saremote)) { + continue; + } + /* and answer this request, and be of its own length */ + if(data_len != ntohs(rpacket.length) || rpacket.id != packet.id) { + continue; + } if( auth && rpacket.code != PW_AUTHENTICATION_ACK && rpacket.code != PW_AUTHENTICATION_REJECT ){