]> git.ipfire.org Git - thirdparty/openssh-portable.git/commitdiff
Determine appropriate salt for invalid users.
authorDarren Tucker <dtucker@zip.com.au>
Fri, 15 Jul 2016 03:32:45 +0000 (13:32 +1000)
committerDarren Tucker <dtucker@zip.com.au>
Fri, 15 Jul 2016 03:45:42 +0000 (13:45 +1000)
When sshd is processing a non-PAM login for a non-existent user it uses
the string from the fakepw structure as the salt for crypt(3)ing the
password supplied by the client.  That string has a Blowfish prefix, so on
systems that don't understand that crypt will fail fast due to an invalid
salt, and even on those that do it may have significantly different timing
from the hash methods used for real accounts (eg sha512).  This allows
user enumeration by, eg, sending large password strings.  This was noted
by EddieEzra.Harari at verint.com (CVE-2016-6210).

To mitigate, use the same hash algorithm that root uses for hashing
passwords for users that do not exist on the system.  ok djm@

auth-passwd.c
openbsd-compat/xcrypt.c

index 63ccf3cabe7d766b310c5b0f9b57433820a2d050..530b5d4f7122963c99dd8e6b369adc8e7c8b5353 100644 (file)
@@ -193,7 +193,7 @@ int
 sys_auth_passwd(Authctxt *authctxt, const char *password)
 {
        struct passwd *pw = authctxt->pw;
-       char *encrypted_password;
+       char *encrypted_password, *salt = NULL;
 
        /* Just use the supplied fake password if authctxt is invalid */
        char *pw_password = authctxt->valid ? shadow_pw(pw) : pw->pw_passwd;
@@ -202,9 +202,13 @@ sys_auth_passwd(Authctxt *authctxt, const char *password)
        if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0)
                return (1);
 
-       /* Encrypt the candidate password using the proper salt. */
-       encrypted_password = xcrypt(password,
-           (pw_password[0] && pw_password[1]) ? pw_password : "xx");
+       /*
+        * Encrypt the candidate password using the proper salt, or pass a
+        * NULL and let xcrypt pick one.
+        */
+       if (authctxt->valid && pw_password[0] && pw_password[1])
+               salt = pw_password;
+       encrypted_password = xcrypt(password, salt);
 
        /*
         * Authentication is accepted if the encrypted passwords
index 8577cbd8a6325606462276ab4a84d7f37b2a173a..8913bb81a5a2bd4684a7fdcff1e0691536401f20 100644 (file)
@@ -25,6 +25,7 @@
 #include "includes.h"
 
 #include <sys/types.h>
+#include <string.h>
 #include <unistd.h>
 #include <pwd.h>
 
 #  define crypt DES_crypt
 # endif
 
+/*
+ * Pick an appropriate password encryption type and salt for the running
+ * system.
+ */
+static const char *
+pick_salt(void)
+{
+       struct passwd *pw;
+       char *passwd, *p;
+       size_t typelen;
+       static char salt[32];
+
+       if (salt[0] != '\0')
+               return salt;
+       strlcpy(salt, "xx", sizeof(salt));
+       if ((pw = getpwuid(0)) == NULL)
+               return salt;
+       passwd = shadow_pw(pw);
+       if (passwd[0] != '$' || (p = strrchr(passwd + 1, '$')) == NULL)
+               return salt;  /* no $, DES */
+       typelen = p - passwd + 1;
+       strlcpy(salt, passwd, MIN(typelen, sizeof(salt)));
+       explicit_bzero(passwd, strlen(passwd));
+       return salt;
+}
+
 char *
 xcrypt(const char *password, const char *salt)
 {
        char *crypted;
 
+       /*
+        * If we don't have a salt we are encrypting a fake password for
+        * for timing purposes.  Pick an appropriate salt.
+        */
+       if (salt == NULL)
+               salt = pick_salt();
+
 # ifdef HAVE_MD5_PASSWORDS
         if (is_md5_salt(salt))
                 crypted = md5_crypt(password, salt);