vishalmishra434 / rpms / openssh

Forked from rpms/openssh a month ago
Clone
Jakub Jelen 105790
From 9286875a73b2de7736b5e50692739d314cd8d9dc Mon Sep 17 00:00:00 2001
Jakub Jelen 105790
From: Darren Tucker <dtucker@zip.com.au>
Jakub Jelen 105790
Date: Fri, 15 Jul 2016 13:32:45 +1000
Jakub Jelen 105790
Subject: [PATCH] Determine appropriate salt for invalid users.
Jakub Jelen 105790
Jakub Jelen 105790
When sshd is processing a non-PAM login for a non-existent user it uses
Jakub Jelen 105790
the string from the fakepw structure as the salt for crypt(3)ing the
Jakub Jelen 105790
password supplied by the client.  That string has a Blowfish prefix, so on
Jakub Jelen 105790
systems that don't understand that crypt will fail fast due to an invalid
Jakub Jelen 105790
salt, and even on those that do it may have significantly different timing
Jakub Jelen 105790
from the hash methods used for real accounts (eg sha512).  This allows
Jakub Jelen 105790
user enumeration by, eg, sending large password strings.  This was noted
Jakub Jelen 105790
by EddieEzra.Harari at verint.com (CVE-2016-6210).
Jakub Jelen 105790
Jakub Jelen 105790
To mitigate, use the same hash algorithm that root uses for hashing
Jakub Jelen 105790
passwords for users that do not exist on the system.  ok djm@
Jakub Jelen 105790
---
Jakub Jelen 105790
 auth-passwd.c           | 12 ++++++++----
Jakub Jelen 105790
 openbsd-compat/xcrypt.c | 34 ++++++++++++++++++++++++++++++++++
Jakub Jelen 105790
 2 files changed, 42 insertions(+), 4 deletions(-)
Jakub Jelen 105790
Jakub Jelen 105790
diff --git a/auth-passwd.c b/auth-passwd.c
Jakub Jelen 105790
index 63ccf3c..530b5d4 100644
Jakub Jelen 105790
--- a/auth-passwd.c
Jakub Jelen 105790
+++ b/auth-passwd.c
Jakub Jelen 105790
@@ -193,7 +193,7 @@ int
Jakub Jelen 105790
 sys_auth_passwd(Authctxt *authctxt, const char *password)
Jakub Jelen 105790
 {
Jakub Jelen 105790
 	struct passwd *pw = authctxt->pw;
Jakub Jelen 105790
-	char *encrypted_password;
Jakub Jelen 105790
+	char *encrypted_password, *salt = NULL;
Jakub Jelen 105790
 
Jakub Jelen 105790
 	/* Just use the supplied fake password if authctxt is invalid */
Jakub Jelen 105790
 	char *pw_password = authctxt->valid ? shadow_pw(pw) : pw->pw_passwd;
Jakub Jelen 105790
@@ -202,9 +202,13 @@ sys_auth_passwd(Authctxt *authctxt, const char *password)
Jakub Jelen 105790
 	if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0)
Jakub Jelen 105790
 		return (1);
Jakub Jelen 105790
 
Jakub Jelen 105790
-	/* Encrypt the candidate password using the proper salt. */
Jakub Jelen 105790
-	encrypted_password = xcrypt(password,
Jakub Jelen 105790
-	    (pw_password[0] && pw_password[1]) ? pw_password : "xx");
Jakub Jelen 105790
+	/*
Jakub Jelen 105790
+	 * Encrypt the candidate password using the proper salt, or pass a
Jakub Jelen 105790
+	 * NULL and let xcrypt pick one.
Jakub Jelen 105790
+	 */
Jakub Jelen 105790
+	if (authctxt->valid && pw_password[0] && pw_password[1])
Jakub Jelen 105790
+		salt = pw_password;
Jakub Jelen 105790
+	encrypted_password = xcrypt(password, salt);
Jakub Jelen 105790
 
Jakub Jelen 105790
 	/*
Jakub Jelen 105790
 	 * Authentication is accepted if the encrypted passwords
Jakub Jelen 105790
diff --git a/openbsd-compat/xcrypt.c b/openbsd-compat/xcrypt.c
Jakub Jelen 105790
index 8577cbd..8913bb8 100644
Jakub Jelen 105790
--- a/openbsd-compat/xcrypt.c
Jakub Jelen 105790
+++ b/openbsd-compat/xcrypt.c
Jakub Jelen 105790
@@ -25,6 +25,7 @@
Jakub Jelen 105790
 #include "includes.h"
Jakub Jelen 105790
 
Jakub Jelen 105790
 #include <sys/types.h>
Jakub Jelen 105790
+#include <string.h>
Jakub Jelen 105790
 #include <unistd.h>
Jakub Jelen 105790
 #include <pwd.h>
Jakub Jelen 105790
 
Jakub Jelen 105790
@@ -62,11 +63,44 @@
Jakub Jelen 105790
 #  define crypt DES_crypt
Jakub Jelen 105790
 # endif
Jakub Jelen 105790
 
Jakub Jelen 105790
+/*
Jakub Jelen 105790
+ * Pick an appropriate password encryption type and salt for the running
Jakub Jelen 105790
+ * system.
Jakub Jelen 105790
+ */
Jakub Jelen 105790
+static const char *
Jakub Jelen 105790
+pick_salt(void)
Jakub Jelen 105790
+{
Jakub Jelen 105790
+	struct passwd *pw;
Jakub Jelen 105790
+	char *passwd, *p;
Jakub Jelen 105790
+	size_t typelen;
Jakub Jelen 105790
+	static char salt[32];
Jakub Jelen 105790
+
Jakub Jelen 105790
+	if (salt[0] != '\0')
Jakub Jelen 105790
+		return salt;
Jakub Jelen 105790
+	strlcpy(salt, "xx", sizeof(salt));
Jakub Jelen 105790
+	if ((pw = getpwuid(0)) == NULL)
Jakub Jelen 105790
+		return salt;
Jakub Jelen 105790
+	passwd = shadow_pw(pw);
Jakub Jelen 105790
+	if (passwd[0] != '$' || (p = strrchr(passwd + 1, '$')) == NULL)
Jakub Jelen 105790
+		return salt;  /* no $, DES */
Jakub Jelen 105790
+	typelen = p - passwd + 1;
Jakub Jelen 105790
+	strlcpy(salt, passwd, MIN(typelen, sizeof(salt)));
Jakub Jelen 105790
+	explicit_bzero(passwd, strlen(passwd));
Jakub Jelen 105790
+	return salt;
Jakub Jelen 105790
+}
Jakub Jelen 105790
+
Jakub Jelen 105790
 char *
Jakub Jelen 105790
 xcrypt(const char *password, const char *salt)
Jakub Jelen 105790
 {
Jakub Jelen 105790
 	char *crypted;
Jakub Jelen 105790
 
Jakub Jelen 105790
+	/*
Jakub Jelen 105790
+	 * If we don't have a salt we are encrypting a fake password for
Jakub Jelen 105790
+	 * for timing purposes.  Pick an appropriate salt.
Jakub Jelen 105790
+	 */
Jakub Jelen 105790
+	if (salt == NULL)
Jakub Jelen 105790
+		salt = pick_salt();
Jakub Jelen 105790
+
Jakub Jelen 105790
 # ifdef HAVE_MD5_PASSWORDS
Jakub Jelen 105790
         if (is_md5_salt(salt))
Jakub Jelen 105790
                 crypted = md5_crypt(password, salt);
Jakub Jelen 105790
Jakub Jelen 105790
From 283b97ff33ea2c641161950849931bd578de6946 Mon Sep 17 00:00:00 2001
Jakub Jelen 105790
From: Darren Tucker <dtucker@zip.com.au>
Jakub Jelen 105790
Date: Fri, 15 Jul 2016 13:49:44 +1000
Jakub Jelen 105790
Subject: [PATCH] Mitigate timing of disallowed users PAM logins.
Jakub Jelen 105790
Jakub Jelen 105790
When sshd decides to not allow a login (eg PermitRootLogin=no) and
Jakub Jelen 105790
it's using PAM, it sends a fake password to PAM so that the timing for
Jakub Jelen 105790
the failure is not noticeably different whether or not the password
Jakub Jelen 105790
is correct.  This behaviour can be detected by sending a very long
Jakub Jelen 105790
password string which is slower to hash than the fake password.
Jakub Jelen 105790
Jakub Jelen 105790
Mitigate by constructing an invalid password that is the same length
Jakub Jelen 105790
as the one from the client and thus takes the same time to hash.
Jakub Jelen 105790
Diff from djm@
Jakub Jelen 105790
---
Jakub Jelen 105790
 auth-pam.c | 35 +++++++++++++++++++++++++++++++----
Jakub Jelen 105790
 1 file changed, 31 insertions(+), 4 deletions(-)
Jakub Jelen 105790
Jakub Jelen 105790
diff --git a/auth-pam.c b/auth-pam.c
Jakub Jelen 105790
index 451de78..465b5a7 100644
Jakub Jelen 105790
--- a/auth-pam.c
Jakub Jelen 105790
+++ b/auth-pam.c
Jakub Jelen 105790
@@ -232,7 +232,6 @@ static int sshpam_account_status = -1;
Jakub Jelen 105790
 static char **sshpam_env = NULL;
Jakub Jelen 105790
 static Authctxt *sshpam_authctxt = NULL;
Jakub Jelen 105790
 static const char *sshpam_password = NULL;
Jakub Jelen 105790
-static char badpw[] = "\b\n\r\177INCORRECT";
Jakub Jelen 105790
 
Jakub Jelen 105790
 /* Some PAM implementations don't implement this */
Jakub Jelen 105790
 #ifndef HAVE_PAM_GETENVLIST
Jakub Jelen 105790
@@ -795,12 +794,35 @@ sshpam_query(void *ctx, char **name, char **info,
Jakub Jelen 105790
 	return (-1);
Jakub Jelen 105790
 }
Jakub Jelen 105790
 
Jakub Jelen 105790
+/*
Jakub Jelen 105790
+ * Returns a junk password of identical length to that the user supplied.
Jakub Jelen 105790
+ * Used to mitigate timing attacks against crypt(3)/PAM stacks that
Jakub Jelen 105790
+ * vary processing time in proportion to password length.
Jakub Jelen 105790
+ */
Jakub Jelen 105790
+static char *
Jakub Jelen 105790
+fake_password(const char *wire_password)
Jakub Jelen 105790
+{
Jakub Jelen 105790
+	const char junk[] = "\b\n\r\177INCORRECT";
Jakub Jelen 105790
+	char *ret = NULL;
Jakub Jelen 105790
+	size_t i, l = wire_password != NULL ? strlen(wire_password) : 0;
Jakub Jelen 105790
+
Jakub Jelen 105790
+	if (l >= INT_MAX)
Jakub Jelen 105790
+		fatal("%s: password length too long: %zu", __func__, l);
Jakub Jelen 105790
+
Jakub Jelen 105790
+	ret = malloc(l + 1);
Jakub Jelen 105790
+	for (i = 0; i < l; i++)
Jakub Jelen 105790
+		ret[i] = junk[i % (sizeof(junk) - 1)];
Jakub Jelen 105790
+	ret[i] = '\0';
Jakub Jelen 105790
+	return ret;
Jakub Jelen 105790
+}
Jakub Jelen 105790
+
Jakub Jelen 105790
 /* XXX - see also comment in auth-chall.c:verify_response */
Jakub Jelen 105790
 static int
Jakub Jelen 105790
 sshpam_respond(void *ctx, u_int num, char **resp)
Jakub Jelen 105790
 {
Jakub Jelen 105790
 	Buffer buffer;
Jakub Jelen 105790
 	struct pam_ctxt *ctxt = ctx;
Jakub Jelen 105790
+	char *fake;
Jakub Jelen 105790
 
Jakub Jelen 105790
 	debug2("PAM: %s entering, %u responses", __func__, num);
Jakub Jelen 105790
 	switch (ctxt->pam_done) {
Jakub Jelen 105790
@@ -821,8 +843,11 @@ sshpam_respond(void *ctx, u_int num, char **resp)
Jakub Jelen 105790
 	    (sshpam_authctxt->pw->pw_uid != 0 ||
Jakub Jelen 105790
 	    options.permit_root_login == PERMIT_YES))
Jakub Jelen 105790
 		buffer_put_cstring(&buffer, *resp);
Jakub Jelen 105790
-	else
Jakub Jelen 105790
-		buffer_put_cstring(&buffer, badpw);
Jakub Jelen 105790
+	else {
Jakub Jelen 105790
+		fake = fake_password(*resp);
Jakub Jelen 105790
+		buffer_put_cstring(&buffer, fake);
Jakub Jelen 105790
+		free(fake);
Jakub Jelen 105790
+	}
Jakub Jelen 105790
 	if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) {
Jakub Jelen 105790
 		buffer_free(&buffer);
Jakub Jelen 105790
 		return (-1);
Jakub Jelen 105790
@@ -1166,6 +1191,7 @@ sshpam_auth_passwd(Authctxt *authctxt, const char *password)
Jakub Jelen 105790
 {
Jakub Jelen 105790
 	int flags = (options.permit_empty_passwd == 0 ?
Jakub Jelen 105790
 	    PAM_DISALLOW_NULL_AUTHTOK : 0);
Jakub Jelen 105790
+	char *fake = NULL;
Jakub Jelen 105790
 
Jakub Jelen 105790
 	if (!options.use_pam || sshpam_handle == NULL)
Jakub Jelen 105790
 		fatal("PAM: %s called when PAM disabled or failed to "
Jakub Jelen 105790
@@ -1181,7 +1207,7 @@ sshpam_auth_passwd(Authctxt *authctxt, const char *password)
Jakub Jelen 105790
 	 */
Jakub Jelen 105790
 	if (!authctxt->valid || (authctxt->pw->pw_uid == 0 &&
Jakub Jelen 105790
 	    options.permit_root_login != PERMIT_YES))
Jakub Jelen 105790
-		sshpam_password = badpw;
Jakub Jelen 105790
+		sshpam_password = fake = fake_password(password);
Jakub Jelen 105790
 
Jakub Jelen 105790
 	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
Jakub Jelen 105790
 	    (const void *)&passwd_conv);
Jakub Jelen 105790
@@ -1191,6 +1217,7 @@ sshpam_auth_passwd(Authctxt *authctxt, const char *password)
Jakub Jelen 105790
 
Jakub Jelen 105790
 	sshpam_err = pam_authenticate(sshpam_handle, flags);
Jakub Jelen 105790
 	sshpam_password = NULL;
Jakub Jelen 105790
+	free(fake);
Jakub Jelen 105790
 	if (sshpam_err == PAM_SUCCESS && authctxt->valid) {
Jakub Jelen 105790
 		debug("PAM: password authentication accepted for %.100s",
Jakub Jelen 105790
 		    authctxt->user);
Jakub Jelen 105790