summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Sutton <josephsutton@catalyst.net.nz>2022-06-10 19:18:53 +1200
committerJule Anger <janger@samba.org>2022-07-24 11:42:02 +0200
commitd5af460403d3949ba266f5c74f051247cd7ce752 (patch)
treea36dc6db13116557cc41c0d2db005c49eaf12b42
parent89c6e36938c27b572573b06d1b35db210bfda99b (diff)
downloadsamba-d5af460403d3949ba266f5c74f051247cd7ce752.tar.gz
CVE-2022-2031 s4:kpasswd: Do not accept TGTs as kpasswd tickets
If TGTs can be used as kpasswd tickets, the two-minute lifetime of a authentic kpasswd ticket may be bypassed. Furthermore, kpasswd tickets are not supposed to be cached, but using this flaw, a stolen credentials cache containing a TGT may be used to change that account's password, and thus is made more valuable to an attacker. Since all TGTs should be issued with a REQUESTER_SID PAC buffer, and service tickets without it, we assert the absence of this buffer to ensure we're not accepting a TGT. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15047 BUG: https://bugzilla.samba.org/show_bug.cgi?id=15049 Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> Reviewed-by: Andreas Schneider <asn@samba.org> [jsutton@samba.org Fixed knownfail conflicts] [jsutton@samba.org Fixed knownfail conflicts]
-rw-r--r--selftest/knownfail_heimdal_kdc4
-rw-r--r--selftest/knownfail_mit_kdc4
-rw-r--r--source4/kdc/kpasswd-helper.c20
-rw-r--r--source4/kdc/kpasswd-helper.h2
-rw-r--r--source4/kdc/kpasswd-service-heimdal.c13
-rw-r--r--source4/kdc/kpasswd-service-mit.c13
6 files changed, 48 insertions, 8 deletions
diff --git a/selftest/knownfail_heimdal_kdc b/selftest/knownfail_heimdal_kdc
index 42beccaed58..424a8b81c38 100644
--- a/selftest/knownfail_heimdal_kdc
+++ b/selftest/knownfail_heimdal_kdc
@@ -271,7 +271,3 @@
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_service_ticket
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_existing
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_fast_sid_mismatch_nonexisting
-#
-# Kpasswd tests
-#
-^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_tgt.ad_dc
diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index 9fc34e5d8db..0d2f5bab6d2 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -581,7 +581,3 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_canonicalize_realm_case.ad_dc
^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_no_canonicalize_realm_case.ad_dc
^samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_ticket_requester_sid_tgs.ad_dc
-#
-# Kpasswd tests
-#
-samba.tests.krb5.kpasswd_tests.samba.tests.krb5.kpasswd_tests.KpasswdTests.test_kpasswd_tgt.ad_dc
diff --git a/source4/kdc/kpasswd-helper.c b/source4/kdc/kpasswd-helper.c
index 55a2f5b3bf6..2ffdb79aea5 100644
--- a/source4/kdc/kpasswd-helper.c
+++ b/source4/kdc/kpasswd-helper.c
@@ -241,3 +241,23 @@ NTSTATUS kpasswd_samdb_set_password(TALLOC_CTX *mem_ctx,
return status;
}
+
+krb5_error_code kpasswd_check_non_tgt(struct auth_session_info *session_info,
+ const char **error_string)
+{
+ switch(session_info->ticket_type) {
+ case TICKET_TYPE_TGT:
+ /* TGTs are disallowed here. */
+ *error_string = "A TGT may not be used as a ticket to kpasswd";
+ return KRB5_KPASSWD_AUTHERROR;
+ case TICKET_TYPE_NON_TGT:
+ /* Non-TGTs are permitted, and expected. */
+ break;
+ default:
+ /* In case we forgot to set the type. */
+ *error_string = "Failed to ascertain that ticket to kpasswd is not a TGT";
+ return KRB5_KPASSWD_HARDERROR;
+ }
+
+ return 0;
+}
diff --git a/source4/kdc/kpasswd-helper.h b/source4/kdc/kpasswd-helper.h
index 8fad81e0a5d..94a6e2acfdd 100644
--- a/source4/kdc/kpasswd-helper.h
+++ b/source4/kdc/kpasswd-helper.h
@@ -43,4 +43,6 @@ NTSTATUS kpasswd_samdb_set_password(TALLOC_CTX *mem_ctx,
enum samPwdChangeReason *reject_reason,
struct samr_DomInfo1 **dominfo);
+krb5_error_code kpasswd_check_non_tgt(struct auth_session_info *session_info,
+ const char **error_string);
#endif /* _KPASSWD_HELPER_H */
diff --git a/source4/kdc/kpasswd-service-heimdal.c b/source4/kdc/kpasswd-service-heimdal.c
index a0352d1ad35..4d009b9eb24 100644
--- a/source4/kdc/kpasswd-service-heimdal.c
+++ b/source4/kdc/kpasswd-service-heimdal.c
@@ -253,6 +253,7 @@ krb5_error_code kpasswd_handle_request(struct kdc_server *kdc,
{
struct auth_session_info *session_info;
NTSTATUS status;
+ krb5_error_code code;
status = gensec_session_info(gensec_security,
mem_ctx,
@@ -264,6 +265,18 @@ krb5_error_code kpasswd_handle_request(struct kdc_server *kdc,
return KRB5_KPASSWD_HARDERROR;
}
+ /*
+ * Since the kpasswd service shares its keys with the krbtgt, we might
+ * have received a TGT rather than a kpasswd ticket. We need to check
+ * the ticket type to ensure that TGTs cannot be misused in this manner.
+ */
+ code = kpasswd_check_non_tgt(session_info,
+ error_string);
+ if (code != 0) {
+ DBG_WARNING("%s\n", *error_string);
+ return code;
+ }
+
switch(verno) {
case KRB5_KPASSWD_VERS_CHANGEPW: {
DATA_BLOB password = data_blob_null;
diff --git a/source4/kdc/kpasswd-service-mit.c b/source4/kdc/kpasswd-service-mit.c
index de4c6f3f622..6b051567b6e 100644
--- a/source4/kdc/kpasswd-service-mit.c
+++ b/source4/kdc/kpasswd-service-mit.c
@@ -332,6 +332,7 @@ krb5_error_code kpasswd_handle_request(struct kdc_server *kdc,
{
struct auth_session_info *session_info;
NTSTATUS status;
+ krb5_error_code code;
status = gensec_session_info(gensec_security,
mem_ctx,
@@ -344,6 +345,18 @@ krb5_error_code kpasswd_handle_request(struct kdc_server *kdc,
return KRB5_KPASSWD_HARDERROR;
}
+ /*
+ * Since the kpasswd service shares its keys with the krbtgt, we might
+ * have received a TGT rather than a kpasswd ticket. We need to check
+ * the ticket type to ensure that TGTs cannot be misused in this manner.
+ */
+ code = kpasswd_check_non_tgt(session_info,
+ error_string);
+ if (code != 0) {
+ DBG_WARNING("%s\n", *error_string);
+ return code;
+ }
+
switch(verno) {
case 1: {
DATA_BLOB password;