mirror of
https://git.yoctoproject.org/poky
synced 2026-06-01 13:09:50 +00:00
openssh: Security fix CVE-2016-6210
affects openssh < 7.3 (From OE-Core rev: 7d07de3841c0a736262088c95a938deff194d9e2) Signed-off-by: Armin Kuster <akuster@mvista.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
committed by
Richard Purdie
parent
fc1ba0b67f
commit
ddb1db9ef7
@@ -0,0 +1,114 @@
|
|||||||
|
From 9286875a73b2de7736b5e50692739d314cd8d9dc Mon Sep 17 00:00:00 2001
|
||||||
|
From: Darren Tucker <dtucker@zip.com.au>
|
||||||
|
Date: Fri, 15 Jul 2016 13:32:45 +1000
|
||||||
|
Subject: [PATCH] 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@
|
||||||
|
|
||||||
|
Upstream-Status: Backport
|
||||||
|
OpenSSH < 7.3
|
||||||
|
CVE: CVE-2016-6210 patch1
|
||||||
|
Signed-off-by: Armin Kuster <akuster@mvista.com>
|
||||||
|
|
||||||
|
---
|
||||||
|
auth-passwd.c | 12 ++++++++----
|
||||||
|
openbsd-compat/xcrypt.c | 34 ++++++++++++++++++++++++++++++++++
|
||||||
|
2 files changed, 42 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
Index: openssh-7.1p2/auth-passwd.c
|
||||||
|
===================================================================
|
||||||
|
--- openssh-7.1p2.orig/auth-passwd.c
|
||||||
|
+++ openssh-7.1p2/auth-passwd.c
|
||||||
|
@@ -198,7 +198,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;
|
||||||
|
@@ -207,9 +207,13 @@ sys_auth_passwd(Authctxt *authctxt, cons
|
||||||
|
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: openssh-7.1p2/openbsd-compat/xcrypt.c
|
||||||
|
===================================================================
|
||||||
|
--- openssh-7.1p2.orig/openbsd-compat/xcrypt.c
|
||||||
|
+++ openssh-7.1p2/openbsd-compat/xcrypt.c
|
||||||
|
@@ -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);
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
From 283b97ff33ea2c641161950849931bd578de6946 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Darren Tucker <dtucker@zip.com.au>
|
||||||
|
Date: Fri, 15 Jul 2016 13:49:44 +1000
|
||||||
|
Subject: [PATCH] Mitigate timing of disallowed users PAM logins.
|
||||||
|
|
||||||
|
When sshd decides to not allow a login (eg PermitRootLogin=no) and
|
||||||
|
it's using PAM, it sends a fake password to PAM so that the timing for
|
||||||
|
the failure is not noticeably different whether or not the password
|
||||||
|
is correct. This behaviour can be detected by sending a very long
|
||||||
|
password string which is slower to hash than the fake password.
|
||||||
|
|
||||||
|
Mitigate by constructing an invalid password that is the same length
|
||||||
|
as the one from the client and thus takes the same time to hash.
|
||||||
|
Diff from djm@
|
||||||
|
|
||||||
|
Upstream-Status: Backport
|
||||||
|
CVE: CVE-2016-6210 patch2
|
||||||
|
Signed-off-by: Armin Kuster <akuster@mvista.com>
|
||||||
|
|
||||||
|
---
|
||||||
|
auth-pam.c | 35 +++++++++++++++++++++++++++++++----
|
||||||
|
1 file changed, 31 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
Index: openssh-7.1p2/auth-pam.c
|
||||||
|
===================================================================
|
||||||
|
--- openssh-7.1p2.orig/auth-pam.c
|
||||||
|
+++ openssh-7.1p2/auth-pam.c
|
||||||
|
@@ -231,7 +231,6 @@ static int sshpam_account_status = -1;
|
||||||
|
static char **sshpam_env = NULL;
|
||||||
|
static Authctxt *sshpam_authctxt = NULL;
|
||||||
|
static const char *sshpam_password = NULL;
|
||||||
|
-static char badpw[] = "\b\n\r\177INCORRECT";
|
||||||
|
|
||||||
|
/* Some PAM implementations don't implement this */
|
||||||
|
#ifndef HAVE_PAM_GETENVLIST
|
||||||
|
@@ -809,12 +808,35 @@ sshpam_query(void *ctx, char **name, cha
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Returns a junk password of identical length to that the user supplied.
|
||||||
|
+ * Used to mitigate timing attacks against crypt(3)/PAM stacks that
|
||||||
|
+ * vary processing time in proportion to password length.
|
||||||
|
+ */
|
||||||
|
+static char *
|
||||||
|
+fake_password(const char *wire_password)
|
||||||
|
+{
|
||||||
|
+ const char junk[] = "\b\n\r\177INCORRECT";
|
||||||
|
+ char *ret = NULL;
|
||||||
|
+ size_t i, l = wire_password != NULL ? strlen(wire_password) : 0;
|
||||||
|
+
|
||||||
|
+ if (l >= INT_MAX)
|
||||||
|
+ fatal("%s: password length too long: %zu", __func__, l);
|
||||||
|
+
|
||||||
|
+ ret = malloc(l + 1);
|
||||||
|
+ for (i = 0; i < l; i++)
|
||||||
|
+ ret[i] = junk[i % (sizeof(junk) - 1)];
|
||||||
|
+ ret[i] = '\0';
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/* XXX - see also comment in auth-chall.c:verify_response */
|
||||||
|
static int
|
||||||
|
sshpam_respond(void *ctx, u_int num, char **resp)
|
||||||
|
{
|
||||||
|
Buffer buffer;
|
||||||
|
struct pam_ctxt *ctxt = ctx;
|
||||||
|
+ char *fake;
|
||||||
|
|
||||||
|
debug2("PAM: %s entering, %u responses", __func__, num);
|
||||||
|
switch (ctxt->pam_done) {
|
||||||
|
@@ -835,8 +857,11 @@ sshpam_respond(void *ctx, u_int num, cha
|
||||||
|
(sshpam_authctxt->pw->pw_uid != 0 ||
|
||||||
|
options.permit_root_login == PERMIT_YES))
|
||||||
|
buffer_put_cstring(&buffer, *resp);
|
||||||
|
- else
|
||||||
|
- buffer_put_cstring(&buffer, badpw);
|
||||||
|
+ else {
|
||||||
|
+ fake = fake_password(*resp);
|
||||||
|
+ buffer_put_cstring(&buffer, fake);
|
||||||
|
+ free(fake);
|
||||||
|
+ }
|
||||||
|
if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) {
|
||||||
|
buffer_free(&buffer);
|
||||||
|
return (-1);
|
||||||
|
@@ -1180,6 +1205,7 @@ sshpam_auth_passwd(Authctxt *authctxt, c
|
||||||
|
{
|
||||||
|
int flags = (options.permit_empty_passwd == 0 ?
|
||||||
|
PAM_DISALLOW_NULL_AUTHTOK : 0);
|
||||||
|
+ char *fake = NULL;
|
||||||
|
|
||||||
|
if (!options.use_pam || sshpam_handle == NULL)
|
||||||
|
fatal("PAM: %s called when PAM disabled or failed to "
|
||||||
|
@@ -1195,7 +1221,7 @@ sshpam_auth_passwd(Authctxt *authctxt, c
|
||||||
|
*/
|
||||||
|
if (!authctxt->valid || (authctxt->pw->pw_uid == 0 &&
|
||||||
|
options.permit_root_login != PERMIT_YES))
|
||||||
|
- sshpam_password = badpw;
|
||||||
|
+ sshpam_password = fake = fake_password(password);
|
||||||
|
|
||||||
|
sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
|
||||||
|
(const void *)&passwd_conv);
|
||||||
|
@@ -1205,6 +1231,7 @@ sshpam_auth_passwd(Authctxt *authctxt, c
|
||||||
|
|
||||||
|
sshpam_err = pam_authenticate(sshpam_handle, flags);
|
||||||
|
sshpam_password = NULL;
|
||||||
|
+ free(fake);
|
||||||
|
if (sshpam_err == PAM_SUCCESS && authctxt->valid) {
|
||||||
|
debug("PAM: password authentication accepted for %.100s",
|
||||||
|
authctxt->user);
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
From dbf788b4d9d9490a5fff08a7b09888272bb10fcc Mon Sep 17 00:00:00 2001
|
||||||
|
From: Darren Tucker <dtucker@zip.com.au>
|
||||||
|
Date: Thu, 21 Jul 2016 14:17:31 +1000
|
||||||
|
Subject: [PATCH] Search users for one with a valid salt.
|
||||||
|
|
||||||
|
If the root account is locked (eg password "!!" or "*LK*") keep looking
|
||||||
|
until we find a user with a valid salt to use for crypting passwords of
|
||||||
|
invalid users. ok djm@
|
||||||
|
|
||||||
|
Upstream-Status: Backport
|
||||||
|
CVE: CVE-2016-6210
|
||||||
|
Signed-off-by: Armin Kuster <akuster@mvista.com>
|
||||||
|
|
||||||
|
---
|
||||||
|
openbsd-compat/xcrypt.c | 24 +++++++++++++++---------
|
||||||
|
1 file changed, 15 insertions(+), 9 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/openbsd-compat/xcrypt.c b/openbsd-compat/xcrypt.c
|
||||||
|
index 8913bb8..cf6a9b9 100644
|
||||||
|
--- a/openbsd-compat/xcrypt.c
|
||||||
|
+++ b/openbsd-compat/xcrypt.c
|
||||||
|
@@ -65,7 +65,9 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pick an appropriate password encryption type and salt for the running
|
||||||
|
- * system.
|
||||||
|
+ * system by searching through accounts until we find one that has a valid
|
||||||
|
+ * salt. Usually this will be root unless the root account is locked out.
|
||||||
|
+ * If we don't find one we return a traditional DES-based salt.
|
||||||
|
*/
|
||||||
|
static const char *
|
||||||
|
pick_salt(void)
|
||||||
|
@@ -78,14 +80,18 @@ pick_salt(void)
|
||||||
|
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));
|
||||||
|
+ setpwent();
|
||||||
|
+ while ((pw = getpwent()) != NULL) {
|
||||||
|
+ passwd = shadow_pw(pw);
|
||||||
|
+ if (passwd[0] == '$' && (p = strrchr(passwd+1, '$')) != NULL) {
|
||||||
|
+ typelen = p - passwd + 1;
|
||||||
|
+ strlcpy(salt, passwd, MIN(typelen, sizeof(salt)));
|
||||||
|
+ explicit_bzero(passwd, strlen(passwd));
|
||||||
|
+ goto out;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ out:
|
||||||
|
+ endpwent();
|
||||||
|
return salt;
|
||||||
|
}
|
||||||
|
|
||||||
|
--
|
||||||
|
2.7.4
|
||||||
|
|
||||||
@@ -25,6 +25,9 @@ SRC_URI = "ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-${PV}.tar.
|
|||||||
file://CVE-2016-1907_2.patch \
|
file://CVE-2016-1907_2.patch \
|
||||||
file://CVE-2016-1907_3.patch \
|
file://CVE-2016-1907_3.patch \
|
||||||
file://CVE-2016-3115.patch \
|
file://CVE-2016-3115.patch \
|
||||||
|
file://CVE-2016-6210.patch \
|
||||||
|
file://CVE-2016-6210_p2.patch \
|
||||||
|
file://CVE-2016-6210_p3.patch \
|
||||||
"
|
"
|
||||||
|
|
||||||
PAM_SRC_URI = "file://sshd"
|
PAM_SRC_URI = "file://sshd"
|
||||||
|
|||||||
Reference in New Issue
Block a user