Bug#798091: wheezy-pu: package pykerberos/1.1+svn4895-1+deb7u1
Package: release.debian.org
Severity: normal
Tags: wheezy
User: release.debian.org@packages.debian.org
Usertags: pu
Hi,
I'd like to fix CVE-2015-3206 (missing KDC authenticity verification)
for wheezy via a point release. The debdiff is attached. The bug is
fixed in unstable as well as squeeze-lts already.
As in squeeze-lts the KDC check is disabled by default to not break existing
installations.
Cheers,
-- Guido.
-- System Information:
Debian Release: 8.1
APT prefers stable
APT policy: (990, 'stable'), (500, 'stable-updates'), (500, 'unstable'), (500, 'testing'), (1, 'experimental')
Architecture: amd64 (x86_64)
Foreign Architectures: i386
Kernel: Linux 4.1.0-2-amd64 (SMP w/4 CPU cores)
Locale: LANG=de_DE.UTF-8, LC_CTYPE=de_DE.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
>From 196366a8fbf843cc91f88aa17eed7aff2591b693 Mon Sep 17 00:00:00 2001
Message-Id: <196366a8fbf843cc91f88aa17eed7aff2591b693.1441460328.git.agx@sigxcpu.org>
From: =?UTF-8?q?Guido=20G=C3=BCnther?= <agx@sigxcpu.org>
Date: Sat, 5 Sep 2015 15:32:08 +0200
Subject: [PATCH] Forward port fix for CVE-2015-3206 to wheezy
from squeeze-lts
---
bin/login | 47 +++++++++++++++++++++++++++++++++++++++++++++++
debian/NEWS | 42 ++++++++++++++++++++++++++++++++++++++++++
debian/changelog | 9 +++++++++
debian/examples | 1 +
pysrc/kerberos.py | 4 +++-
src/kerberos.c | 5 +++--
src/kerberosbasic.c | 41 ++++++++++++++++++++++++++++++++++-------
src/kerberosbasic.h | 2 +-
8 files changed, 140 insertions(+), 11 deletions(-)
create mode 100644 bin/login
create mode 100644 debian/NEWS
diff --git a/bin/login b/bin/login
new file mode 100644
index 0000000..d9becaa
--- /dev/null
+++ b/bin/login
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+##
+# Copyright (c) 2008 Jelmer Vernooij <jelmer@samba.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""A sample script showing how to verify a user with username and password."""
+
+import argparse
+import getpass
+import kerberos
+import sys
+
+
+def main():
+ # construct arg parser
+ parser = argparse.ArgumentParser(description='Verify Kerberos login.')
+ parser.add_argument('--service', default='', help='the service to authenticate as')
+ parser.add_argument('--default_realm', default='', help='the realm to use if none is provided in the username')
+ parser.add_argument('--verify', default=False, action='store_true', help='enable KDC verification support')
+ parser.add_argument('user', metavar='user', help='the username to verify')
+ args = parser.parse_args()
+
+ print args.service
+
+ # get the password
+ password = getpass.getpass('Password: ')
+
+ # verify
+ try:
+ kerberos.checkPassword(args.user, password, args.service, args.default_realm, args.verify)
+ print "Successfully verified"
+ except kerberos.BasicAuthError as e:
+ print "{0} ({1})".format(*e.args)
+
+if __name__ == "__main__":
+ main()
diff --git a/debian/NEWS b/debian/NEWS
new file mode 100644
index 0000000..2143663
--- /dev/null
+++ b/debian/NEWS
@@ -0,0 +1,42 @@
+pykerberos (1.1+svn4895-1+deb7u1) wheezy; urgency=medium
+
+ The python-kerberos checkPassword() method has been badly insecure in
+ previous releases. It used to do (and still does by default) a kinit
+ (AS-REQ) to ask a KDC for a TGT for the given user principal, and
+ interprets the success or failure of that as indicating whether the
+ password is correct. It does not, however, verify that it actually spoke
+ to a trusted KDC: an attacker may simply reply instead with an AS-REP
+ which matches the password he just gave you.
+ .
+ Imagine you were verifying a password using LDAP authentication rather
+ than Kerberos: you would, of course, use TLS in conjunction with LDAP to
+ make sure you were talking to a real, trusted LDAP server. The same
+ requirement applies here. kinit is not a password-verification service.
+ .
+ The usual way of doing this is to take the TGT you've obtained with the
+ user's password, and then obtain a ticket for a principal for which the
+ verifier has keys (e.g. a web server processing a username/password form
+ login might get a ticket for its own HTTP/host@REALM principal), which
+ it can then verify. Note that this requires that the verifier has its
+ own Kerberos identity, which is mandated by the symmetric nature of
+ Kerberos (whereas in the LDAP case, the use of public-key cryptography
+ allows anonymous verification).
+ .
+ The fact of pykerberos being susceptible to KDC spoofing attacks has
+ been filed as CVE-2015-3206.
+ .
+ With this version of the pykerberos package a new option is introduced
+ for the checkPassword() method. Setting verify to True when using
+ checkPassword() will perform a KDC verification. For this to work, you
+ need to provide a krb5.keytab file containing service principal keys for
+ the service you intend to use.
+ .
+ As the default krb5.keytab file in /etc is normally not accessible by
+ non-root users/processes, you have to make sure a custom krb5.keytab
+ file containing the correct principal keys is provided to your
+ application using the KRB5_KTNAME environment variable.
+ .
+ Note: In Debian wheezy, KDC verification support is disabled by
+ default in ordner not to break existing setups.
+
+ -- Guido Günther <agx@sigxcpu.org> Sat, 05 Sep 2015 15:31:19 +0200
diff --git a/debian/changelog b/debian/changelog
index 27c11ff..f0076d2 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,12 @@
+pykerberos (1.1+svn4895-1+deb7u1) wheezy; urgency=medium
+
+ * Add KDC authenticity verification support (CVE-2015-3206).
+ Obtained from upstream, ignoring white-space changes, URL:
+ https://github.com/02strich/pykerberos/commit/
+ 02d13860b25fab58e739f0e000bed0067b7c6f9c
+
+ -- Guido Günther <agx@sigxcpu.org> Sat, 05 Sep 2015 15:31:19 +0200
+
pykerberos (1.1+svn4895-1) unstable; urgency=low
* [d6e470d] fix typo in package description (Closes: #520276) - thanks to
diff --git a/debian/examples b/debian/examples
index de45608..10845a7 100644
--- a/debian/examples
+++ b/debian/examples
@@ -1 +1,2 @@
bin/ftp-gss
+bin/login
diff --git a/pysrc/kerberos.py b/pysrc/kerberos.py
index eb8839f..a6c4c3a 100644
--- a/pysrc/kerberos.py
+++ b/pysrc/kerberos.py
@@ -27,7 +27,7 @@ class BasicAuthError(KrbError):
class GSSError(KrbError):
pass
-def checkPassword(user, pswd, service, default_realm):
+def checkPassword(user, pswd, service, default_realm, verify=False):
"""
This function provides a simple way to verify that a user name and password match
those normally used for Kerberos authentication. It does this by checking that the
@@ -49,6 +49,8 @@ def checkPassword(user, pswd, service, default_realm):
@param default_realm: a string containing the default realm to use if one is not
supplied in the user argument. Note that Kerberos realms are normally all
uppercase (e.g., 'EXAMPLE.COM').
+ @param verify: a boolean flagging KDC verification to enabled or disabled
+ (default: False).
@return: True if authentication succeeds, False otherwise.
"""
diff --git a/src/kerberos.c b/src/kerberos.c
index e0d8938..a887f7c 100644
--- a/src/kerberos.c
+++ b/src/kerberos.c
@@ -31,12 +31,13 @@ static PyObject *checkPassword(PyObject *self, PyObject *args)
const char *pswd;
const char *service;
const char *default_realm;
+ int verify = 0;
int result = 0;
- if (!PyArg_ParseTuple(args, "ssss", &user, &pswd, &service, &default_realm))
+ if (!PyArg_ParseTuple(args, "ssss|b", &user, &pswd, &service, &default_realm, &verify))
return NULL;
- result = authenticate_user_krb5pwd(user, pswd, service, default_realm);
+ result = authenticate_user_krb5pwd(user, pswd, service, default_realm, verify);
if (result)
return Py_INCREF(Py_True), Py_True;
diff --git a/src/kerberosbasic.c b/src/kerberosbasic.c
index 8b38f11..65ec176 100644
--- a/src/kerberosbasic.c
+++ b/src/kerberosbasic.c
@@ -26,9 +26,9 @@
extern PyObject *BasicAuthException_class;
static void set_basicauth_error(krb5_context context, krb5_error_code code);
-static krb5_error_code verify_krb5_user(krb5_context context, krb5_principal principal, const char *password, krb5_principal server);
+static krb5_error_code verify_krb5_user(krb5_context context, krb5_principal principal, const char *password, krb5_principal server, unsigned char verify);
-int authenticate_user_krb5pwd(const char *user, const char *pswd, const char *service, const char *default_realm)
+int authenticate_user_krb5pwd(const char *user, const char *pswd, const char *service, const char *default_realm, unsigned char verify)
{
krb5_context kcontext = NULL;
krb5_error_code code;
@@ -87,7 +87,7 @@ int authenticate_user_krb5pwd(const char *user, const char *pswd, const char *se
goto end;
}
- code = verify_krb5_user(kcontext, client, pswd, server);
+ code = verify_krb5_user(kcontext, client, pswd, server, verify);
if (code)
{
@@ -113,10 +113,11 @@ end:
}
/* Inspired by krb5_verify_user from Heimdal */
-static krb5_error_code verify_krb5_user(krb5_context context, krb5_principal principal, const char *password, krb5_principal server)
+static krb5_error_code verify_krb5_user(krb5_context context, krb5_principal principal, const char *password, krb5_principal server, unsigned char verify)
{
krb5_creds creds;
- krb5_get_init_creds_opt gic_options;
+ krb5_get_init_creds_opt *gic_options;
+ krb5_verify_init_creds_opt vic_options;
krb5_error_code ret;
char *name = NULL;
@@ -131,17 +132,43 @@ static krb5_error_code verify_krb5_user(krb5_context context, krb5_principal pri
free(name);
}
- krb5_get_init_creds_opt_init(&gic_options);
- ret = krb5_get_init_creds_password(context, &creds, principal, (char *)password, NULL, NULL, 0, NULL, &gic_options);
+ // verify passed in server principal if needed
+ if (verify) {
+ ret = krb5_unparse_name(context, server, &name);
+ if (ret == 0) {
+#ifdef PRINTFS
+ printf("Trying to get TGT for service %s\n", name);
+#endif
+ free(name);
+ }
+ }
+
+ // verify password
+ krb5_get_init_creds_opt_alloc(context, &gic_options);
+ ret = krb5_get_init_creds_password(context, &creds, principal, (char *)password, NULL, NULL, 0, NULL, gic_options);
if (ret)
{
set_basicauth_error(context, ret);
goto end;
}
+ // verify response authenticity
+ if (verify) {
+ krb5_verify_init_creds_opt_init(&vic_options);
+ krb5_verify_init_creds_opt_set_ap_req_nofail(&vic_options, 1);
+ ret = krb5_verify_init_creds(context, &creds, server, NULL, NULL, &vic_options);
+ if (ret) {
+ set_basicauth_error(context, ret);
+ }
+ }
+
end:
+ // clean up
krb5_free_cred_contents(context, &creds);
+ if (gic_options)
+ krb5_get_init_creds_opt_free(context, gic_options);
+
return ret;
}
diff --git a/src/kerberosbasic.h b/src/kerberosbasic.h
index d3dca95..116d93d 100644
--- a/src/kerberosbasic.h
+++ b/src/kerberosbasic.h
@@ -20,4 +20,4 @@
#define krb5_get_err_text(context,code) error_message(code)
-int authenticate_user_krb5pwd(const char *user, const char *pswd, const char *service, const char *default_realm);
+int authenticate_user_krb5pwd(const char *user, const char *pswd, const char *service, const char *default_realm, unsigned char verify);
--
2.1.4
Reply to: