OSEC

Neohapsis is currently accepting applications for employment. For more information, please visit our website www.neohapsis.com or email hr@neohapsis.com
 
Subject: Security Advisory: MULTIPLE DENIAL OF SERVICE VULNERABILITIES IN KRB4 KDC
From: Tom Yu (tlyuMIT.EDU)
Date: Fri Jun 09 2000 - 14:08:59 CDT


-----BEGIN PGP SIGNED MESSAGE-----

        MULTIPLE DENIAL OF SERVICE VULNERABILITIES IN KRB4 KDC

2000-06-09

SUMMARY:

A buffer overrun capable of creating a denial of service exists in
implementations of Kerberos 4 KDC programs. This is IN ADDITION to
the krb_rd_req() vulnerability that was previously announced. Many
Kerberos 4 KDC implementations derived from MIT sources are believed
to be vulnerable.

Another denial of service vulnerability exists in the krb5-1.1.x KDC
implementations (and krb5-1.2-beta1, but not krb5-1.0.x) that can
cause the Kerberos 4 compatibility code to perform a double-free,
possibly resulting in a crash of the KDC process.

IMPACT:

A remote user may be able to cause the KDC to issue bogus tickets, or
to return an error of the form "principal unknown" for all principals,
necessitating a restart of the KDC to resume proper operation.

A remote user may also be able to cause a krb5-1.1.x KDC to experience
a segmentation violation or malloc pool corruption, causing the KDC
process to crash.

DETAILS:

A static buffer can be overrun by corrupt requests sent to a KDC
process. It is believed that this overrun does not lead to a root
compromise, but it can lead to a denial of service by corrupting
long-term state in the KDC process.

The krb5-1.1.x KDC contains in its Kerberos 4 compatibility mode some
code which tickles a memory management bug in the library. This can
result in a double-free of memory and corruption of the malloc pool,
possibly leading to a crash of the KDC. Whether or not a crash occurs
depends on the idiosyncrasies of the malloc implementation used.

VULNERABLE DISTRIBUTIONS:

Source distributions which may contain vulnerable code include:

        MIT Kerberos 5 releases krb5-1.0.x, krb5-1.1, krb5-1.1.1

        MIT Kerberos 4 patch 10, and probably earlier releases as well

        KerbNet (Cygnus implementation of Kerberos 5)

        Cygnus Network Security (CNS -- Cygnus implementation of
                Kerberos 4)

        KTH-krb4 before version 0.10

NON-VULNERABLE DISTRIBUTIONS:

Source distributions that are believed not to be vulnerable include:

        KTH-krb4 -- version 0.10 and above

        Heimdal (KTH implementation of Kerberos 5) -- any version

FIXES:

The best course of action is to patch your KDC. If you have not done
so already, install the patches to deal with the krb_rd_req()
vulnerability that was previously announced. Patches and the original
announcement may be found at:

        http://web.mit.edu/kerberos/www/advisories/index.html

MIT will soon release krb5-1.2, which will have these changes
incorporated. The krb5-1.2-beta1 release does not have this fix,
though the upcoming krb5-1.2-beta2 release, tentatively scheduled for
the week of June 5, will. The two recent beta patch releases,
krb5-1.0.7-beta2 and krb5-1.1.2-beta1, which were intended to fix the
krb4 buffer overrun problems, have not been patched for this problem
yet.

The following patches for this bug will be posted to the
aforementioned security advisories web page once this announcement is
made public.

PATCHES AGAINST krb5-1.0.x:

These patches are against krb5-1.0.7-beta1, but will probably apply
cleanly against krb5-1.0.6 and earlier releases as well.

These patches also will be made available at:

        http://web.mit.edu/kerberos/www/advisories/krb4kdc_10x_patch.txt

Index: kerberos_v4.c
===================================================================
RCS file: /cvs/krbdev/krb5/src/kdc/kerberos_v4.c,v
retrieving revision 5.56.4.3
diff -c -r5.56.4.3 kerberos_v4.c
*** kerberos_v4.c 1998/05/10 03:02:55 5.56.4.3
- --- kerberos_v4.c 2000/05/19 19:38:17
***************
*** 173,183 ****
          return(retval);

      if (!*local_realm) { /* local-realm name already set up */
- - /* XXX assumes realm is null-terminated! */
          lrealm = master_princ->realm.data;
! if (strlen(lrealm) < sizeof(local_realm))
! strcpy(local_realm, lrealm);
! else
              retval = KRB5_CONFIG_NOTENUFSPACE;
      }
      /* convert client_fulladdr to client_sockaddr:
- --- 173,183 ----
          return(retval);

      if (!*local_realm) { /* local-realm name already set up */
          lrealm = master_princ->realm.data;
! if (master_princ->realm.length < sizeof(local_realm)) {
! memcpy(local_realm, lrealm, master_princ->realm.length);
! local_realm[master_princ->realm.length] = '\0';
! } else
              retval = KRB5_CONFIG_NOTENUFSPACE;
      }
      /* convert client_fulladdr to client_sockaddr:
***************
*** 196,201 ****
- --- 196,202 ----
              return KRB5KRB_ERR_FIELD_TOOLONG;
      }
      v4_pkt.length = pkt->length;
+ v4_pkt.mbz = 0;
      memcpy( v4_pkt.dat, pkt->data, pkt->length);

      kerberos_v4( &client_sockaddr, &v4_pkt);
***************
*** 507,512 ****
- --- 508,516 ----

      req_act_vno = req_version;

+ /* set these to point to something safe */
+ req_name_ptr = req_inst_ptr = req_realm_ptr = "";
+
      /* check packet version */
      if (req_version != KRB_PROT_VERSION) {
          lt = klog(L_KRB_PERR,
***************
*** 574,580 ****

              if ((i = check_princ(req_name_ptr, req_inst_ptr, 0,
                                   &a_name_data))) {
! kerb_err_reply(client, pkt, i, lt);
                  a_name_data.key_low = a_name_data.key_high = 0;
                  return;
              }
- --- 578,584 ----

              if ((i = check_princ(req_name_ptr, req_inst_ptr, 0,
                                   &a_name_data))) {
! kerb_err_reply(client, pkt, i, "check_princ failed");
                  a_name_data.key_low = a_name_data.key_high = 0;
                  return;
              }
***************
*** 586,592 ****
              /* this does all the checking */
              if ((i = check_princ(service, instance, lifetime,
                                   &s_name_data))) {
! kerb_err_reply(client, pkt, i, lt);
                  a_name_data.key_high = a_name_data.key_low = 0;
                  s_name_data.key_high = s_name_data.key_low = 0;
                  return;
- --- 590,596 ----
              /* this does all the checking */
              if ((i = check_princ(service, instance, lifetime,
                                   &s_name_data))) {
! 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;
                  return;
***************
*** 664,681 ****
              tk->length = 0;
              k_flags = 0; /* various kerberos flags */

              auth->length = 4 + strlen((char *)pkt->dat + 3);
              auth->length += (int) *(pkt->dat + auth->length) +
                  (int) *(pkt->dat + auth->length + 1) + 2;

              memcpy(auth->dat, pkt->dat, auth->length);

              strncpy(tktrlm, (char *)auth->dat + 3, REALM_SZ);
              if (set_tgtkey(tktrlm)) {
                  lt = klog(L_ERR_UNK,
                      "FAILED realm %s unknown. Host: %s ",
                            tktrlm, inet_ntoa(client_host));
! kerb_err_reply(client, pkt, kerno, lt);
                  return;
              }
              kerno = krb_rd_req(auth, "ktbtgt", tktrlm, client_host.s_addr,
- --- 668,706 ----
              tk->length = 0;
              k_flags = 0; /* various kerberos flags */

+ auth->mbz = 0; /* pkt->mbz already zeroed */
              auth->length = 4 + strlen((char *)pkt->dat + 3);
+ if (auth->length + 1 > MAX_KTXT_LEN) {
+ 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;
+ }
+
              auth->length += (int) *(pkt->dat + auth->length) +
                  (int) *(pkt->dat + auth->length + 1) + 2;
+ if (auth->length > MAX_KTXT_LEN) {
+ 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;
+ }

              memcpy(auth->dat, pkt->dat, auth->length);

              strncpy(tktrlm, (char *)auth->dat + 3, REALM_SZ);
+ tktrlm[REALM_SZ-1] = '\0';
              if (set_tgtkey(tktrlm)) {
                  lt = klog(L_ERR_UNK,
                      "FAILED realm %s unknown. Host: %s ",
                            tktrlm, inet_ntoa(client_host));
! /* no better error code */
! kerb_err_reply(client, pkt,
! KERB_ERR_PRINCIPAL_UNKNOWN, lt);
                  return;
              }
              kerno = krb_rd_req(auth, "ktbtgt", tktrlm, client_host.s_addr,
***************
*** 720,726 ****
              kerno = check_princ(service, instance, req_life,
                  &s_name_data);
              if (kerno) {
! kerb_err_reply(client, pkt, kerno, lt);
                  return;
              }
              /* Bound requested lifetime with service and user */
- --- 745,751 ----
              kerno = check_princ(service, instance, req_life,
                  &s_name_data);
              if (kerno) {
! kerb_err_reply(client, pkt, kerno, "check_princ failed");
                  return;
              }
              /* Bound requested lifetime with service and user */
***************
*** 844,850 ****
      static char e_msg[128];

      strcpy(e_msg, "\nKerberos error -- ");
! strcat(e_msg, string);
      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,
- --- 869,875 ----
      static char e_msg[128];

      strcpy(e_msg, "\nKerberos error -- ");
! 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,
***************
*** 989,995 ****
      kdb_encrypt_key(key, key, master_key,
                      master_key_schedule, DECRYPT);
      krb_set_key((char *) key, 0);
! strcpy(lastrealm, r);
      return (KSUCCESS);
  }

- --- 1014,1021 ----
      kdb_encrypt_key(key, key, master_key,
                      master_key_schedule, DECRYPT);
      krb_set_key((char *) key, 0);
! strncpy(lastrealm, r, sizeof(lastrealm) - 1);
! lastrealm[sizeof(lastrealm) - 1] = '\0';
      return (KSUCCESS);
  }

PATCHES AGAINST krb5-1.1.1:

These patches should apply cleanly against krb5-1.2-beta1 as well.
These patches will also be made available at:

        http://web.mit.edu/kerberos/www/advisories/krb4kdc_111_patch.txt

Index: krb5/src/kdc/kerberos_v4.c
diff -c krb5/src/kdc/kerberos_v4.c:5.65.2.2 krb5/src/kdc/kerberos_v4.c:5.65.2.3
*** krb5/src/kdc/kerberos_v4.c:5.65.2.2 Wed Sep 22 20:47:22 1999
- --- krb5/src/kdc/kerberos_v4.c Mon Jun 5 13:58:34 2000
***************
*** 233,243 ****
          return(retval);

      if (!*local_realm) { /* local-realm name already set up */
- - /* XXX assumes realm is null-terminated! */
          lrealm = master_princ->realm.data;
! if (strlen(lrealm) < sizeof(local_realm))
! strcpy(local_realm, lrealm);
! else
              retval = KRB5_CONFIG_NOTENUFSPACE;
      }
      /* convert client_fulladdr to client_sockaddr:
- --- 233,243 ----
          return(retval);

      if (!*local_realm) { /* local-realm name already set up */
          lrealm = master_princ->realm.data;
! if (master_princ->realm.length < sizeof(local_realm)) {
! memcpy(local_realm, lrealm, master_princ->realm.length);
! local_realm[master_princ->realm.length] = '\0';
! } else
              retval = KRB5_CONFIG_NOTENUFSPACE;
      }
      /* convert client_fulladdr to client_sockaddr:
***************
*** 256,261 ****
- --- 256,262 ----
              return KRB5KRB_ERR_FIELD_TOOLONG;
      }
      v4_pkt.length = pkt->length;
+ v4_pkt.mbz = 0;
      memcpy( v4_pkt.dat, pkt->data, pkt->length);

      kerberos_v4( &client_sockaddr, &v4_pkt);
***************
*** 293,299 ****
      case L_APPL_REQ:
          strcpy(log_text, "PROCESS_V4:");
          vsprintf(log_text+strlen(log_text), format, pvar);
! krb5_klog_syslog(logpri, log_text);
      /* ignore the other types... */
      }
      va_end(pvar);
- --- 294,300 ----
      case L_APPL_REQ:
          strcpy(log_text, "PROCESS_V4:");
          vsprintf(log_text+strlen(log_text), format, pvar);
! krb5_klog_syslog(logpri, "%s", log_text);
      /* ignore the other types... */
      }
      va_end(pvar);
***************
*** 622,627 ****
- --- 623,631 ----

      req_act_vno = req_version;

+ /* set these to point to something safe */
+ req_name_ptr = req_inst_ptr = req_realm_ptr = "";
+
      /* check if disabled, but we tell client */
      if (kdc_v4 == KDC_V4_DISABLE) {
          lt = klog(L_KRB_PERR,
***************
*** 700,706 ****

              if ((i = check_princ(req_name_ptr, req_inst_ptr, 0,
                                   &a_name_data, &k5key, 0))) {
! kerb_err_reply(client, pkt, i, lt);
                  a_name_data.key_low = a_name_data.key_high = 0;
                  krb5_free_keyblock_contents(kdc_context, &k5key);
                  return;
- --- 704,710 ----

              if ((i = check_princ(req_name_ptr, req_inst_ptr, 0,
                                   &a_name_data, &k5key, 0))) {
! 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;
***************
*** 715,721 ****
              /* this does all the checking */
              if ((i = check_princ(service, instance, lifetime,
                                   &s_name_data, &k5key, 1))) {
! kerb_err_reply(client, pkt, i, lt);
                  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);
- --- 719,725 ----
              /* this does all the checking */
              if ((i = check_princ(service, instance, lifetime,
                                   &s_name_data, &k5key, 1))) {
! 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);
***************
*** 806,824 ****
              tk->length = 0;
              k_flags = 0; /* various kerberos flags */

              auth->length = 4 + strlen((char *)pkt->dat + 3);
              auth->length += (int) *(pkt->dat + auth->length) +
                  (int) *(pkt->dat + auth->length + 1) + 2;

              memcpy(auth->dat, pkt->dat, auth->length);

              strncpy(tktrlm, (char *)auth->dat + 3, REALM_SZ);
              kvno = (krb5_kvno)auth->dat[2];
              if (set_tgtkey(tktrlm, kvno)) {
                  lt = klog(L_ERR_UNK,
                            "FAILED set_tgtkey realm %s, kvno %d. Host: %s ",
                            tktrlm, kvno, inet_ntoa(client_host));
! kerb_err_reply(client, pkt, kerno, lt);
                  return;
              }
              kerno = krb_rd_req(auth, "krbtgt", tktrlm, client_host.s_addr,
- --- 810,849 ----
              tk->length = 0;
              k_flags = 0; /* various kerberos flags */

+ auth->mbz = 0; /* pkt->mbz already zeroed */
              auth->length = 4 + strlen((char *)pkt->dat + 3);
+ if (auth->length + 1 > MAX_KTXT_LEN) {
+ 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;
+ }
+
              auth->length += (int) *(pkt->dat + auth->length) +
                  (int) *(pkt->dat + auth->length + 1) + 2;
+ if (auth->length > MAX_KTXT_LEN) {
+ 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;
+ }

              memcpy(auth->dat, pkt->dat, auth->length);

              strncpy(tktrlm, (char *)auth->dat + 3, REALM_SZ);
+ tktrlm[REALM_SZ-1] = '\0';
              kvno = (krb5_kvno)auth->dat[2];
              if (set_tgtkey(tktrlm, kvno)) {
                  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;
              }
              kerno = krb_rd_req(auth, "krbtgt", tktrlm, client_host.s_addr,
***************
*** 863,869 ****
              kerno = check_princ(service, instance, req_life,
                                  &s_name_data, &k5key, 1);
              if (kerno) {
! kerb_err_reply(client, pkt, kerno, lt);
                  s_name_data.key_high = s_name_data.key_low = 0;
                  krb5_free_keyblock_contents(kdc_context, &k5key);
                  return;
- --- 888,894 ----
              kerno = check_princ(service, instance, req_life,
                                  &s_name_data, &k5key, 1);
              if (kerno) {
! 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;
***************
*** 968,974 ****
      static char e_msg[128];

      strcpy(e_msg, "\nKerberos error -- ");
! strcat(e_msg, string);
      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,
- --- 993,999 ----
      static char e_msg[128];

      strcpy(e_msg, "\nKerberos error -- ");
! 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,
***************
*** 1127,1133 ****

      if (!K4KDC_ENCTYPE_OK(k5key.enctype)) {
          krb_set_key_krb5(kdc_context, &k5key);
! strcpy(lastrealm, r);
          last_kvno = kvno;
      } else {
          /* unseal tgt key from master key */
- --- 1152,1159 ----

      if (!K4KDC_ENCTYPE_OK(k5key.enctype)) {
          krb_set_key_krb5(kdc_context, &k5key);
! strncpy(lastrealm, r, sizeof(lastrealm) - 1);
! lastrealm[sizeof(lastrealm) - 1] = '\0';
          last_kvno = kvno;
      } else {
          /* unseal tgt key from master key */
***************
*** 1136,1142 ****
          kdb_encrypt_key(key, key, master_key,
                          master_key_schedule, DECRYPT);
          krb_set_key((char *) key, 0);
! strcpy(lastrealm, r);
          last_kvno = kvno;
      }
      krb5_free_keyblock_contents(kdc_context, &k5key);
- --- 1162,1169 ----
          kdb_encrypt_key(key, key, master_key,
                          master_key_schedule, DECRYPT);
          krb_set_key((char *) key, 0);
! strncpy(lastrealm, r, sizeof(lastrealm) - 1);
! lastrealm[sizeof(lastrealm) - 1] = '\0';
          last_kvno = kvno;
      }
      krb5_free_keyblock_contents(kdc_context, &k5key);
Index: krb5/src/lib/krb5/krb/kfree.c
diff -c krb5/src/lib/krb5/krb/kfree.c:5.3.4.1 krb5/src/lib/krb5/krb/kfree.c:5.3.4.2
*** krb5/src/lib/krb5/krb/kfree.c:5.3.4.1 Wed Sep 22 20:50:11 1999
- --- krb5/src/lib/krb5/krb/kfree.c Mon Jun 5 18:30:06 2000
***************
*** 36,42 ****
      if (val->contents)
          krb5_xfree(val->contents);
      krb5_xfree(val);
- - return;
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 36,41 ----
***************
*** 52,58 ****
          krb5_xfree(*temp);
      }
      krb5_xfree(val);
- - return;
  }

- --- 51,56 ----
***************
*** 64,70 ****
      if (val->enc_part.ciphertext.data)
          krb5_xfree(val->enc_part.ciphertext.data);
      krb5_xfree(val);
- - return;
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 62,67 ----
***************
*** 77,83 ****
      if (val->authenticator.ciphertext.data)
          krb5_xfree(val->authenticator.ciphertext.data);
      krb5_xfree(val);
- - return;
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 74,79 ----
***************
*** 88,94 ****
      if (val->subkey)
          krb5_free_keyblock(context, val->subkey);
      krb5_xfree(val);
- - return;
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 84,89 ----
***************
*** 96,110 ****
      krb5_context context;
      krb5_authenticator FAR *val;
  {
! if (val->checksum)
          krb5_free_checksum(context, val->checksum);
! if (val->client)
          krb5_free_principal(context, val->client);
! if (val->subkey)
          krb5_free_keyblock(context, val->subkey);
! if (val->authorization_data)
! krb5_free_authdata(context, val->authorization_data);
! return;
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 91,112 ----
      krb5_context context;
      krb5_authenticator FAR *val;
  {
! if (val->checksum) {
          krb5_free_checksum(context, val->checksum);
! val->checksum = 0;
! }
! if (val->client) {
          krb5_free_principal(context, val->client);
! val->client = 0;
! }
! if (val->subkey) {
          krb5_free_keyblock(context, val->subkey);
! val->subkey = 0;
! }
! if (val->authorization_data) {
! krb5_free_authdata(context, val->authorization_data);
! val->authorization_data = 0;
! }
  }

  KRB5_DLLIMP void KRB5_CALLCONV
***************
*** 120,126 ****
          krb5_xfree(*temp);
      }
      krb5_xfree(val);
- - return;
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 122,127 ----
***************
*** 128,143 ****
      krb5_context context;
      krb5_authenticator FAR *val;
  {
! if (val->checksum)
! krb5_free_checksum(context, val->checksum);
! if (val->client)
! krb5_free_principal(context, val->client);
! if (val->subkey)
! krb5_free_keyblock(context, val->subkey);
! if (val->authorization_data)
! krb5_free_authdata(context, val->authorization_data);
      krb5_xfree(val);
- - return;
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 129,136 ----
      krb5_context context;
      krb5_authenticator FAR *val;
  {
! krb5_free_authenticator_contents(context, val);
      krb5_xfree(val);
  }

  KRB5_DLLIMP void KRB5_CALLCONV
***************
*** 145,154 ****
      krb5_context context;
      register krb5_checksum *val;
  {
! if (val->contents)
! krb5_xfree(val->contents);
      krb5_xfree(val);
- - return;
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 138,145 ----
      krb5_context context;
      register krb5_checksum *val;
  {
! krb5_free_checksum_contents(context, val);
      krb5_xfree(val);
  }

  KRB5_DLLIMP void KRB5_CALLCONV
***************
*** 156,164 ****
      krb5_context context;
      register krb5_checksum *val;
  {
! if (val->contents)
          krb5_xfree(val->contents);
! return;
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 147,156 ----
      krb5_context context;
      register krb5_checksum *val;
  {
! if (val->contents) {
          krb5_xfree(val->contents);
! val->contents = 0;
! }
  }

  KRB5_DLLIMP void KRB5_CALLCONV
***************
*** 171,177 ****
      if (val->enc_part.ciphertext.data)
          krb5_xfree(val->enc_part.ciphertext.data);
      krb5_xfree(val);
- - return;
  }

  /*
- --- 163,168 ----
***************
*** 184,206 ****
      krb5_context context;
      krb5_creds FAR *val;
  {
! if (val->client)
          krb5_free_principal(context, val->client);
! if (val->server)
          krb5_free_principal(context, val->server);
      if (val->keyblock.contents) {
          memset((char *)val->keyblock.contents, 0, val->keyblock.length);
          krb5_xfree(val->keyblock.contents);
      }
! if (val->ticket.data)
          krb5_xfree(val->ticket.data);
! if (val->second_ticket.data)
          krb5_xfree(val->second_ticket.data);
! if (val->addresses)
          krb5_free_addresses(context, val->addresses);
! if (val->authdata)
          krb5_free_authdata(context, val->authdata);
! return;
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 175,209 ----
      krb5_context context;
      krb5_creds FAR *val;
  {
! if (val->client) {
          krb5_free_principal(context, val->client);
! val->client = 0;
! }
! if (val->server) {
          krb5_free_principal(context, val->server);
+ val->server = 0;
+ }
      if (val->keyblock.contents) {
          memset((char *)val->keyblock.contents, 0, val->keyblock.length);
          krb5_xfree(val->keyblock.contents);
+ val->keyblock.contents = 0;
      }
! if (val->ticket.data) {
          krb5_xfree(val->ticket.data);
! val->ticket.data = 0;
! }
! if (val->second_ticket.data) {
          krb5_xfree(val->second_ticket.data);
! val->second_ticket.data = 0;
! }
! if (val->addresses) {
          krb5_free_addresses(context, val->addresses);
! val->addresses = 0;
! }
! if (val->authdata) {
          krb5_free_authdata(context, val->authdata);
! val->authdata = 0;
! }
  }

  KRB5_DLLIMP void KRB5_CALLCONV
***************
*** 210,219 ****
  {
      register krb5_cred_info **temp;

! if (val->r_address)
! krb5_free_address(context, val->r_address);
! if (val->s_address)
! krb5_free_address(context, val->s_address);

      if (val->ticket_info) {
          for (temp = val->ticket_info; *temp; temp++) {
- --- 213,226 ----
  {
      register krb5_cred_info **temp;

! if (val->r_address) {
! krb5_free_address(context, val->r_address);
! val->r_address = 0;
! }
! if (val->s_address) {
! krb5_free_address(context, val->s_address);
! val->s_address = 0;
! }

      if (val->ticket_info) {
          for (temp = val->ticket_info; *temp; temp++) {
***************
*** 228,235 ****
              krb5_xfree((*temp));
          }
          krb5_xfree(val->ticket_info);
      }
- - return;
  }

- --- 235,242 ----
              krb5_xfree((*temp));
          }
          krb5_xfree(val->ticket_info);
+ val->ticket_info = 0;
      }
  }

***************
*** 240,246 ****
  {
      krb5_free_cred_contents(context, val);
      krb5_xfree(val);
- - return;
  }

- --- 247,252 ----
***************
*** 252,258 ****
      if (val->data)
          krb5_xfree(val->data);
      krb5_xfree(val);
- - return;
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 258,263 ----
***************
*** 260,268 ****
      krb5_context context;
      krb5_data FAR * val;
  {
! if (val->data)
          krb5_xfree(val->data);
! return;
  }

  void krb5_free_etype_info(context, info)
- --- 265,274 ----
      krb5_context context;
      krb5_data FAR * val;
  {
! if (val->data) {
          krb5_xfree(val->data);
! val->data = 0;
! }
  }

  void krb5_free_etype_info(context, info)
***************
*** 294,300 ****
      if (val->caddrs)
          krb5_free_addresses(context, val->caddrs);
      krb5_xfree(val);
- - return;
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 300,305 ----
***************
*** 313,319 ****
      if (val->authorization_data)
          krb5_free_authdata(context, val->authorization_data);
      krb5_xfree(val);
- - return;
  }

- --- 318,323 ----
***************
*** 331,337 ****
      if (val->e_data.data)
          krb5_xfree(val->e_data.data);
      krb5_xfree(val);
- - return;
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 335,340 ----
***************
*** 350,356 ****
      if (val->enc_part2)
          krb5_free_enc_kdc_rep_part(context, val->enc_part2);
      krb5_xfree(val);
- - return;
  }

- --- 353,358 ----
***************
*** 376,382 ****
      if (val->second_ticket)
          krb5_free_tickets(context, val->second_ticket);
      krb5_xfree(val);
- - return;
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 378,383 ----
***************
*** 387,394 ****
       if (key->contents) {
            memset(key->contents, 0, key->length);
            krb5_xfree(key->contents);
       }
- - return;
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 388,395 ----
       if (key->contents) {
            memset(key->contents, 0, key->length);
            krb5_xfree(key->contents);
+ key->contents = 0;
       }
  }

  KRB5_DLLIMP void KRB5_CALLCONV
***************
*** 398,404 ****
  {
      krb5_free_keyblock_contents(context, val);
      krb5_xfree(val);
- - return;
  }

- --- 399,404 ----
***************
*** 413,419 ****
      for (temp = val; *temp; temp++)
          krb5_xfree(*temp);
      krb5_xfree(val);
- - return;
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 413,418 ----
***************
*** 429,435 ****
          krb5_xfree(*temp);
      }
      krb5_xfree(val);
- - return;
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 428,433 ----
***************
*** 451,457 ****
      if (val->realm.data)
          krb5_xfree(val->realm.data);
      krb5_xfree(val);
- - return;
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 449,454 ----
***************
*** 462,468 ****
      if (val->enc_part.ciphertext.data)
          krb5_xfree(val->enc_part.ciphertext.data);
      krb5_xfree(val);
- - return;
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 459,464 ----
***************
*** 477,483 ****
      if (val->s_address)
          krb5_free_address(context, val->s_address);
      krb5_xfree(val);
- - return;
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 473,478 ----
***************
*** 488,494 ****
      if (val->element)
          krb5_free_pwd_sequences(context, val->element);
      krb5_xfree(val);
- - return;
  }

- --- 483,488 ----
***************
*** 497,507 ****
      krb5_context context;
      passwd_phrase_element FAR * FAR *val;
  {
! if ((*val)->passwd)
          krb5_xfree((*val)->passwd);
! if ((*val)->phrase)
          krb5_xfree((*val)->phrase);
! return;
  }

- --- 491,504 ----
      krb5_context context;
      passwd_phrase_element FAR * FAR *val;
  {
! if ((*val)->passwd) {
          krb5_xfree((*val)->passwd);
! (*val)->passwd = 0;
! }
! if ((*val)->phrase) {
          krb5_xfree((*val)->phrase);
! (*val)->phrase = 0;
! }
  }

***************
*** 519,525 ****
      if (val->checksum)
          krb5_free_checksum(context, val->checksum);
      krb5_xfree(val);
- - return;
  }

- --- 516,521 ----
***************
*** 535,541 ****
      if (val->enc_part2)
          krb5_free_enc_tkt_part(context, val->enc_part2);
      krb5_xfree(val);
- - return;
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 531,536 ----
***************
*** 548,554 ****
      for (temp = val; *temp; temp++)
          krb5_free_ticket(context, *temp);
      krb5_xfree(val);
- - return;
  }

- --- 543,548 ----
***************
*** 573,579 ****
      if (val->authenticator)
              krb5_free_authenticator(context, val->authenticator);
      krb5_xfree(val);
- - return;
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 567,572 ----
***************
*** 583,589 ****
  {
      if (val)
          krb5_xfree(val);
- - return;
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 576,581 ----
***************
*** 612,619 ****
          krb5_free_data_contents(ctx, &sc->sam_response_prompt);
      if (sc->sam_pk_for_sad.data)
          krb5_free_data_contents(ctx, &sc->sam_pk_for_sad);
! if (sc->sam_cksum.contents)
          krb5_xfree(sc->sam_cksum.contents);
  }

  KRB5_DLLIMP void KRB5_CALLCONV
- --- 604,613 ----
          krb5_free_data_contents(ctx, &sc->sam_response_prompt);
      if (sc->sam_pk_for_sad.data)
          krb5_free_data_contents(ctx, &sc->sam_pk_for_sad);
! if (sc->sam_cksum.contents) {
          krb5_xfree(sc->sam_cksum.contents);
+ sc->sam_cksum.contents = 0;
+ }
  }

  KRB5_DLLIMP void KRB5_CALLCONV
***************
*** 685,688 ****
          return;
      krb5_xfree(pa_enc_ts);
  }
- -
- --- 679,681 ----

FIXES FOR KTH-krb4:

If you are still running a version before 0.10, please upgrade to
1.0.1.

See the following URL for retrieving distributions:

        http://www.pdc.kth.se/kth-krb/

PATCHES AGAINST CNS:

These patches compile but have not been tested. They will also be
made available at:

        http://web.mit.edu/kerberos/www/advisories/krb4kdc_cns_patch.txt

*** kerberos.c.orig Sat Feb 24 05:43:44 1996
- --- kerberos.c Fri Jun 2 15:25:22 2000
***************
*** 358,363 ****
- --- 358,377 ----
  }

+ static void str_length_check(str, max_size)
+ char *str;
+ int max_size;
+ {
+ int i;
+ char *cp;
+
+ for (i=0, cp = str; i < max_size-1; i++, cp++) {
+ if (*cp == 0)
+ return;
+ }
+ *cp = 0;
+ }
+
  kerberos(client, pkt)
      struct sockaddr_in *client;
      KTEXT pkt;
***************
*** 397,402 ****
- --- 411,419 ----

      req_act_vno = req_version;

+ /* set these to point to something safe */
+ req_name_ptr = req_inst_ptr = req_realm_ptr = "";
+
      /* check packet version */
      if (req_version != KRB_PROT_VERSION) {
          lt = klog(L_KRB_PERR,
***************
*** 435,442 ****
- --- 452,462 ----

              /* set up and correct for byte order and alignment */
              req_name_ptr = (char *) pkt_a_name(pkt);
+ str_length_check(req_name_ptr, ANAME_SZ);
              req_inst_ptr = (char *) pkt_a_inst(pkt);
+ str_length_check(req_inst_ptr, INST_SZ);
              req_realm_ptr = (char *) pkt_a_realm(pkt);
+ str_length_check(req_realm_ptr, REALM_SZ);
              memcpy(&req_time_ws, pkt_time_ws(pkt), sizeof(req_time_ws));
              /* time has to be diddled */
              if (swap_bytes) {
***************
*** 460,466 ****

              if (i = check_princ(req_name_ptr, req_inst_ptr, 0,
                  &a_name_data)) {
! kerb_err_reply(client, pkt, i, lt);
                  return;
              }
              tk->length = 0; /* init */
- --- 480,487 ----

              if (i = check_princ(req_name_ptr, req_inst_ptr, 0,
                  &a_name_data)) {
! kerb_err_reply(client, pkt, i, "check_princ failed");
! a_name_data.key_low = a_name_data.key_high = 0;
                  return;
              }
              tk->length = 0; /* init */
***************
*** 471,477 ****
              /* this does all the checking */
              if (i = check_princ(service, instance, req_life,
                  &s_name_data)) {
! kerb_err_reply(client, pkt, i, lt);
                  return;
              }

- --- 492,500 ----
              /* this does all the checking */
              if (i = check_princ(service, instance, req_life,
                  &s_name_data)) {
! 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;
                  return;
              }

***************
*** 627,638 ****
- --- 650,679 ----
              k_flags = 0; /* various kerberos flags */

              auth->length = 4 + strlen((char *) pkt->dat + 3);
+ if (auth->length + 1 > MAX_KTXT_LEN) {
+ 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;
+ }
+
              auth->length += (int) *(pkt->dat + auth->length) +
                  (int) *(pkt->dat + auth->length + 1) + 2;
+ if (auth->length > MAX_KTXT_LEN) {
+ 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;
+ }

              memcpy(auth->dat, pkt->dat, auth->length);

              strncpy(tktrlm, (char *) auth->dat + 3, REALM_SZ);
+ tktrlm[REALM_SZ-1] = '\0';
              if (set_tgtkey(tktrlm)) {
                  lt = klog(L_ERR_UNK,
                      "FAILED realm %s unknown. Host: %s ",
***************
*** 680,686 ****
              kerno = check_princ(service, instance, req_life,
                  &s_name_data);
              if (kerno) {
! kerb_err_reply(client, pkt, kerno, lt);
                  return;
              }
              /* Bound requested lifetime with service and user */
- --- 721,727 ----
              kerno = check_princ(service, instance, req_life,
                  &s_name_data);
              if (kerno) {
! kerb_err_reply(client, pkt, kerno, "check_princ failed");
                  return;
              }
              /* Bound requested lifetime with service and user */
***************
*** 804,810 ****
      static char e_msg[128];

      strcpy(e_msg, "\nKerberos error -- ");
! strcat(e_msg, string);
      cr_err_reply(e_pkt, req_name_ptr, req_inst_ptr, req_realm_ptr,
                   req_time_ws, err, e_msg);
      sendto(f, e_pkt->dat, e_pkt->length, 0, (struct sockaddr *) client,
- --- 845,851 ----
      static char e_msg[128];

      strcpy(e_msg, "\nKerberos error -- ");
! 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);
      sendto(f, e_pkt->dat, e_pkt->length, 0, (struct sockaddr *) client,
***************
*** 928,934 ****
      kdb_encrypt_key(key, key, master_key,
                      master_key_schedule, DECRYPT);
      krb_set_key(key, 0);
! strcpy(lastrealm, r);
      return (KSUCCESS);
  }

- --- 969,976 ----
      kdb_encrypt_key(key, key, master_key,
                      master_key_schedule, DECRYPT);
      krb_set_key(key, 0);
! strncpy(lastrealm, r, sizeof(lastrealm) - 1);
! lastrealm[sizeof(lastrealm) - 1] = '\0';
      return (KSUCCESS);
  }

PATCHES AGAINST MIT Kerberos 4 Patch 10:

Please note that these patches have not been tested in any way. Use
at your own risk. These patches will also be made available at:

        http://web.mit.edu/kerberos/www/advisories/krb4kdc_krb4p10_patch.txt

*** kerberos.c.orig Fri Mar 1 01:34:09 1991
- --- kerberos.c Fri Jun 2 15:37:32 2000
***************
*** 318,323 ****
- --- 318,337 ----
  }

+ static void str_length_check(str, max_size)
+ char *str;
+ int max_size;
+ {
+ int i;
+ char *cp;
+
+ for (i=0, cp = str; i < max_size-1; i++, cp++) {
+ if (*cp == 0)
+ return;
+ }
+ *cp = 0;
+ }
+
  kerberos(client, pkt)
      struct sockaddr_in *client;
      KTEXT pkt;
***************
*** 357,362 ****
- --- 371,379 ----

      req_act_vno = req_version;

+ /* set these to point to something safe */
+ req_name_ptr = req_inst_ptr = req_realm_ptr = "";
+
      /* check packet version */
      if (req_version != KRB_PROT_VERSION) {
          lt = klog(L_KRB_PERR,
***************
*** 392,399 ****
- --- 409,419 ----

              /* set up and correct for byte order and alignment */
              req_name_ptr = (char *) pkt_a_name(pkt);
+ str_length_check(req_name_ptr, ANAME_SZ);
              req_inst_ptr = (char *) pkt_a_inst(pkt);
+ str_length_check(req_inst_ptr, INST_SZ);
              req_realm_ptr = (char *) pkt_a_realm(pkt);
+ str_length_check(req_realm_ptr, REALM_SZ);
              bcopy(pkt_time_ws(pkt), &req_time_ws, sizeof(req_time_ws));
              /* time has to be diddled */
              if (swap_bytes) {
***************
*** 413,419 ****

              if (i = check_princ(req_name_ptr, req_inst_ptr, 0,
                  &a_name_data)) {
! kerb_err_reply(client, pkt, i, lt);
                  return;
              }
              tk->length = 0; /* init */
- --- 433,440 ----

              if (i = check_princ(req_name_ptr, req_inst_ptr, 0,
                  &a_name_data)) {
! kerb_err_reply(client, pkt, i, "check_princ failed");
! a_name_data.key_low = a_name_data.key_high = 0;
                  return;
              }
              tk->length = 0; /* init */
***************
*** 424,430 ****
              /* this does all the checking */
              if (i = check_princ(service, instance, lifetime,
                  &s_name_data)) {
! kerb_err_reply(client, pkt, i, lt);
                  return;
              }
              /* Bound requested lifetime with service and user */
- --- 445,453 ----
              /* this does all the checking */
              if (i = check_princ(service, instance, lifetime,
                  &s_name_data)) {
! 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;
                  return;
              }
              /* Bound requested lifetime with service and user */
***************
*** 497,508 ****
- --- 520,549 ----
              k_flags = 0; /* various kerberos flags */

              auth->length = 4 + strlen(pkt->dat + 3);
+ if (auth->length + 1 > MAX_KTXT_LEN) {
+ 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;
+ }
+
              auth->length += (int) *(pkt->dat + auth->length) +
                  (int) *(pkt->dat + auth->length + 1) + 2;
+ if (auth->length > MAX_KTXT_LEN) {
+ 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;
+ }

              bcopy(pkt->dat, auth->dat, auth->length);

              strncpy(tktrlm, auth->dat + 3, REALM_SZ);
+ tktrlm[REALM_SZ-1] = '\0';
              if (set_tgtkey(tktrlm)) {
                  lt = klog(L_ERR_UNK,
                      "FAILED realm %s unknown. Host: %s ",
***************
*** 550,556 ****
              kerno = check_princ(service, instance, req_life,
                  &s_name_data);
              if (kerno) {
! kerb_err_reply(client, pkt, kerno, lt);
                  return;
              }
              /* Bound requested lifetime with service and user */
- --- 591,597 ----
              kerno = check_princ(service, instance, req_life,
                  &s_name_data);
              if (kerno) {
! kerb_err_reply(client, pkt, kerno, "check_princ failed");
                  return;
              }
              /* Bound requested lifetime with service and user */
***************
*** 669,675 ****
      static char e_msg[128];

      strcpy(e_msg, "\nKerberos error -- ");
! strcat(e_msg, string);
      cr_err_reply(e_pkt, req_name_ptr, req_inst_ptr, req_realm_ptr,
                   req_time_ws, err, e_msg);
      sendto(f, e_pkt->dat, e_pkt->length, 0, client, S_AD_SZ);
- --- 710,716 ----
      static char e_msg[128];

      strcpy(e_msg, "\nKerberos error -- ");
! 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);
      sendto(f, e_pkt->dat, e_pkt->length, 0, client, S_AD_SZ);
***************
*** 793,799 ****
      kdb_encrypt_key(key, key, master_key,
                      master_key_schedule, DECRYPT);
      krb_set_key(key, 0);
! strcpy(lastrealm, r);
      return (KSUCCESS);
  }

- --- 834,841 ----
      kdb_encrypt_key(key, key, master_key,
                      master_key_schedule, DECRYPT);
      krb_set_key(key, 0);
! strncpy(lastrealm, r, sizeof(lastrealm) - 1);
! lastrealm[sizeof(lastrealm) - 1] = '\0';
      return (KSUCCESS);
  }

ACKNOWLEDGEMENTS:

Thanks to Matt Power of MIT for assistance in debugging this
vulnerability.

Thanks to Assar Westerlund of SICS for information about KTH-krb4 and
Heimdal.

Thanks to Nalin Dahyabhai of Redhat for additional buffer paranoia
patches.

Thanks to Andrew Newman of Yale University for discovering the
double-free problem with the krb5-1.1.x KDC.

-----BEGIN PGP SIGNATURE-----
Version: 2.6.2

iQCVAwUBOUE+AabDgE/zdoE9AQEO3QQA1UAOcnx3tM/KYEVDpYuB0ZpGb4weQT0T
nubJKoywGcvxDZ4+F2yd/cQMehG9y0/rsb8iIJmXyeUZTF1ygerS6xvW03bUF2KM
l2sra2WeAdMK12H7J2B4Cxah3E96hhGHuZ32MYhsTUMxKH3sL7jJpfabHjwPYcY9
thdTpc1rP1U=
=WeXV
-----END PGP SIGNATURE-----