From e3b5a5e5267818c97750b266df50b6a3d4649604 Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Tue, 24 Mar 2015 12:02:37 -0400 Subject: [PATCH] Prevent requires_preauth bypass [CVE-2015-2694] In the OTP kdcpreauth module, don't set the TKT_FLG_PRE_AUTH bit until the request is successfully verified. In the PKINIT kdcpreauth module, don't respond with code 0 on empty input or an unconfigured realm. Together these bugs could cause the KDC preauth framework to erroneously treat a request as pre-authenticated. CVE-2015-2694: In MIT krb5 1.12 and later, when the KDC is configured with PKINIT support, an unauthenticated remote attacker can bypass the requires_preauth flag on a client principal and obtain a ciphertext encrypted in the principal's long-term key. This ciphertext could be used to conduct an off-line dictionary attack against the user's password. CVSSv2 Vector: AV:N/AC:M/Au:N/C:P/I:P/A:N/E:POC/RL:OF/RC:C ticket: 8160 (new) target_version: 1.13.2 tags: pullup subject: requires_preauth bypass in PKINIT-enabled KDC [CVE-2015-2694] --- src/plugins/preauth/otp/main.c | 10 +++++++--- src/plugins/preauth/pkinit/pkinit_srv.c | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/plugins/preauth/otp/main.c b/src/plugins/preauth/otp/main.c index bf9c6a8..7941b4a 100644 --- a/src/plugins/preauth/otp/main.c +++ b/src/plugins/preauth/otp/main.c @@ -42,6 +42,7 @@ static krb5_preauthtype otp_pa_type_list[] = struct request_state { krb5_kdcpreauth_verify_respond_fn respond; void *arg; + krb5_enc_tkt_part *enc_tkt_reply; }; static krb5_error_code @@ -159,6 +160,9 @@ on_response(void *data, krb5_error_code retval, otp_response response) if (retval == 0 && response != otp_response_success) retval = KRB5_PREAUTH_FAILED; + if (retval == 0) + rs.enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH; + rs.respond(rs.arg, retval, NULL, NULL, NULL); } @@ -263,8 +267,6 @@ otp_verify(krb5_context context, krb5_data *req_pkt, krb5_kdc_req *request, krb5_data d, plaintext; char *config; - enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH; - /* Get the FAST armor key. */ armor_key = cb->fast_armor(context, rock); if (armor_key == NULL) { @@ -298,12 +300,14 @@ otp_verify(krb5_context context, krb5_data *req_pkt, krb5_kdc_req *request, goto error; } - /* Create the request state. */ + /* Create the request state. Save the response callback, and the + * enc_tkt_reply pointer so we can set the TKT_FLG_PRE_AUTH flag later. */ rs = k5alloc(sizeof(struct request_state), &retval); if (rs == NULL) goto error; rs->arg = arg; rs->respond = respond; + rs->enc_tkt_reply = enc_tkt_reply; /* Get the principal's OTP configuration string. */ retval = cb->get_string(context, rock, "otp", &config); diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c index b472741..5b1d73e 100644 --- a/src/plugins/preauth/pkinit/pkinit_srv.c +++ b/src/plugins/preauth/pkinit/pkinit_srv.c @@ -301,7 +301,7 @@ pkinit_server_verify_padata(krb5_context context, pkiDebug("pkinit_verify_padata: entered!\n"); if (data == NULL || data->length <= 0 || data->contents == NULL) { - (*respond)(arg, 0, NULL, NULL, NULL); + (*respond)(arg, EINVAL, NULL, NULL, NULL); return; } @@ -313,7 +313,7 @@ pkinit_server_verify_padata(krb5_context context, plgctx = pkinit_find_realm_context(context, moddata, request->server); if (plgctx == NULL) { - (*respond)(arg, 0, NULL, NULL, NULL); + (*respond)(arg, EINVAL, NULL, NULL, NULL); return; }