[3026] in Kerberos-V5-bugs

home help back first fref pref prev next nref lref last post

krb5-kdc/681: Principal impersonation when using SAM

daemon@ATHENA.MIT.EDU (fcusack@iconnet.net)
Wed Jan 6 17:28:14 1999

Resent-From: gnats@rt-11.MIT.EDU (GNATS Management)
Resent-To: krb5-unassigned@RT-11.MIT.EDU
Resent-Reply-To: krb5-bugs@MIT.EDU, fcusack@iconnet.net
Date: Wed, 6 Jan 1999 17:28:33 -0500 (EST)
From: fcusack@iconnet.net
Reply-To: fcusack@iconnet.net
To: krb5-bugs@MIT.EDU
Cc: fcusack@iconnet.net


>Number:         681
>Category:       krb5-kdc
>Synopsis:       It's possible to replay another principal's SAM data.
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    krb5-unassigned
>State:          open
>Class:          sw-bug
>Submitter-Id:   unknown
>Arrival-Date:   Wed Jan 06 17:28:01 EST 1999
>Last-Modified:
>Originator:     Frank Cusack
>Organization:
Icon CMT Corp.
>Release:        krb5-current-19981119
>Environment:
Unix
System: SunOS ratbert 5.6 Generic_105181-09 sun4u sparc SUNW,Ultra-5_10
Architecture: sun4

>Description:
	If authentication of 2 principal's requires the same SAM mechanism,
	it's possible to use a known SAM reply from principal A to authenticate
	as principal B. This is b/c the current SAM code doesn't do
	enough checking on the returned SAM data.

	The fix below is based on previous patches I submitted. Without
	these patches (and this one), using SAM is significantly (critically)
	weaker than not using it.
>How-To-Repeat:
>Fix:
Index: include/k5-int.h
===================================================================
RCS file: /icon/d04/cvsroot/3rd-party/krb5-19981119/include/k5-int.h,v
retrieving revision 1.8
diff -u -r1.8 k5-int.h
--- k5-int.h	1998/12/02 23:16:14	1.8
+++ k5-int.h	1999/01/06 22:10:50
@@ -349,6 +349,7 @@
 	krb5_keyblock	sam_key;
 	krb5_timestamp	stime;	/* for replay detection */
 	krb5_int32	susec;
+	krb5_principal	client;
 	krb5_data	msd;	/* mechanism specific data */
 } krb5_predicted_sam_response;
 
Index: kdc/preauth/pa_sam.c
===================================================================
RCS file: /icon/d04/cvsroot/3rd-party/krb5-19981119/kdc/preauth/pa_sam.c,v
retrieving revision 1.2
diff -u -r1.2 pa_sam.c
--- pa_sam.c	1998/12/01 02:06:21	1.2
+++ pa_sam.c	1999/01/06 22:10:51
@@ -36,11 +36,6 @@
  */
 
 /*
- * XXX Most (all?) of the sam types use the master database key to
- * encrypt the track-data. This is probably bad.
- */
-
-/*
  * To define a new SAM type, place it in the sam_inst_map below,
  * and take a look at the code for the other SAM types.
  *
Index: kdc/preauth/pa_sam_cryptocard.c
===================================================================
RCS file: /icon/d04/cvsroot/3rd-party/krb5-19981119/kdc/preauth/pa_sam_cryptocard.c,v
retrieving revision 1.8
diff -u -r1.8 pa_sam_cryptocard.c
--- pa_sam_cryptocard.c	1998/12/02 23:16:14	1.8
+++ pa_sam_cryptocard.c	1999/01/06 22:10:51
@@ -242,14 +242,17 @@
     } /* switch (mode) */
 #endif /* KRBCONF_KDC_MODIFIES_KDB */
 
-    /* Convert the SAD into a key. */
     psr.magic = KV5M_PREDICTED_SAM_RESPONSE;
+    if (retval = krb5_copy_principal(context, request->client, &psr.client))
+	goto cleanup;
+
 #ifdef USE_RCACHE
     /* XXX Watch these types when time_t or krb5_timestamp changes. */
     if (retval = krb5_us_timeofday(context, &psr.stime, &psr.susec))
 	goto cleanup;
 #endif /* USE_RCACHE */
 
+    /* Convert the SAD into a key. */
     if (retval = krb5_c_string_to_key(context, ENCTYPE_DES_CBC_MD5,
 				      &predict_response, 0 /* salt */,
 				      &psr.sam_key)) {
@@ -382,6 +385,7 @@
     krb5_predicted_sam_response	*	psr = 0;
     krb5_enc_sam_response_enc *		esre = 0;
     krb5_timestamp			timenow;
+    char *				princ_req = 0, *princ_psr = 0;
 
     /* Sanity check */
     if (sr->sam_type != PA_SAM_TYPE_CRYPTOCARD) {
@@ -419,6 +423,16 @@
 	goto cleanup;
     }
 
+    if (retval = krb5_unparse_name(context, request->client, &princ_req))
+	goto cleanup;
+    if (retval = krb5_unparse_name(context, psr->client, &princ_psr))
+	goto cleanup;
+    if (strcmp(princ_req, princ_psr) != 0) {
+	com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED,
+		"Principal mismatch in rb1 track-data!");
+	goto cleanup;
+    }
+
     if (retval = krb5_timeofday(context, &timenow))
 	goto cleanup;
 
@@ -438,8 +452,8 @@
 	}
 
 	/* Now check the replay cache. */
-	rep.client = "sam/rc"; /* Any fixed value will do, although this */
-	rep.server = "sam/rc"; /* should not match any principal name.   */
+	rep.client = princ_psr;
+	rep.server = "sam/rc";  /* Should not match any principal name. */
 	rep.ctime = psr->stime;
 	rep.cusec = psr->susec;
 	if (retval = krb5_rc_store(kdc_context, kdc_rcache, &rep)) {
@@ -508,6 +522,11 @@
 	krb5_free_predicted_sam_response(context, psr);
     if (esre) 
 	krb5_free_enc_sam_response_enc(context, esre);
+
+    if (princ_req)
+	krb5_xfree(princ_req);
+    if (princ_psr)
+	krb5_xfree(princ_psr);
 
     if (!retval) {
 	setflag(enc_tkt_reply->flags, TKT_FLG_HW_AUTH);
Index: kdc/preauth/pa_sam_digi_path.c
===================================================================
RCS file: /icon/d04/cvsroot/3rd-party/krb5-19981119/kdc/preauth/pa_sam_digi_path.c,v
retrieving revision 1.9
diff -u -r1.9 pa_sam_digi_path.c
--- pa_sam_digi_path.c	1998/12/02 23:16:15	1.9
+++ pa_sam_digi_path.c	1999/01/06 22:10:51
@@ -150,14 +150,18 @@
     predict_response.data = response;
     predict_response.length = 8;
 
-    /* Convert the SAD into a key. */
     psr.magic = KV5M_PREDICTED_SAM_RESPONSE;
+    if (retval = krb5_copy_principal(context, request->client, &psr.client))
+	goto cleanup;
+
+
 #ifdef USE_RCACHE
     /* XXX Watch these types when time_t or krb5_timestamp changes. */
     if (retval = krb5_us_timeofday(context, &psr.stime, &psr.susec))
 	goto cleanup;
 #endif /* USE_RCACHE */
 
+    /* Convert the SAD into a key. */
     if (retval = krb5_c_string_to_key(context, ENCTYPE_DES_CBC_MD5,
 				      &predict_response, 0 /* salt */,
 				      &psr.sam_key)) {
@@ -281,6 +285,7 @@
     krb5_predicted_sam_response *	psr = 0;
     krb5_enc_sam_response_enc *		esre = 0;
     krb5_timestamp			timenow;
+    char *				princ_req = 0, *princ_psr = 0;
 
     /* Sanity check */
     if (sr->sam_type != PA_SAM_TYPE_DIGI_PATH) {
@@ -318,6 +323,16 @@
 	goto cleanup;
     }
 
+    if (retval = krb5_unparse_name(context, request->client, &princ_req))
+	goto cleanup;
+    if (retval = krb5_unparse_name(context, psr->client, &princ_psr))
+	goto cleanup;
+    if (strcmp(princ_req, princ_psr) != 0) {
+	com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED,
+		"Principal mismatch in snk4 track-data!");
+	goto cleanup;
+    }
+
     if (retval = krb5_timeofday(context, &timenow))
 	goto cleanup;
 
@@ -337,8 +352,8 @@
 	}
 
 	/* Now check the replay cache. */
-	rep.client = "sam/rc"; /* Any fixed value will do, although this */
-	rep.server = "sam/rc"; /* should not match any principal name.   */
+	rep.client = princ_psr;
+	rep.server = "sam/rc";  /* Should not match any principal name. */
 	rep.ctime = psr->stime;
 	rep.cusec = psr->susec;
 	if (retval = krb5_rc_store(kdc_context, kdc_rcache, &rep)) {
@@ -392,6 +407,11 @@
 	krb5_free_predicted_sam_response(context, psr);
     if (esre) 
 	krb5_free_enc_sam_response_enc(context, esre);
+
+    if (princ_req)
+	krb5_xfree(princ_req);
+    if (princ_psr)
+	krb5_xfree(princ_psr);
 
     if (!retval) {
 	setflag(enc_tkt_reply->flags, TKT_FLG_HW_AUTH);
Index: kdc/preauth/pa_sam_grail.c
===================================================================
RCS file: /icon/d04/cvsroot/3rd-party/krb5-19981119/kdc/preauth/pa_sam_grail.c,v
retrieving revision 1.6
diff -u -r1.6 pa_sam_grail.c
--- pa_sam_grail.c	1998/12/02 23:16:15	1.6
+++ pa_sam_grail.c	1999/01/06 22:10:51
@@ -69,6 +69,9 @@
     sc.sam_challenge.length = strlen(sc.sam_challenge.data);
 
     psr.magic = KV5M_PREDICTED_SAM_RESPONSE;
+    if (retval = krb5_copy_principal(context, request->client, &psr.client))
+	goto cleanup;
+
 #ifdef USE_RCACHE
     /* XXX Watch these types when time_t or krb5_timestamp changes. */
     if (retval = krb5_us_timeofday(context, &psr.stime, &psr.susec))
@@ -183,6 +186,7 @@
     krb5_predicted_sam_response *	psr = 0;
     krb5_enc_sam_response_enc *		esre = 0;
     krb5_timestamp			timenow;
+    char *				princ_req = 0, *princ_psr = 0;
 
     /* Sanity check */
     if (sr->sam_type != PA_SAM_TYPE_GRAIL) {
@@ -220,6 +224,16 @@
 	goto cleanup;
     }
 
+    if (retval = krb5_unparse_name(context, request->client, &princ_req))
+	goto cleanup;
+    if (retval = krb5_unparse_name(context, psr->client, &princ_psr))
+	goto cleanup;
+    if (strcmp(princ_req, princ_psr) != 0) {
+	com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED,
+		"Principal mismatch in Grail track-data!");
+	goto cleanup;
+    }
+
     if (retval = krb5_timeofday(context, &timenow))
 	goto cleanup;
 
@@ -239,8 +253,8 @@
 	}
 
 	/* Now check the replay cache. */
-	rep.client = "sam/rc"; /* Any fixed value will do, although this */
-	rep.server = "sam/rc"; /* should not match any principal name.   */
+	rep.client = princ_psr;
+	rep.server = "sam/rc";  /* Should not match any principal name. */
 	rep.ctime = psr->stime;
 	rep.cusec = psr->susec;
 	if (retval = krb5_rc_store(kdc_context, kdc_rcache, &rep)) {
@@ -294,6 +308,11 @@
 	krb5_free_predicted_sam_response(context, psr);
     if (esre) 
 	krb5_free_enc_sam_response_enc(context, esre);
+
+    if (princ_req)
+	krb5_xfree(princ_req);
+    if (princ_psr)
+	krb5_xfree(princ_psr);
 
     if (!retval) {
 	setflag(enc_tkt_reply->flags, TKT_FLG_HW_AUTH);
Index: kdc/preauth/pa_sam_securid.c
===================================================================
RCS file: /icon/d04/cvsroot/3rd-party/krb5-19981119/kdc/preauth/pa_sam_securid.c,v
retrieving revision 1.7
diff -u -r1.7 pa_sam_securid.c
--- pa_sam_securid.c	1998/12/02 23:16:15	1.7
+++ pa_sam_securid.c	1999/01/06 22:10:53
@@ -142,6 +142,9 @@
     g_sc.sam_response_prompt.length = strlen(g_sc.sam_response_prompt.data);
 
     psr.magic = KV5M_PREDICTED_SAM_RESPONSE;
+    if (retval = krb5_copy_principal(context, request->client, &psr.client))
+	goto cleanup;
+
     psr.msd.data = &g_sid_track_data;
     psr.msd.length = sizeof(g_sid_track_data);
 #ifdef USE_RCACHE
@@ -269,6 +272,7 @@
     krb5_predicted_sam_response *	psr = 0;
     krb5_enc_sam_response_enc *		esre = 0;
     krb5_timestamp			timenow;
+    char *				princ_req = 0, *princ_psr = 0;
 
     char *				user = 0, cp;
 
@@ -378,6 +382,16 @@
 	    goto cleanup;
 	}
 
+	if (retval = krb5_unparse_name(context, request->client, &princ_req))
+	    goto cleanup;
+	if (retval = krb5_unparse_name(context, psr->client, &princ_psr))
+	    goto cleanup;
+	if (strcmp(princ_req, princ_psr) != 0) {
+	    com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED,
+		    "Principal mismatch in SecurID track-data!");
+	    goto cleanup;
+	}
+
 #ifdef USE_RCACHE
 	/* Probably not useful for SecurID, but what the hell. */
 	{
@@ -395,8 +409,8 @@
 	    }
 
 	    /* Now check the replay cache. */
-	    rep.client = "sam/rc"; /* Any fixed value will do, although this */
-	    rep.server = "sam/rc"; /* should not match any principal name.   */
+	    rep.client = princ_psr;
+	    rep.server = "sam/rc";  /* Should not match any principal name. */
 	    rep.ctime = psr->stime;
 	    rep.cusec = psr->susec;
 	    if (retval = krb5_rc_store(kdc_context, kdc_rcache, &rep)) {
@@ -551,6 +565,11 @@
 	krb5_free_enc_sam_response_enc(context, esre);
     if (client_key.contents)
 	krb5_free_keyblock_contents(context, &client_key);
+
+    if (princ_req)
+	krb5_xfree(princ_req);
+    if (princ_psr)
+	krb5_xfree(princ_psr);
 
     if (user)
 	krb5_xfree(user);
Index: lib/krb5/asn.1/asn1_k_decode.c
===================================================================
RCS file: /icon/d04/cvsroot/3rd-party/krb5-19981119/lib/krb5/asn.1/asn1_k_decode.c,v
retrieving revision 1.8
diff -u -r1.8 asn1_k_decode.c
--- asn1_k_decode.c	1998/12/02 23:16:15	1.8
+++ asn1_k_decode.c	1999/01/06 22:10:55
@@ -815,7 +815,10 @@
     get_field(val->sam_key,0,asn1_decode_encryption_key);
     get_field(val->stime,1,asn1_decode_kerberos_time);
     get_field(val->susec,2,asn1_decode_int32);
-    opt_string(val->msd,3,asn1_decode_octetstring);
+    alloc_field(val->client,krb5_principal_data);
+    get_field(val->client,3,asn1_decode_realm);
+    get_field(val->client,4,asn1_decode_principal_name);
+    opt_string(val->msd,5,asn1_decode_octetstring);
     end_structure();
     val->magic = KV5M_PREDICTED_SAM_RESPONSE;
   }
Index: lib/krb5/asn.1/asn1_k_encode.c
===================================================================
RCS file: /icon/d04/cvsroot/3rd-party/krb5-19981119/lib/krb5/asn.1/asn1_k_encode.c,v
retrieving revision 1.8
diff -u -r1.8 asn1_k_encode.c
--- asn1_k_encode.c	1998/12/02 23:16:15	1.8
+++ asn1_k_encode.c	1999/01/06 22:10:55
@@ -949,7 +949,9 @@
 {
   asn1_setup();
 
-  add_optstring(val->msd,3,asn1_encode_octetstring);
+  add_optstring(val->msd,5,asn1_encode_octetstring);
+  asn1_addfield(val->client,4,asn1_encode_principal_name);
+  asn1_addfield(val->client,3,asn1_encode_realm);
   asn1_addfield(val->susec,2,asn1_encode_integer);
   asn1_addfield(val->stime,1,asn1_encode_kerberos_time);
   asn1_addfield(&(val->sam_key),0,asn1_encode_encryption_key);
Index: lib/krb5/error_tables/kv5m_err.et
===================================================================
RCS file: /icon/d04/cvsroot/3rd-party/krb5-19981119/lib/krb5/error_tables/kv5m_err.et,v
retrieving revision 1.2
diff -u -r1.2 kv5m_err.et
--- kv5m_err.et	1998/11/25 06:50:50	1.2
+++ kv5m_err.et	1999/01/06 22:10:56
@@ -80,6 +80,5 @@
 error_code KV5M_PASSWD_PHRASE_ELEMENT,	"Bad magic number for passwd_phrase_element"
 error_code KV5M_GSS_OID,	"Bad magic number for GSSAPI OID"
 error_code KV5M_GSS_QUEUE,	"Bad magic number for GSSAPI QUEUE"
-error_code KV5M_RB1_TRACK_DATA,	"Bad magic number for RB1_TRACK_DATA"
 
 end
Index: lib/krb5/krb/kfree.c
===================================================================
RCS file: /icon/d04/cvsroot/3rd-party/krb5-19981119/lib/krb5/krb/kfree.c,v
retrieving revision 1.4
diff -u -r1.4 kfree.c
--- kfree.c	1998/12/01 02:06:23	1.4
+++ kfree.c	1999/01/06 22:10:57
@@ -653,6 +653,8 @@
 	return;
     if (psr->sam_key.contents)
 	krb5_free_keyblock_contents(ctx, &psr->sam_key);
+    if (psr->client)
+	krb5_free_principal(ctx, psr->client);
     if (psr->msd.data)
 	krb5_free_data_contents(ctx, &psr->msd);
 }
>Audit-Trail:
>Unformatted:

home help back first fref pref prev next nref lref last post