Determine appropriate salt for invalid users.
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@
This commit is contained in:
parent
a162dd5e58
commit
9286875a73
|
@ -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
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "includes.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
|
||||
|
@ -62,11 +63,44 @@
|
|||
# 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);
|
||||
|
|
Loading…
Reference in New Issue