Kerberos krb5-1.13 Insecure Functions

2015.04.07
Credit: NicholasL
Risk: Medium
Local: Yes
Remote: No
CWE: N/A

-=[Advanced Information Security Corp]=- Nicholas Lemonias Report Date: 3/4/2015 Email: lem.nikolas@gmail.com Introduction ============== During a source-code audit of the krb5-1.13 stable release (15 October 2014) implementation for linux; conducted internally by the Advanced Information Security Group, instances of insecure function use were observed, which could lead to a number of attacks. Software Overview ================== Kerberos is a computer network authentication protocol which works on the basis of 'tickets' to allow nodes communicating over a non-secure network to prove their identity to one another in a secure manner. Its designers aimed it primarily at a clientserver model and it provides mutual authenticationboth the user and the server verify each other's identity. Kerberos protocol messages are protected against eavesdropping and replay attacks. Kerberos builds on symmetric key cryptography and requires a trusted third party, and optionally may use public-key cryptography during certain phases of authentication. Massachusetts Institute of Technology (MIT) developed Kerberos to protect network services provided by Project Athena. The protocol is based on the earlier NeedhamSchroeder symmetric key protocol. Several versions of the protocol exist; versions 13 occurred only internally at MIT. Steve Miller and Clifford Neuman, the primary designers of Kerberos version 4, published that version in the late 1980s, although they had targeted it primarily for Project Athena. Version 5, designed by John Kohl and Clifford Neuman, appeared as RFC 1510 in 1993 (made obsolete by RFC 4120 in 2005), with the intention of overcoming the limitations and security problems of version 4. Authorities in the United States classified Kerberos as auxiliary military technology and banned its export because it used the Data Encryption Standard (DES) encryption algorithm (with 56-bit keys). PoC 1 - Code Snippet [CWE 362] ============================== (.../src/ccapi/server/win/ccs_win_pipe.c:67) struct ccs_win_pipe_t* ccs_win_pipe_new (const char* uuid, const UINT64 h) { cc_int32 err = ccNoError; struct ccs_win_pipe_t* out_pipe = NULL; char* uuidCopy = NULL; if (!err) { if (!uuid) {err = cci_check_error(ccErrBadParam);} } if (!err) { uuidCopy = (char*)malloc(1+strlen(uuid)); if (!uuidCopy) {err = cci_check_error(ccErrBadParam);} strcpy(uuidCopy, uuid); } if (!err) { out_pipe = (struct ccs_win_pipe_t*)malloc(sizeof(struct ccs_win_pipe_t)); if (!out_pipe) {err = cci_check_error(ccErrBadParam);} out_pipe->uuid = uuidCopy; out_pipe->clientHandle = h; } #if 0 cci_debug_printf("0x%X = %s(%s, 0x%X)", out_pipe, __FUNCTION__, uuid, h); #endif return out_pipe; } Description: Memory leak [1] PoC 2 - Code Snippet [CWE 457] ============================== (.../src/lib/kadm5/chpass_util.c:110) int code, code2; unsigned int pwsize; static char buffer[255]; char *new_password; kadm5_principal_ent_rec princ_ent; kadm5_policy_ent_rec policy_ent; _KADM5_CHECK_HANDLE(server_handle); if (ret_pw) *ret_pw = NULL; if (new_pw != NULL) { new_password = new_pw; } else { /* read the password */ krb5_context context; if ((code = (int) kadm5_init_krb5_context(&context)) == 0) { pwsize = sizeof(buffer); code = krb5_read_password(context, KADM5_PW_FIRST_PROMPT, KADM5_PW_SECOND_PROMPT, buffer, &pwsize); krb5_free_context(context); } if (code == 0) new_password = buffer; else { #ifdef ZEROPASSWD memset(buffer, 0, sizeof(buffer)); #endif if (code == KRB5_LIBOS_BADPWDMATCH) { strncpy(msg_ret, string_text(CHPASS_UTIL_NEW_PASSWORD_MISMATCH), msg_len - 1); msg_ret[msg_len - 1] = '\0'; return(code); } else { snprintf(msg_ret, msg_len, "%s %s\n\n%s", error_message(code), string_text(CHPASS_UTIL_WHILE_READING_PASSWORD), string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED)); msg_ret[msg_len - 1] = '\0'; return(code); } } if (pwsize == 0) { #ifdef ZEROPASSWD memset(buffer, 0, sizeof(buffer)); #endif strncpy(msg_ret, string_text(CHPASS_UTIL_NO_PASSWORD_READ), msg_len - 1); msg_ret[msg_len - 1] = '\0'; return(KRB5_LIBOS_CANTREADPWD); /* could do better */ } } if (ret_pw) *ret_pw = new_password; Description: Unitialized variable pwsize PoC 3 - Code Snippet [CWE 401] =============================== (.../src/lib/krb5/krb/rd_req_dec.c:672) retval = krb5int_validate_times(context, &req->ticket->enc_part2->times); if (retval != 0) goto cleanup; if ((retval = krb5_check_clockskew(context, (*auth_context)->authentp->ctime))) goto cleanup; if (check_valid_flag) { if (req->ticket->enc_part2->flags & TKT_FLG_INVALID) { retval = KRB5KRB_AP_ERR_TKT_INVALID; goto cleanup; } if ((retval = krb5_authdata_context_init(context, &(*auth_context)->ad_context))) goto cleanup; if ((retval = krb5int_authdata_verify(context, (*auth_context)->ad_context, AD_USAGE_MASK, auth_context, &decrypt_key, req))) goto cleanup; } /* read RFC 4537 etype list from sender */ retval = decode_etype_list(context, (*auth_context)->authentp, &desired_etypes, &rfc4537_etypes_len); if (retval != 0) goto cleanup; if (desired_etypes == NULL) desired_etypes = (krb5_enctype *)calloc(4, sizeof(krb5_enctype)); else desired_etypes = (krb5_enctype *)realloc(desired_etypes, (rfc4537_etypes_len + 4) * sizeof(krb5_enctype)); if (desired_etypes == NULL) { retval = ENOMEM; goto cleanup; } desired_etypes_len = rfc4537_etypes_len; Description: desired_etypes nulled but not freed upon failure. PoC 4 - Code Snippet [CWE 362] ================================ (.../src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c:1440) static char * getstringtime(krb5_timestamp epochtime) { struct tm tme; char *strtime=NULL; time_t posixtime = epochtime; strtime = calloc (50, 1); if (strtime == NULL) return NULL; if (gmtime_r(&posixtime, &tme) == NULL) return NULL; strftime(strtime, 50, "%Y%m%d%H%M%SZ", &tme); return strtime; } Description: Memory leak on strtime. PoC 5 - Code Snippet [CWE 362] ================================ (.../src/plugins/preauth/pkinit/pkinit_crypto_nss.c:1897) char *rnd_buf; size_t kbyte, klength; krb5_data rnd_data; krb5_error_code result; NSSInitContext *ncontext; if (counter_length > sizeof(counter)) return EINVAL; result = krb5_c_keylengths(context, etype, &kbyte, &klength); if (result != 0) return result; rnd_buf = malloc(dh_key_len); if (rnd_buf == NULL) return ENOMEM; memset(counter, 0, sizeof(counter)); for (i = sizeof(counter) - 1; i >= 0; i--) counter[i] = (counter_start >> (8 * (counter_length - 1 - i))) & 0xff; rnd_len = kbyte; left = rnd_len; ncontext = NSS_InitContext(DEFAULT_CONFIGDIR, NULL, NULL, NULL, NULL, NSS_INIT_READONLY | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN | NSS_INIT_NOROOTINIT | NSS_INIT_PK11RELOAD); while (left > 0) { ctx = PK11_CreateDigestContext(hash_alg); if (ctx == NULL) { krb5int_zap(buf, sizeof(buf)); krb5int_zap(rnd_buf, dh_key_len); free(rnd_buf); return ENOMEM; } if (PK11_DigestBegin(ctx) != SECSuccess) { PK11_DestroyContext(ctx, PR_TRUE); krb5int_zap(buf, sizeof(buf)); krb5int_zap(rnd_buf, dh_key_len); free(rnd_buf); return ENOMEM; } if (PK11_DigestOp(ctx, counter, counter_length) != SECSuccess) { PK11_DestroyContext(ctx, PR_TRUE); krb5int_zap(buf, sizeof(buf)); krb5int_zap(rnd_buf, dh_key_len); free(rnd_buf); return ENOMEM; } if (PK11_DigestOp(ctx, dh_key, dh_key_len) != SECSuccess) { PK11_DestroyContext(ctx, PR_TRUE); krb5int_zap(buf, sizeof(buf)); krb5int_zap(rnd_buf, dh_key_len); free(rnd_buf); return ENOMEM; } if ((other_data_len > 0) && (PK11_DigestOp(ctx, (const unsigned char *) other_data, other_data_len) != SECSuccess)) { PK11_DestroyContext(ctx, PR_TRUE) Description: rnd_buf in pkinit_octetstring_hkdf() can be leaked on malloc failure. PoC 6 - Code Snippet [CWE 401] ================================== (.../src/plugins/preauth/pkinit/pkinit_crypto_openssl.c:1909) /* transfer the decoded PKCS7 SignedData message into a separate buffer */ for (;;) { if ((tmp_buf = realloc(tmp_buf, size + 1024 * 10)) == NULL) goto cleanup; i = BIO_read(out, &(tmp_buf[size]), 1024 * 10); if (i <= 0) break; else size += i; } tmp_buf_len = size; Description: Buffer tmp_buf is nulled but not freed upon failure. PoC 7 - Code Snippet [CWE 467] =============================== (.../src/windows/leashdll/krb5routines.c:183) /* initialize ticket cache */ if ((icode = pkrb_in_tkt(v4creds->pname, v4creds->pinst, v4creds->realm) != KSUCCESS)) { goto cleanup; } /* stash ticket, session key, etc. for future use */ if ((icode = pkrb_save_credentials(v4creds->service,v4creds->instance,v4creds->realm,v4creds->session,v4creds->lifetime,v4creds->kvno, &(v4creds->ticket_st),v4creds->issue_date))) { goto cleanup; } cleanup: memset(v4creds, 0, sizeof(v4creds)); free(v4creds); if (v5creds) { pkrb5_free_creds(ctx, v5creds); } Description: size of pointer v4credis is used instead of its data. This should be 'sizeof(*v4creds). This could lead to buffer overflows. PoC 8 - Code Snippet [CWE 120] =============================== (.../src/windows/leashdll/lshfunc.c:534,539) sscanf(principal, "%[/0-9a-zA-Z._-]@%[/0-9a-zA-Z._-]", first_part, second_part); strcpy(temp, first_part); strcpy(realm, second_part); memset(first_part, '\0', sizeof(first_part)); memset(second_part, '\0', sizeof(second_part)); if (sscanf(temp, "%[@0-9a-zA-Z._-]/%[@0-9a-zA-Z._-]", first_part, second_part) == 2) { strcpy(aname, first_part); strcpy(inst, second_part); } Description: Function Scanf doesn't have field limits on input, and could lead to a buffer overflow attack. [2] Appendices =========== Sincere Thanks to the Kerberos team for their mutual security efforts. References =========== [1] M. Howard, D. LeBlanc Writing Secure Code, Second Edition Microsoft Press. [2] Oracle. Basic Library Functions - Title: scaf() man pages section 3: Basic Library Functions [Online] Available at: http://docs.oracle.com/cd/E36784_01/html/E36874/scanf-3c.html [Last Accessed 2 April, 2015]

References:

http://docs.oracle.com/cd/E36784_01/html/E36874/scanf-3c.html


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2024, cxsecurity.com

 

Back to Top