From a75b488aafd38670c356effd2bddcd3395d99be2 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 | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/authradius.c b/src/authradius.c index 1234596..5d28ba4 100644 --- a/src/authradius.c +++ b/src/authradius.c @@ -198,12 +198,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. @@ -298,6 +306,7 @@ int radsend(struct clientparam * param, int auth, int stop){ int total_length; int len; PROXYSOCKADDRTYPE saremote; + PROXYSOCKADDRTYPE safrom; struct pollfd fds[1]; char vector[AUTH_VECTOR_LEN]; radius_packet_t packet, rpacket; @@ -568,15 +577,25 @@ int radsend(struct clientparam * param, int auth, int stop){ continue; } - salen = sizeof(saremote); - + salen = sizeof(safrom); + data_len = so._recvfrom(so.state, remsock, (char *)&rpacket, sizeof(packet)-16, - 0, (struct sockaddr *)&saremote, &salen); + 0, (struct sockaddr *)&safrom, &salen); 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 ){