guix-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

01/01: gnu: openssh: Fix CVE-2016-6210.


From: Efraim Flashner
Subject: 01/01: gnu: openssh: Fix CVE-2016-6210.
Date: Sun, 24 Jul 2016 13:19:55 +0000 (UTC)

efraim pushed a commit to branch master
in repository guix.

commit d841a292b27fdda780cc3692eb2bfed211bc3675
Author: Efraim Flashner <address@hidden>
Date:   Sun Jul 24 16:18:41 2016 +0300

    gnu: openssh: Fix CVE-2016-6210.
    
    * gnu/packages/ssh.scm (openssh)[source]: Add patches
    openssh-CVE-2016-6210-1.patch, openssh-CVE-2016-6210-2.patch,
    openssh-CVE-2016-6210-3.patch.
    * gnu/packages/patches/openssh-CVE-2016-6210-1.patch: New file.
    * gnu/packages/patches/openssh-CVE-2016-6210-2.patch: New file.
    * gnu/packages/patches/openssh-CVE-2016-6210-3.patch: New file.
    * gnu/local.mk (dist_patch_DATA): Register them.
---
 gnu/local.mk                                       |    3 +
 gnu/packages/patches/openssh-CVE-2016-6210-1.patch |  114 ++++++++++++++++++++
 gnu/packages/patches/openssh-CVE-2016-6210-2.patch |  111 +++++++++++++++++++
 gnu/packages/patches/openssh-CVE-2016-6210-3.patch |   60 +++++++++++
 gnu/packages/ssh.scm                               |    5 +-
 5 files changed, 292 insertions(+), 1 deletion(-)

diff --git a/gnu/local.mk b/gnu/local.mk
index 31a4d58..ea63453 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -696,6 +696,9 @@ dist_patch_DATA =                                           
\
   %D%/packages/patches/openjpeg-CVE-2015-6581.patch            \
   %D%/packages/patches/openjpeg-use-after-free-fix.patch       \
   %D%/packages/patches/openssh-CVE-2015-8325.patch             \
+  %D%/packages/patches/openssh-CVE-2016-6210-1.patch           \
+  %D%/packages/patches/openssh-CVE-2016-6210-2.patch           \
+  %D%/packages/patches/openssh-CVE-2016-6210-3.patch           \
   %D%/packages/patches/openssl-runpath.patch                   \
   %D%/packages/patches/openssl-c-rehash-in.patch               \
   %D%/packages/patches/openssl-CVE-2016-2177.patch             \
diff --git a/gnu/packages/patches/openssh-CVE-2016-6210-1.patch 
b/gnu/packages/patches/openssh-CVE-2016-6210-1.patch
new file mode 100644
index 0000000..9b46ec1
--- /dev/null
+++ b/gnu/packages/patches/openssh-CVE-2016-6210-1.patch
@@ -0,0 +1,114 @@
+From e5ef9d3942cebda819a6fd81647b51c8d87d23df Mon Sep 17 00:00:00 2001
+From: Darren Tucker <address@hidden>
+Date: Fri, 15 Jul 2016 13:32:45 +1000
+Subject: 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@
+
+Origin: upstream, 
https://anongit.mindrot.org/openssh.git/commit/?id=9286875a73b2de7736b5e50692739d314cd8d9dc
+Bug-Debian: https://bugs.debian.org/831902
+Last-Update: 2016-07-22
+
+Patch-Name: CVE-2016-6210-1.patch
+---
+ auth-passwd.c           | 12 ++++++++----
+ openbsd-compat/xcrypt.c | 34 ++++++++++++++++++++++++++++++++++
+ 2 files changed, 42 insertions(+), 4 deletions(-)
+
+diff --git a/auth-passwd.c b/auth-passwd.c
+index 63ccf3c..530b5d4 100644
+--- a/auth-passwd.c
++++ b/auth-passwd.c
+@@ -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
+diff --git a/openbsd-compat/xcrypt.c b/openbsd-compat/xcrypt.c
+index 8577cbd..8913bb8 100644
+--- a/openbsd-compat/xcrypt.c
++++ b/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);
diff --git a/gnu/packages/patches/openssh-CVE-2016-6210-2.patch 
b/gnu/packages/patches/openssh-CVE-2016-6210-2.patch
new file mode 100644
index 0000000..1c580f9
--- /dev/null
+++ b/gnu/packages/patches/openssh-CVE-2016-6210-2.patch
@@ -0,0 +1,111 @@
+From dde63f7f998ac3812a26bbb2c1b2947f24fcd060 Mon Sep 17 00:00:00 2001
+From: Darren Tucker <address@hidden>
+Date: Fri, 15 Jul 2016 13:49:44 +1000
+Subject: 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@
+
+Origin: upstream, 
https://anongit.mindrot.org/openssh.git/commit/?id=283b97ff33ea2c641161950849931bd578de6946
+Bug-Debian: https://bugs.debian.org/831902
+Last-Update: 2016-07-22
+
+Patch-Name: CVE-2016-6210-2.patch
+---
+ auth-pam.c | 35 +++++++++++++++++++++++++++++++----
+ 1 file changed, 31 insertions(+), 4 deletions(-)
+
+diff --git a/auth-pam.c b/auth-pam.c
+index 8425af1..abd6a5e 100644
+--- a/auth-pam.c
++++ b/auth-pam.c
+@@ -232,7 +232,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
+@@ -810,12 +809,35 @@ sshpam_query(void *ctx, char **name, char **info,
+       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) {
+@@ -836,8 +858,11 @@ sshpam_respond(void *ctx, u_int num, char **resp)
+           (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);
+@@ -1181,6 +1206,7 @@ sshpam_auth_passwd(Authctxt *authctxt, const char 
*password)
+ {
+       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 "
+@@ -1196,7 +1222,7 @@ sshpam_auth_passwd(Authctxt *authctxt, const char 
*password)
+        */
+       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);
+@@ -1206,6 +1232,7 @@ sshpam_auth_passwd(Authctxt *authctxt, const char 
*password)
+ 
+       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);
diff --git a/gnu/packages/patches/openssh-CVE-2016-6210-3.patch 
b/gnu/packages/patches/openssh-CVE-2016-6210-3.patch
new file mode 100644
index 0000000..303c34e
--- /dev/null
+++ b/gnu/packages/patches/openssh-CVE-2016-6210-3.patch
@@ -0,0 +1,60 @@
+From abde8dda29c2db2405d6fbca2fe022430e2c1177 Mon Sep 17 00:00:00 2001
+From: Darren Tucker <address@hidden>
+Date: Thu, 21 Jul 2016 14:17:31 +1000
+Subject: 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@
+
+Origin: upstream, 
https://anongit.mindrot.org/openssh.git/commit/?id=dbf788b4d9d9490a5fff08a7b09888272bb10fcc
+Bug-Debian: https://bugs.debian.org/831902
+Last-Update: 2016-07-22
+
+Patch-Name: CVE-2016-6210-3.patch
+---
+ 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;
+ }
+ 
diff --git a/gnu/packages/ssh.scm b/gnu/packages/ssh.scm
index 71310ec..61a6a5b 100644
--- a/gnu/packages/ssh.scm
+++ b/gnu/packages/ssh.scm
@@ -135,7 +135,10 @@ a server that supports the SSH-2 protocol.")
                                         tail))))
             (sha256 (base32
                      "132lh9aanb0wkisji1d6cmsxi520m8nh7c7i9wi6m1s3l38q29x7"))
-            (patches (search-patches "openssh-CVE-2015-8325.patch"))))
+            (patches (search-patches "openssh-CVE-2015-8325.patch"
+                                     "openssh-CVE-2016-6210-1.patch"
+                                     "openssh-CVE-2016-6210-2.patch"
+                                     "openssh-CVE-2016-6210-3.patch"))))
    (build-system gnu-build-system)
    (inputs `(("groff" ,groff)
              ("openssl" ,openssl)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]