The MIT Kerberos Team is aware of the following vulnerabilities in the MIT krb5 software. Please treat this information as confidential, and do not publicly disseminate it prior to our public disclosure. Also, please do not use un-encrypted communications to discuss this vulnerability. We have drafted MITKRB5-SA-2008-001 describing these vulnerabilities. We plan to publish no sooner than Tuesday, 18 March 2008, at 14:00 US/Eastern time. We plan to notify CERT/CC and vendor-sec@lst.de on 4 March 2008, but only provide them with summary text. Vendors contacted through CERT/CC or vendor-sec will be requested to contact us directly for details. We will post our public disclosure to the kerberos-announce@mit.edu and bugtraq@securityfocus.com mailing lists. Please let us know if you have any concerns about this disclosure timeline. Also, please send us any comments you have concerning the advisory text or the patches. Our preferred security contact PGP key, is available on the keyserver pgp.mit.edu: pub 1024D/2915318C 2008-01-18 [expires: 2009-02-01] uid MIT Kerberos Team Security Contact sub 2048g/3A91A276 2008-01-18 [expires: 2009-02-01] As part of our effort to improve our vendor coordination process, please tell us which releases of MIT krb5 you use in your products, as well as which components. ====================================================================== *** CONFIDENTIAL PRERELEASE VULNERABILITY INFORMATION *** DRAFT - DO NOT PUBLISH - DRAFT - DO NOT PUBLISH - DRAFT - DO NOT PUBLISH MITKRB5-SA-2008-001 MIT krb5 Security Advisory 2008-001 Original release: YYYY-MM-DD Last update: YYYY-MM-DD Topic: double-free, uninitialized data vulnerabilities in krb5kdc CVE-2008-0062 VU#NNNNNN Use of a null or dangling pointer in the MIT Kerberos KDC can result in a crash or double-free, and may leak portions of process memory to an attacker. CVSSv2 Vector: AV:N/AC:M/Au:N/C:P/I:P/A:C/E:P/RL:O/RC:C CVSSv2 Base Score: 9.3 Access Vector: Network Access Complexity: Medium Authentication: None Confidentiality Impact: Complete Integrity Impact: Complete Availability Impact: Complete CVSSv2 Temporal Score: 6.5 Exploitability: Proof-of-Concept Remediation Level: Official Fix Report Confidence: Confirmed CVE-2008-0063 VU#NNNNNN Uninitialized stack values cause re-use of a small window of previous stack values to be interpreted as message content. Some of the "content" may be returned to the attacker as part of an error response. CVSSv2 Vector: AV:N/AC:M/Au:N/C:P/I:N/A:N/E:P/RL:O/RC:C CVSSv2 Base Score: 4.3 Access Vector: Network Access Complexity: Medium Authentication: None Confidentiality Impact: Partial Integrity Impact: None Availability Impact: None CVSSv2 Temporal Score: 3.4 Exploitability: Proof-of-Concept Remediation Level: Official Fix Report Confidence: Confirmed SUMMARY ======= When Kerberos 4 support is enabled in the MIT Kerberos 5 KDC, malformed messages may trigger two bugs: CVE-2008-0062: A global variable holding a pointer to the message to be sent back to the client is only set for two recognized krb4 message types, but may be used (and freed) in additional cases, resulting in use of a null or dangling pointer. CVE-2008-0063: The incoming krb4 message is copied into a fixed-size buffer on the stack, but the remainder of the buffer is left untouched, and the bounds checks use the size of the buffer, not the size of the data copied into it. By default, Kerberos 4 support is compiled in but not enabled in recent versions, and these bugs are not exposed unless Kerberos 4 support is enabled. These are implementation bugs, not protocol defects. IMPACT ====== CVE-2008-0062: An unauthenticated remote attacker may cause a krb4-enabled KDC to crash, expose information, or execute arbitrary code. Successful exploitation of this vulnerability could compromise the Kerberos key database and host security on the KDC host. CVE-2008-0063: An unauthenticated remote attacker may cause a krb4-enabled KDC to expose information. It is theoretically possible for the exposed information to include secret key data on some platforms. AFFECTED SOFTWARE ================= MIT Kerberos 5 version 1.6.3 KDC, and probably all earlier versions, when krb4 support is compiled in and enabled. (The krb4 support is disabled by default in recent releases.) No client or application server programs are affected. FIXES ===== * Apply the following patch: Index: src/kdc/dispatch.c =================================================================== --- src/kdc/dispatch.c (revision 20192) +++ src/kdc/dispatch.c (working copy) @@ -1,7 +1,7 @@ /* * kdc/dispatch.c * - * Copyright 1990 by the Massachusetts Institute of Technology. + * Copyright 1990, 2007 by the Massachusetts Institute of Technology. * * Export of this software from the United States of America may * require a specific license from the United States Government. @@ -107,7 +107,7 @@ retval = KRB5KRB_AP_ERR_MSG_TYPE; #ifndef NOCACHE /* put the response into the lookaside buffer */ - if (!retval) + if (!retval && *response != NULL) kdc_insert_lookaside(pkt, *response); #endif Index: src/kdc/kerberos_v4.c =================================================================== --- src/kdc/kerberos_v4.c (revision 20192) +++ src/kdc/kerberos_v4.c (working copy) @@ -1,7 +1,7 @@ /* * kdc/kerberos_v4.c * - * Copyright 1985, 1986, 1987, 1988,1991 by the Massachusetts Institute + * Copyright 1985, 1986, 1987, 1988,1991,2007 by the Massachusetts Institute * of Technology. * All Rights Reserved. * @@ -87,11 +87,6 @@ #define MSB_FIRST 0 /* 68000, IBM RT/PC */ #define LSB_FIRST 1 /* Vax, PC8086 */ -int f; - -/* XXX several files in libkdb know about this */ -char *progname; - #ifndef BACKWARD_COMPAT static Key_schedule master_key_schedule; static C_Block master_key; @@ -143,10 +138,8 @@ #include "com_err.h" #include "extern.h" /* to pick up master_princ */ -static krb5_data *response; - -void kerberos_v4 (struct sockaddr_in *, KTEXT); -void kerb_err_reply (struct sockaddr_in *, KTEXT, long, char *); +static krb5_data *kerberos_v4 (struct sockaddr_in *, KTEXT); +static krb5_data *kerb_err_reply (struct sockaddr_in *, KTEXT, long, char *); static int set_tgtkey (char *, krb5_kvno, krb5_boolean); /* Attributes converted from V5 to V4 - internal representation */ @@ -262,12 +255,12 @@ (void) klog(L_KRB_PERR, "V4 request too long."); return KRB5KRB_ERR_FIELD_TOOLONG; } + memset( &v4_pkt, 0, sizeof(v4_pkt)); v4_pkt.length = pkt->length; v4_pkt.mbz = 0; memcpy( v4_pkt.dat, pkt->data, pkt->length); - kerberos_v4( &client_sockaddr, &v4_pkt); - *resp = response; + *resp = kerberos_v4( &client_sockaddr, &v4_pkt); return(retval); } @@ -300,19 +293,20 @@ } static -int krb4_sendto(int s, const char *msg, int len, int flags, - const struct sockaddr *to, int to_len) +krb5_data *make_response(const char *msg, int len) { + krb5_data *response; + if ( !(response = (krb5_data *) malloc( sizeof *response))) { - return ENOMEM; + return 0; } if ( !(response->data = (char *) malloc( len))) { krb5_free_data(kdc_context, response); - return ENOMEM; + return 0; } response->length = len; memcpy( response->data, msg, len); - return( 0); + return response; } static void hang(void) @@ -586,7 +580,7 @@ *cp = 0; } -void +static krb5_data * kerberos_v4(struct sockaddr_in *client, KTEXT pkt) { static KTEXT_ST rpkt_st; @@ -599,8 +593,8 @@ KTEXT auth = &auth_st; AUTH_DAT ad_st; AUTH_DAT *ad = &ad_st; + krb5_data *response = 0; - static struct in_addr client_host; static int msg_byte_order; static int swap_bytes; @@ -637,8 +631,7 @@ inet_ntoa(client_host)); /* send an error reply */ req_name_ptr = req_inst_ptr = req_realm_ptr = ""; - kerb_err_reply(client, pkt, KERB_ERR_PKT_VER, lt); - return; + return kerb_err_reply(client, pkt, KERB_ERR_PKT_VER, lt); } /* check packet version */ @@ -648,8 +641,7 @@ KRB_PROT_VERSION, req_version, 0); /* send an error reply */ req_name_ptr = req_inst_ptr = req_realm_ptr = ""; - kerb_err_reply(client, pkt, KERB_ERR_PKT_VER, lt); - return; + return kerb_err_reply(client, pkt, KERB_ERR_PKT_VER, lt); } msg_byte_order = req_msg_type & 1; @@ -707,10 +699,10 @@ if ((i = check_princ(req_name_ptr, req_inst_ptr, 0, &a_name_data, &k5key, 0, &ck5life))) { - kerb_err_reply(client, pkt, i, "check_princ failed"); + response = kerb_err_reply(client, pkt, i, "check_princ failed"); a_name_data.key_low = a_name_data.key_high = 0; krb5_free_keyblock_contents(kdc_context, &k5key); - return; + return response; } /* don't use k5key for client */ krb5_free_keyblock_contents(kdc_context, &k5key); @@ -722,11 +714,11 @@ /* this does all the checking */ if ((i = check_princ(service, instance, lifetime, &s_name_data, &k5key, 1, &sk5life))) { - kerb_err_reply(client, pkt, i, "check_princ failed"); + response = kerb_err_reply(client, pkt, i, "check_princ failed"); a_name_data.key_high = a_name_data.key_low = 0; s_name_data.key_high = s_name_data.key_low = 0; krb5_free_keyblock_contents(kdc_context, &k5key); - return; + return response; } /* Bound requested lifetime with service and user */ v4req_end = krb_life_to_time(kerb_time.tv_sec, req_life); @@ -797,8 +789,7 @@ rpkt = create_auth_reply(req_name_ptr, req_inst_ptr, req_realm_ptr, req_time_ws, 0, a_name_data.exp_date, a_name_data.key_version, ciph); - krb4_sendto(f, (char *) rpkt->dat, rpkt->length, 0, - (struct sockaddr *) client, sizeof (struct sockaddr_in)); + response = make_response((char *) rpkt->dat, rpkt->length); memset(&a_name_data, 0, sizeof(a_name_data)); memset(&s_name_data, 0, sizeof(s_name_data)); break; @@ -824,9 +815,8 @@ lt = klog(L_KRB_PERR, "APPL request with realm length too long from %s", inet_ntoa(client_host)); - kerb_err_reply(client, pkt, RD_AP_INCON, - "realm length too long"); - return; + return kerb_err_reply(client, pkt, RD_AP_INCON, + "realm length too long"); } auth->length += (int) *(pkt->dat + auth->length) + @@ -835,9 +825,8 @@ lt = klog(L_KRB_PERR, "APPL request with funky tkt or req_id length from %s", inet_ntoa(client_host)); - kerb_err_reply(client, pkt, RD_AP_INCON, - "funky tkt or req_id length"); - return; + return kerb_err_reply(client, pkt, RD_AP_INCON, + "funky tkt or req_id length"); } memcpy(auth->dat, pkt->dat, auth->length); @@ -848,18 +837,16 @@ if ((!allow_v4_crossrealm)&&strcmp(tktrlm, local_realm) != 0) { lt = klog(L_ERR_UNK, "Cross realm ticket from %s denied by policy,", tktrlm); - kerb_err_reply(client, pkt, - KERB_ERR_PRINCIPAL_UNKNOWN, lt); - return; + return kerb_err_reply(client, pkt, + KERB_ERR_PRINCIPAL_UNKNOWN, lt); } if (set_tgtkey(tktrlm, kvno, 0)) { - lt = klog(L_ERR_UNK, + lt = klog(L_ERR_UNK, "FAILED set_tgtkey realm %s, kvno %d. Host: %s ", tktrlm, kvno, inet_ntoa(client_host)); /* no better error code */ - kerb_err_reply(client, pkt, - KERB_ERR_PRINCIPAL_UNKNOWN, lt); - return; + return kerb_err_reply(client, pkt, + KERB_ERR_PRINCIPAL_UNKNOWN, lt); } kerno = krb_rd_req(auth, "krbtgt", tktrlm, client_host.s_addr, ad, 0); @@ -869,9 +856,8 @@ "FAILED 3des set_tgtkey realm %s, kvno %d. Host: %s ", tktrlm, kvno, inet_ntoa(client_host)); /* no better error code */ - kerb_err_reply(client, pkt, - KERB_ERR_PRINCIPAL_UNKNOWN, lt); - return; + return kerb_err_reply(client, pkt, + KERB_ERR_PRINCIPAL_UNKNOWN, lt); } kerno = krb_rd_req(auth, "krbtgt", tktrlm, client_host.s_addr, ad, 0); @@ -881,8 +867,7 @@ klog(L_ERR_UNK, "FAILED krb_rd_req from %s: %s", inet_ntoa(client_host), krb_get_err_text(kerno)); req_name_ptr = req_inst_ptr = req_realm_ptr = ""; - kerb_err_reply(client, pkt, kerno, "krb_rd_req failed"); - return; + return kerb_err_reply(client, pkt, kerno, "krb_rd_req failed"); } ptr = (char *) pkt->dat + auth->length; @@ -904,22 +889,21 @@ req_realm_ptr = ad->prealm; if (strcmp(ad->prealm, tktrlm)) { - kerb_err_reply(client, pkt, KERB_ERR_PRINCIPAL_UNKNOWN, - "Can't hop realms"); - return; + return kerb_err_reply(client, pkt, KERB_ERR_PRINCIPAL_UNKNOWN, + "Can't hop realms"); } if (!strcmp(service, "changepw")) { - kerb_err_reply(client, pkt, KERB_ERR_PRINCIPAL_UNKNOWN, - "Can't authorize password changed based on TGT"); - return; + return kerb_err_reply(client, pkt, KERB_ERR_PRINCIPAL_UNKNOWN, + "Can't authorize password changed based on TGT"); } kerno = check_princ(service, instance, req_life, &s_name_data, &k5key, 1, &sk5life); if (kerno) { - kerb_err_reply(client, pkt, kerno, "check_princ failed"); + response = kerb_err_reply(client, pkt, kerno, + "check_princ failed"); s_name_data.key_high = s_name_data.key_low = 0; krb5_free_keyblock_contents(kdc_context, &k5key); - return; + return response; } /* Bound requested lifetime with service and user */ v4endtime = krb_life_to_time((KRB4_32)ad->time_sec, ad->life); @@ -975,8 +959,7 @@ rpkt = create_auth_reply(ad->pname, ad->pinst, ad->prealm, time_ws, 0, 0, 0, ciph); - krb4_sendto(f, (char *) rpkt->dat, rpkt->length, 0, - (struct sockaddr *) client, sizeof (struct sockaddr_in)); + response = make_response((char *) rpkt->dat, rpkt->length); memset(&s_name_data, 0, sizeof(s_name_data)); break; } @@ -1001,6 +984,7 @@ break; } } + return response; } @@ -1010,7 +994,7 @@ * client. */ -void +static krb5_data * kerb_err_reply(struct sockaddr_in *client, KTEXT pkt, long int err, char *string) { static KTEXT_ST e_pkt_st; @@ -1021,9 +1005,7 @@ strncat(e_msg, string, sizeof(e_msg) - 1 - 19); cr_err_reply(e_pkt, req_name_ptr, req_inst_ptr, req_realm_ptr, req_time_ws, err, e_msg); - krb4_sendto(f, (char *) e_pkt->dat, e_pkt->length, 0, - (struct sockaddr *) client, sizeof (struct sockaddr_in)); - + return make_response((char *) e_pkt->dat, e_pkt->length); } static int Index: src/kdc/network.c =================================================================== --- src/kdc/network.c (revision 20192) +++ src/kdc/network.c (working copy) @@ -1,7 +1,7 @@ /* * kdc/network.c * - * Copyright 1990,2000 by the Massachusetts Institute of Technology. + * Copyright 1990,2000,2007 by the Massachusetts Institute of Technology. * * Export of this software from the United States of America may * require a specific license from the United States Government. @@ -747,6 +747,8 @@ com_err(prog, retval, "while dispatching (udp)"); return; } + if (response == NULL) + return; cc = sendto(port_fd, response->data, (socklen_t) response->length, 0, (struct sockaddr *)&saddr, saddr_len); if (cc == -1) { * These bugs will be fixed in the next release. REFERENCES ========== This announcement is posted at: http://web.mit.edu/kerberos/advisories/MITKRB5-SA-2008-001.txt This announcement and related security advisories may be found on the MIT Kerberos security advisory page at: http://web.mit.edu/kerberos/advisories/index.html The main MIT Kerberos web page is at: http://web.mit.edu/kerberos/index.html CVSSv2: http://www.first.org/cvss/cvss-guide.html http://nvd.nist.gov/cvss.cfm?calculator&adv&version=2 CVE: CVE-YYYY-NNNN http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-YYYY-NNNN CERT: VU#NNNNNN http://www.kb.cert.org/vuls/id/NNNNNN CONTACT ======= The MIT Kerberos Team security contact address is . When sending sensitive information, please PGP-encrypt it using the following key: pub 1024D/2915318C 2008-01-18 [expires: 2009-02-01] uid MIT Kerberos Team Security Contact sub 2048g/3A91A276 2008-01-18 [expires: 2009-02-01] DETAILS ======= CVE-2008-0062: If a bogus Kerberos 4 message (i.e., a message with the first byte having the value 4, but the second byte not describing one of the message types supported by the KDC) is received by the KDC, and there has been no previous Kerberos 4 traffic, a null pointer dereference will result, likely crashing the KDC. If there has been valid Kerberos 4 traffic already, a dangling pointer will be used to locate the message to send to the client; it may resend a previously generated response, send some other arbitrary chunk of process memory, perhaps including secret key data, or crash the process by attempting to access an invalid address. If the process doesn't crash, random addresses will be passed to free(), likely corrupting the free pool, and potentially leading to later crashes, data corruption, jumps to arbitrary locations in process memory, etc. The KDC normally runs without write access to its database, so it is not likely to corrupt the database, except insofar as arbitrary code execution could theoretically corrupt anything the process has access to on the system. CVE-2008-0063: If a Kerberos 4 message is truncated, previous contents of the stack may be used in place of the missing portions of the message. (Note that if the message type is missing, and the data read from the stack is not a recognized message type, this may indirectly trigger CVE-2008-0062 described above.) Several strings are read from the "message" as parts of principal names; these strings are limited to 40 bytes or the next ASCII NUL found in the buffer. If the KDC returns an error message indicating that a principal name is not found in its database, the principal name is included in the error message, and some of the old stack content may be there. If the previously handled message was a valid Kerberos 4 message, parts of that message may be re-used for the new message; this wouldn't expose any data that wouldn't have been visible on the local network. If the previously handled message was a Kerberos 5 message, the values overlaid by the buffer are likely to be old argument pointers, saved registers, return addresses, and so forth. However, since stack contents and layout are highly dependent on the platform and compiler, it is impossible to assert that no secret key data may be leaked into the exposed stack regions on any platform. REVISION HISTORY ================ YYYY-MM-DD original release Copyright (C) 2008 Massachusetts Institute of Technology