summaryrefslogtreecommitdiff
path: root/debian
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2016-07-22 14:09:29 +0100
committerColin Watson <cjwatson@debian.org>2016-07-22 14:11:33 +0100
commit5ebf9c1d19aa0d9d20781bab05e9d73d8addecb3 (patch)
tree7d48ac2d5442eff8ca63a0dd6938651e05b9c7c3 /debian
parent79139a04a0183cd47f3e837fa76fe5d51e62fcc9 (diff)
parentabde8dda29c2db2405d6fbca2fe022430e2c1177 (diff)
CVE-2016-6210: Mitigate user enumeration via covert timing channel.
Diffstat (limited to 'debian')
-rw-r--r--debian/.git-dpm4
-rw-r--r--debian/changelog1
-rw-r--r--debian/patches/CVE-2016-6210-1.patch114
-rw-r--r--debian/patches/CVE-2016-6210-2.patch111
-rw-r--r--debian/patches/CVE-2016-6210-3.patch60
-rw-r--r--debian/patches/series3
6 files changed, 291 insertions, 2 deletions
diff --git a/debian/.git-dpm b/debian/.git-dpm
index 4d6e084d7..8da19debc 100644
--- a/debian/.git-dpm
+++ b/debian/.git-dpm
@@ -1,6 +1,6 @@
1# see git-dpm(1) from git-dpm package 1# see git-dpm(1) from git-dpm package
243a633de1cabe77e652125dac394a99ad9cac3b4 2abde8dda29c2db2405d6fbca2fe022430e2c1177
343a633de1cabe77e652125dac394a99ad9cac3b4 3abde8dda29c2db2405d6fbca2fe022430e2c1177
4f0329aac23c61e1a5197d6d57349a63f459bccb0 4f0329aac23c61e1a5197d6d57349a63f459bccb0
5f0329aac23c61e1a5197d6d57349a63f459bccb0 5f0329aac23c61e1a5197d6d57349a63f459bccb0
6openssh_7.2p2.orig.tar.gz 6openssh_7.2p2.orig.tar.gz
diff --git a/debian/changelog b/debian/changelog
index ac2268f2e..45cae471b 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -9,6 +9,7 @@ openssh (1:7.2p2-6) UNRELEASED; urgency=medium
9 scp1 works (reported by Olivier MATZ). 9 scp1 works (reported by Olivier MATZ).
10 * Retroactively add a NEWS.Debian entry for the UseDNS change in 6.9 (see 10 * Retroactively add a NEWS.Debian entry for the UseDNS change in 6.9 (see
11 LP #1588457). 11 LP #1588457).
12 * CVE-2016-6210: Mitigate user enumeration via covert timing channel.
12 13
13 -- Colin Watson <cjwatson@debian.org> Sat, 30 Apr 2016 11:29:20 +0100 14 -- Colin Watson <cjwatson@debian.org> Sat, 30 Apr 2016 11:29:20 +0100
14 15
diff --git a/debian/patches/CVE-2016-6210-1.patch b/debian/patches/CVE-2016-6210-1.patch
new file mode 100644
index 000000000..9b46ec12a
--- /dev/null
+++ b/debian/patches/CVE-2016-6210-1.patch
@@ -0,0 +1,114 @@
1From e5ef9d3942cebda819a6fd81647b51c8d87d23df Mon Sep 17 00:00:00 2001
2From: Darren Tucker <dtucker@zip.com.au>
3Date: Fri, 15 Jul 2016 13:32:45 +1000
4Subject: Determine appropriate salt for invalid users.
5
6When sshd is processing a non-PAM login for a non-existent user it uses
7the string from the fakepw structure as the salt for crypt(3)ing the
8password supplied by the client. That string has a Blowfish prefix, so on
9systems that don't understand that crypt will fail fast due to an invalid
10salt, and even on those that do it may have significantly different timing
11from the hash methods used for real accounts (eg sha512). This allows
12user enumeration by, eg, sending large password strings. This was noted
13by EddieEzra.Harari at verint.com (CVE-2016-6210).
14
15To mitigate, use the same hash algorithm that root uses for hashing
16passwords for users that do not exist on the system. ok djm@
17
18Origin: upstream, https://anongit.mindrot.org/openssh.git/commit/?id=9286875a73b2de7736b5e50692739d314cd8d9dc
19Bug-Debian: https://bugs.debian.org/831902
20Last-Update: 2016-07-22
21
22Patch-Name: CVE-2016-6210-1.patch
23---
24 auth-passwd.c | 12 ++++++++----
25 openbsd-compat/xcrypt.c | 34 ++++++++++++++++++++++++++++++++++
26 2 files changed, 42 insertions(+), 4 deletions(-)
27
28diff --git a/auth-passwd.c b/auth-passwd.c
29index 63ccf3c..530b5d4 100644
30--- a/auth-passwd.c
31+++ b/auth-passwd.c
32@@ -193,7 +193,7 @@ int
33 sys_auth_passwd(Authctxt *authctxt, const char *password)
34 {
35 struct passwd *pw = authctxt->pw;
36- char *encrypted_password;
37+ char *encrypted_password, *salt = NULL;
38
39 /* Just use the supplied fake password if authctxt is invalid */
40 char *pw_password = authctxt->valid ? shadow_pw(pw) : pw->pw_passwd;
41@@ -202,9 +202,13 @@ sys_auth_passwd(Authctxt *authctxt, const char *password)
42 if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0)
43 return (1);
44
45- /* Encrypt the candidate password using the proper salt. */
46- encrypted_password = xcrypt(password,
47- (pw_password[0] && pw_password[1]) ? pw_password : "xx");
48+ /*
49+ * Encrypt the candidate password using the proper salt, or pass a
50+ * NULL and let xcrypt pick one.
51+ */
52+ if (authctxt->valid && pw_password[0] && pw_password[1])
53+ salt = pw_password;
54+ encrypted_password = xcrypt(password, salt);
55
56 /*
57 * Authentication is accepted if the encrypted passwords
58diff --git a/openbsd-compat/xcrypt.c b/openbsd-compat/xcrypt.c
59index 8577cbd..8913bb8 100644
60--- a/openbsd-compat/xcrypt.c
61+++ b/openbsd-compat/xcrypt.c
62@@ -25,6 +25,7 @@
63 #include "includes.h"
64
65 #include <sys/types.h>
66+#include <string.h>
67 #include <unistd.h>
68 #include <pwd.h>
69
70@@ -62,11 +63,44 @@
71 # define crypt DES_crypt
72 # endif
73
74+/*
75+ * Pick an appropriate password encryption type and salt for the running
76+ * system.
77+ */
78+static const char *
79+pick_salt(void)
80+{
81+ struct passwd *pw;
82+ char *passwd, *p;
83+ size_t typelen;
84+ static char salt[32];
85+
86+ if (salt[0] != '\0')
87+ return salt;
88+ strlcpy(salt, "xx", sizeof(salt));
89+ if ((pw = getpwuid(0)) == NULL)
90+ return salt;
91+ passwd = shadow_pw(pw);
92+ if (passwd[0] != '$' || (p = strrchr(passwd + 1, '$')) == NULL)
93+ return salt; /* no $, DES */
94+ typelen = p - passwd + 1;
95+ strlcpy(salt, passwd, MIN(typelen, sizeof(salt)));
96+ explicit_bzero(passwd, strlen(passwd));
97+ return salt;
98+}
99+
100 char *
101 xcrypt(const char *password, const char *salt)
102 {
103 char *crypted;
104
105+ /*
106+ * If we don't have a salt we are encrypting a fake password for
107+ * for timing purposes. Pick an appropriate salt.
108+ */
109+ if (salt == NULL)
110+ salt = pick_salt();
111+
112 # ifdef HAVE_MD5_PASSWORDS
113 if (is_md5_salt(salt))
114 crypted = md5_crypt(password, salt);
diff --git a/debian/patches/CVE-2016-6210-2.patch b/debian/patches/CVE-2016-6210-2.patch
new file mode 100644
index 000000000..1c580f90b
--- /dev/null
+++ b/debian/patches/CVE-2016-6210-2.patch
@@ -0,0 +1,111 @@
1From dde63f7f998ac3812a26bbb2c1b2947f24fcd060 Mon Sep 17 00:00:00 2001
2From: Darren Tucker <dtucker@zip.com.au>
3Date: Fri, 15 Jul 2016 13:49:44 +1000
4Subject: Mitigate timing of disallowed users PAM logins.
5
6When sshd decides to not allow a login (eg PermitRootLogin=no) and
7it's using PAM, it sends a fake password to PAM so that the timing for
8the failure is not noticeably different whether or not the password
9is correct. This behaviour can be detected by sending a very long
10password string which is slower to hash than the fake password.
11
12Mitigate by constructing an invalid password that is the same length
13as the one from the client and thus takes the same time to hash.
14Diff from djm@
15
16Origin: upstream, https://anongit.mindrot.org/openssh.git/commit/?id=283b97ff33ea2c641161950849931bd578de6946
17Bug-Debian: https://bugs.debian.org/831902
18Last-Update: 2016-07-22
19
20Patch-Name: CVE-2016-6210-2.patch
21---
22 auth-pam.c | 35 +++++++++++++++++++++++++++++++----
23 1 file changed, 31 insertions(+), 4 deletions(-)
24
25diff --git a/auth-pam.c b/auth-pam.c
26index 8425af1..abd6a5e 100644
27--- a/auth-pam.c
28+++ b/auth-pam.c
29@@ -232,7 +232,6 @@ static int sshpam_account_status = -1;
30 static char **sshpam_env = NULL;
31 static Authctxt *sshpam_authctxt = NULL;
32 static const char *sshpam_password = NULL;
33-static char badpw[] = "\b\n\r\177INCORRECT";
34
35 /* Some PAM implementations don't implement this */
36 #ifndef HAVE_PAM_GETENVLIST
37@@ -810,12 +809,35 @@ sshpam_query(void *ctx, char **name, char **info,
38 return (-1);
39 }
40
41+/*
42+ * Returns a junk password of identical length to that the user supplied.
43+ * Used to mitigate timing attacks against crypt(3)/PAM stacks that
44+ * vary processing time in proportion to password length.
45+ */
46+static char *
47+fake_password(const char *wire_password)
48+{
49+ const char junk[] = "\b\n\r\177INCORRECT";
50+ char *ret = NULL;
51+ size_t i, l = wire_password != NULL ? strlen(wire_password) : 0;
52+
53+ if (l >= INT_MAX)
54+ fatal("%s: password length too long: %zu", __func__, l);
55+
56+ ret = malloc(l + 1);
57+ for (i = 0; i < l; i++)
58+ ret[i] = junk[i % (sizeof(junk) - 1)];
59+ ret[i] = '\0';
60+ return ret;
61+}
62+
63 /* XXX - see also comment in auth-chall.c:verify_response */
64 static int
65 sshpam_respond(void *ctx, u_int num, char **resp)
66 {
67 Buffer buffer;
68 struct pam_ctxt *ctxt = ctx;
69+ char *fake;
70
71 debug2("PAM: %s entering, %u responses", __func__, num);
72 switch (ctxt->pam_done) {
73@@ -836,8 +858,11 @@ sshpam_respond(void *ctx, u_int num, char **resp)
74 (sshpam_authctxt->pw->pw_uid != 0 ||
75 options.permit_root_login == PERMIT_YES))
76 buffer_put_cstring(&buffer, *resp);
77- else
78- buffer_put_cstring(&buffer, badpw);
79+ else {
80+ fake = fake_password(*resp);
81+ buffer_put_cstring(&buffer, fake);
82+ free(fake);
83+ }
84 if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) {
85 buffer_free(&buffer);
86 return (-1);
87@@ -1181,6 +1206,7 @@ sshpam_auth_passwd(Authctxt *authctxt, const char *password)
88 {
89 int flags = (options.permit_empty_passwd == 0 ?
90 PAM_DISALLOW_NULL_AUTHTOK : 0);
91+ char *fake = NULL;
92
93 if (!options.use_pam || sshpam_handle == NULL)
94 fatal("PAM: %s called when PAM disabled or failed to "
95@@ -1196,7 +1222,7 @@ sshpam_auth_passwd(Authctxt *authctxt, const char *password)
96 */
97 if (!authctxt->valid || (authctxt->pw->pw_uid == 0 &&
98 options.permit_root_login != PERMIT_YES))
99- sshpam_password = badpw;
100+ sshpam_password = fake = fake_password(password);
101
102 sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
103 (const void *)&passwd_conv);
104@@ -1206,6 +1232,7 @@ sshpam_auth_passwd(Authctxt *authctxt, const char *password)
105
106 sshpam_err = pam_authenticate(sshpam_handle, flags);
107 sshpam_password = NULL;
108+ free(fake);
109 if (sshpam_err == PAM_SUCCESS && authctxt->valid) {
110 debug("PAM: password authentication accepted for %.100s",
111 authctxt->user);
diff --git a/debian/patches/CVE-2016-6210-3.patch b/debian/patches/CVE-2016-6210-3.patch
new file mode 100644
index 000000000..303c34ee1
--- /dev/null
+++ b/debian/patches/CVE-2016-6210-3.patch
@@ -0,0 +1,60 @@
1From abde8dda29c2db2405d6fbca2fe022430e2c1177 Mon Sep 17 00:00:00 2001
2From: Darren Tucker <dtucker@zip.com.au>
3Date: Thu, 21 Jul 2016 14:17:31 +1000
4Subject: Search users for one with a valid salt.
5
6If the root account is locked (eg password "!!" or "*LK*") keep looking
7until we find a user with a valid salt to use for crypting passwords of
8invalid users. ok djm@
9
10Origin: upstream, https://anongit.mindrot.org/openssh.git/commit/?id=dbf788b4d9d9490a5fff08a7b09888272bb10fcc
11Bug-Debian: https://bugs.debian.org/831902
12Last-Update: 2016-07-22
13
14Patch-Name: CVE-2016-6210-3.patch
15---
16 openbsd-compat/xcrypt.c | 24 +++++++++++++++---------
17 1 file changed, 15 insertions(+), 9 deletions(-)
18
19diff --git a/openbsd-compat/xcrypt.c b/openbsd-compat/xcrypt.c
20index 8913bb8..cf6a9b9 100644
21--- a/openbsd-compat/xcrypt.c
22+++ b/openbsd-compat/xcrypt.c
23@@ -65,7 +65,9 @@
24
25 /*
26 * Pick an appropriate password encryption type and salt for the running
27- * system.
28+ * system by searching through accounts until we find one that has a valid
29+ * salt. Usually this will be root unless the root account is locked out.
30+ * If we don't find one we return a traditional DES-based salt.
31 */
32 static const char *
33 pick_salt(void)
34@@ -78,14 +80,18 @@ pick_salt(void)
35 if (salt[0] != '\0')
36 return salt;
37 strlcpy(salt, "xx", sizeof(salt));
38- if ((pw = getpwuid(0)) == NULL)
39- return salt;
40- passwd = shadow_pw(pw);
41- if (passwd[0] != '$' || (p = strrchr(passwd + 1, '$')) == NULL)
42- return salt; /* no $, DES */
43- typelen = p - passwd + 1;
44- strlcpy(salt, passwd, MIN(typelen, sizeof(salt)));
45- explicit_bzero(passwd, strlen(passwd));
46+ setpwent();
47+ while ((pw = getpwent()) != NULL) {
48+ passwd = shadow_pw(pw);
49+ if (passwd[0] == '$' && (p = strrchr(passwd+1, '$')) != NULL) {
50+ typelen = p - passwd + 1;
51+ strlcpy(salt, passwd, MIN(typelen, sizeof(salt)));
52+ explicit_bzero(passwd, strlen(passwd));
53+ goto out;
54+ }
55+ }
56+ out:
57+ endpwent();
58 return salt;
59 }
60
diff --git a/debian/patches/series b/debian/patches/series
index d2d89669f..363475c20 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -27,3 +27,6 @@ systemd-readiness.patch
27debian-config.patch 27debian-config.patch
28CVE-2015-8325.patch 28CVE-2015-8325.patch
29unbreak-certificate-auth.patch 29unbreak-certificate-auth.patch
30CVE-2016-6210-1.patch
31CVE-2016-6210-2.patch
32CVE-2016-6210-3.patch