diff options
author | Efraim Flashner <efraim@flashner.co.il> | 2016-07-24 16:18:41 +0300 |
---|---|---|
committer | Efraim Flashner <efraim@flashner.co.il> | 2016-07-24 16:18:41 +0300 |
commit | d841a292b27fdda780cc3692eb2bfed211bc3675 (patch) | |
tree | ac411bbed936e34fa71f8affb94f41b495f41377 | |
parent | df2c7563ffb9f84239327c46719cd6a7cc01af39 (diff) | |
download | guix-d841a292b27fdda780cc3692eb2bfed211bc3675.tar guix-d841a292b27fdda780cc3692eb2bfed211bc3675.tar.gz |
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.
-rw-r--r-- | gnu/local.mk | 3 | ||||
-rw-r--r-- | gnu/packages/patches/openssh-CVE-2016-6210-1.patch | 114 | ||||
-rw-r--r-- | gnu/packages/patches/openssh-CVE-2016-6210-2.patch | 111 | ||||
-rw-r--r-- | gnu/packages/patches/openssh-CVE-2016-6210-3.patch | 60 | ||||
-rw-r--r-- | gnu/packages/ssh.scm | 5 |
5 files changed, 292 insertions, 1 deletions
diff --git a/gnu/local.mk b/gnu/local.mk index 31a4d58f84..ea63453129 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 0000000000..9b46ec12a9 --- /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 <dtucker@zip.com.au> +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 0000000000..1c580f90b9 --- /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 <dtucker@zip.com.au> +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 0000000000..303c34ee1b --- /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 <dtucker@zip.com.au> +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 71310ecf94..61a6a5b9d9 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) |