From 4353fdc43ef646c43a8dda7025cc1a898caf1482 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Thu, 5 Nov 2026 08:18:18 +1100 Subject: [PATCH] avoid password authn bypass This bypass affects some configurations and runtime configurations. We do not consider the root cause to be within OpenSSH but we are well equipped to avoid it. --- auth-passwd.c | 17 +++++++++++++---- openbsd-compat/port-uw.c | 16 ++++++++-------- openbsd-compat/xcrypt.c | 18 +++++++++++++----- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/auth-passwd.c b/auth-passwd.c index 37dba168c6da..5406e2d55a8a 100644 --- a/auth-passwd.c +++ b/auth-passwd.c @@ -50,6 +50,7 @@ #include "ssherr.h" #include "log.h" #include "misc.h" +#include "xmalloc.h" #include "servconf.h" #include "sshkey.h" #include "hostfile.h" @@ -67,6 +68,7 @@ extern login_cap_t *lc; #define DAY (24L * 60 * 60) /* 1 day in seconds */ #define TWO_WEEKS (2L * 7 * DAY) /* 2 weeks in seconds */ +#define MIN_PASSWORD_HASH_LEN 4 #define MAX_PASSWORD_LEN 1024 /* @@ -198,16 +200,20 @@ sys_auth_passwd(struct ssh *ssh, const char *password) Authctxt *authctxt = ssh->authctxt; struct passwd *pw = authctxt->pw; char *encrypted_password, *salt = NULL; + int ret; /* Just use the supplied fake password if authctxt is invalid */ - char *pw_password = authctxt->valid ? shadow_pw(pw) : pw->pw_passwd; + char *pw_password = authctxt->valid ? + shadow_pw(pw) : xstrdup(pw->pw_passwd); if (pw_password == NULL) return 0; /* Check for users with no password. */ - if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0) - return (1); + if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0) { + free(pw_password); + return 1; + } /* * Encrypt the candidate password using the proper salt, or pass a @@ -221,7 +227,10 @@ sys_auth_passwd(struct ssh *ssh, const char *password) * Authentication is accepted if the encrypted passwords * are identical. */ - return encrypted_password != NULL && + ret = encrypted_password != NULL && + strlen(pw_password) >= MIN_PASSWORD_HASH_LEN && strcmp(encrypted_password, pw_password) == 0; + freezero(pw_password, strlen(pw_password)); + return ret; } #endif diff --git a/openbsd-compat/port-uw.c b/openbsd-compat/port-uw.c index 074f80c8d3d5..5c50ffa0fb87 100644 --- a/openbsd-compat/port-uw.c +++ b/openbsd-compat/port-uw.c @@ -58,14 +58,17 @@ sys_auth_passwd(struct ssh *ssh, const char *password) int result; /* Just use the supplied fake password if authctxt is invalid */ - char *pw_password = authctxt->valid ? shadow_pw(pw) : pw->pw_passwd; + char *pw_password = authctxt->valid ? + shadow_pw(pw) : xstrdup(pw->pw_passwd); if (pw_password == NULL) return 0; /* Check for users with no password. */ - if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0) - return (1); + if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0) { + free(pw_password); + return 1; + } /* Encrypt the candidate password using the proper salt. */ salt = (pw_password[0] && pw_password[1]) ? pw_password : "xx"; @@ -83,11 +86,8 @@ sys_auth_passwd(struct ssh *ssh, const char *password) #endif /* UNIXWARE_LONG_PASSWORDS */ result = (strcmp(xcrypt(password, salt), pw_password) == 0); -#ifdef USE_LIBIAF - if (authctxt->valid) - free(pw_password); -#endif - return(result); + freezero(pw_password, strlen(pw_password)); + return result; } #ifdef UNIXWARE_LONG_PASSWORDS diff --git a/openbsd-compat/xcrypt.c b/openbsd-compat/xcrypt.c index 4e0d0d64414a..80b13a5c4b67 100644 --- a/openbsd-compat/xcrypt.c +++ b/openbsd-compat/xcrypt.c @@ -25,6 +25,8 @@ #include "includes.h" #include +#include +#include #include #include #include @@ -59,6 +61,8 @@ # define crypt DES_crypt # endif +#include "xmalloc.h" + #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) /* @@ -71,7 +75,7 @@ static const char * pick_salt(void) { struct passwd *pw; - char *passwd, *p; + char *passwd = NULL, *p; size_t typelen; static char salt[32]; @@ -80,6 +84,8 @@ pick_salt(void) strlcpy(salt, "xx", sizeof(salt)); setpwent(); while ((pw = getpwent()) != NULL) { + if (passwd != NULL) + freezero(passwd, strlen(passwd)); if ((passwd = shadow_pw(pw)) == NULL) continue; if (passwd[0] == '$' && (p = strrchr(passwd+1, '$')) != NULL) { @@ -97,6 +103,8 @@ pick_salt(void) } } out: + if (passwd != NULL) + freezero(passwd, strlen(passwd)); endpwent(); return salt; } @@ -129,9 +137,8 @@ xcrypt(const char *password, const char *salt) /* * Handle shadowed password systems in a cleaner way for portable - * version. + * version. Caller must free returned value. */ - char * shadow_pw(struct passwd *pw) { @@ -145,7 +152,8 @@ shadow_pw(struct passwd *pw) # endif #ifdef USE_LIBIAF - return(get_iaf_password(pw)); + pw_password = get_iaf_password(pw); + return pw_password == NULL ? NULL : xstrdup(pw_password); #endif # if defined(HAVE_GETPWANAM) && !defined(DISABLE_SHADOW) @@ -159,5 +167,5 @@ shadow_pw(struct passwd *pw) pw_password = spw->ufld.fd_encrypt; # endif - return pw_password; + return pw_password == NULL ? NULL : xstrdup(pw_password); }