CVE-2014-5355: Other (NVD-CWE-Other)
value: MIT Kerberos 5 (aka krb5) through 1.13.1 incorrectly expects that a krb5_read_message data field is represented as a string ending with a '\0' character, which allows remote attackers to (1) cause a denial of service (NULL pointer dereference) via a zero-byte version string or (2) cause a denial of service (out-of-bounds read) by omitting the '\0' character, related to appl/user_user/server.c and lib/krb5/krb/recvauth.c.
CWE description: NVD is only using a subset of CWE for mapping instead of the entire CWE, and the weakness type is not covered by that subset.
Published: 2015-02-20T11:59Z
Repository: https://github.com/krb5/krb5
Language: C
Files changed: src/appl/user_user/server.c, src/lib/krb5/krb/recvauth.c
Commit date: 2015-02-17 14:54:59 -0500
Commit message: Fix krb5_read_message handling [CVE-2014-5355]

In recvauth_common, do not use strcmp against the data fields of
krb5_data objects populated by krb5_read_message(), as there is no
guarantee that they are C strings.  Instead, create an expected
krb5_data value and use data_eq().

In the sample user-to-user server application, check that the received
client principal name is null-terminated before using it with printf
and krb5_parse_name.

CVE-2014-5355:

In MIT krb5, when a server process uses the krb5_recvauth function, an
unauthenticated remote attacker can cause a NULL dereference by
sending a zero-byte version string, or a read beyond the end of
allocated storage by sending a non-null-terminated version string.
The example user-to-user server application (uuserver) is similarly
vulnerable to a zero-length or non-null-terminated principal name
string.

The krb5_recvauth function reads two version strings from the client
using krb5_read_message(), which produces a krb5_data structure
containing a length and a pointer to an octet sequence.  krb5_recvauth
assumes that the data pointer is a valid C string and passes it to
strcmp() to verify the versions.  If the client sends an empty octet
sequence, the data pointer will be NULL and strcmp() will dereference
a NULL pointer, causing the process to crash.  If the client sends a
non-null-terminated octet sequence, strcmp() will read beyond the end
of the allocated storage, possibly causing the process to crash.

uuserver similarly uses krb5_read_message() to read a client principal
name, and then passes it to printf() and krb5_parse_name() without
verifying that it is a valid C string.

The krb5_recvauth function is used by kpropd and the Kerberized
versions of the BSD rlogin and rsh daemons.  These daemons are usually
run out of inetd or in a mode which forks before processing incoming
connections, so a process crash will generally not result in a
complete denial of service.

Thanks to Tim Uglow for discovering this issue.

CVSSv2: AV:N/AC:L/Au:N/C:N/I:N/A:P/E:POC/RL:OF/RC:C

[tlyu@mit.edu: CVSS score]

ticket: 8050 (new)
target_version: 1.13.1
tags: pullup

Diff: diff --git a/src/appl/user_user/server.c b/src/appl/user_user/server.c
index 09ea4e0ed74..f2b5b614e30 100644
--- a/src/appl/user_user/server.c
+++ b/src/appl/user_user/server.c
@@ -109,12 +109,14 @@ int main(argc, argv)
         close(sock);
         sock = 0;
     }
 #endif
 
+    /* principal name must be sent null-terminated. */
     retval = krb5_read_message(context, (krb5_pointer) &sock, &pname_data);
-    if (retval) {
+    if (retval || pname_data.length == 0 ||
+        pname_data.data[pname_data.length - 1] != '\0') {
         com_err ("uu-server", retval, "reading pname");
         return 2;
     }
 
     retval = krb5_read_message(context, (krb5_pointer) &sock, &tkt_data);
diff --git a/src/lib/krb5/krb/recvauth.c b/src/lib/krb5/krb/recvauth.c
index da83628303f..5adc6dd14ab 100644
--- a/src/lib/krb5/krb/recvauth.c
+++ b/src/lib/krb5/krb/recvauth.c
@@ -57,10 +57,11 @@ recvauth_common(krb5_context context,
     krb5_data             inbuf;
     krb5_data             outbuf;
     krb5_rcache           rcache = 0;
     krb5_octet            response;
     krb5_data             null_server;
+    krb5_data             d;
     int                   need_error_free = 0;
     int                   local_rcache = 0, local_authcon = 0;
 
     /*
      * Zero out problem variable.  If problem is set at the end of
@@ -75,11 +76,12 @@ recvauth_common(krb5_context context,
         /*
          * First read the sendauth version string and check it.
          */
         if ((retval = krb5_read_message(context, fd, &inbuf)))
             return(retval);
-        if (strcmp(inbuf.data, sendauth_version)) {
+        d = make_data((char *)sendauth_version, strlen(sendauth_version) + 1);
+        if (!data_eq(inbuf, d)) {
             problem = KRB5_SENDAUTH_BADAUTHVERS;
             response = 1;
         }
         free(inbuf.data);
     }
@@ -91,12 +93,13 @@ recvauth_common(krb5_context context,
     /*
      * Do the same thing for the application version string.
      */
     if ((retval = krb5_read_message(context, fd, &inbuf)))
         return(retval);
-    if (appl_version && strcmp(inbuf.data, appl_version)) {
-        if (!problem) {
+    if (appl_version != NULL && !problem) {
+        d = make_data(appl_version, strlen(appl_version) + 1);
+        if (!data_eq(inbuf, d)) {
             problem = KRB5_SENDAUTH_BADAPPLVERS;
             response = 2;
         }
     }
     if (version && !problem)

Vulnerable code:     if (retval) {
        if (strcmp(inbuf.data, sendauth_version)) {
    if (appl_version && strcmp(inbuf.data, appl_version)) {
        if (!problem) {
Fixed code:     /* principal name must be sent null-terminated. */
    if (retval || pname_data.length == 0 ||
        pname_data.data[pname_data.length - 1] != '\0') {
    krb5_data             d;
        d = make_data((char *)sendauth_version, strlen(sendauth_version) + 1);
        if (!data_eq(inbuf, d)) {
    if (appl_version != NULL && !problem) {
        d = make_data(appl_version, strlen(appl_version) + 1);
        if (!data_eq(inbuf, d)) {