diff options
author | Colin Watson <cjwatson@debian.org> | 2016-07-22 14:09:29 +0100 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2016-07-22 14:11:33 +0100 |
commit | 5ebf9c1d19aa0d9d20781bab05e9d73d8addecb3 (patch) | |
tree | 7d48ac2d5442eff8ca63a0dd6938651e05b9c7c3 /debian/patches/CVE-2016-6210-2.patch | |
parent | 79139a04a0183cd47f3e837fa76fe5d51e62fcc9 (diff) | |
parent | abde8dda29c2db2405d6fbca2fe022430e2c1177 (diff) |
CVE-2016-6210: Mitigate user enumeration via covert timing channel.
Diffstat (limited to 'debian/patches/CVE-2016-6210-2.patch')
-rw-r--r-- | debian/patches/CVE-2016-6210-2.patch | 111 |
1 files changed, 111 insertions, 0 deletions
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 @@ | |||
1 | From dde63f7f998ac3812a26bbb2c1b2947f24fcd060 Mon Sep 17 00:00:00 2001 | ||
2 | From: Darren Tucker <dtucker@zip.com.au> | ||
3 | Date: Fri, 15 Jul 2016 13:49:44 +1000 | ||
4 | Subject: Mitigate timing of disallowed users PAM logins. | ||
5 | |||
6 | When sshd decides to not allow a login (eg PermitRootLogin=no) and | ||
7 | it's using PAM, it sends a fake password to PAM so that the timing for | ||
8 | the failure is not noticeably different whether or not the password | ||
9 | is correct. This behaviour can be detected by sending a very long | ||
10 | password string which is slower to hash than the fake password. | ||
11 | |||
12 | Mitigate by constructing an invalid password that is the same length | ||
13 | as the one from the client and thus takes the same time to hash. | ||
14 | Diff from djm@ | ||
15 | |||
16 | Origin: upstream, https://anongit.mindrot.org/openssh.git/commit/?id=283b97ff33ea2c641161950849931bd578de6946 | ||
17 | Bug-Debian: https://bugs.debian.org/831902 | ||
18 | Last-Update: 2016-07-22 | ||
19 | |||
20 | Patch-Name: CVE-2016-6210-2.patch | ||
21 | --- | ||
22 | auth-pam.c | 35 +++++++++++++++++++++++++++++++---- | ||
23 | 1 file changed, 31 insertions(+), 4 deletions(-) | ||
24 | |||
25 | diff --git a/auth-pam.c b/auth-pam.c | ||
26 | index 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); | ||