Kerberos KRBTKFILE ticketfile vulnerability

Summary
Description:Suid root programs in the Kerberos 4 suite don't check permissions on $KRBTKFILE before using it for authentication.
Author:Mattias Amnefelt <mattiasa@stacken.kth.se>
Compromise:Spoof Kerberos authentication
Vulnerable Systems:Those running Kerberos 4 with rsh,rcp, or rlogin suid-root .
Date:6 November 1997
Details


Date: Thu, 6 Nov 1997 11:25:03 +0100
From: Mattias Amnefelt <mattiasa@stacken.kth.se>
To: best-of-security@cyber.com.au
Subject: BoS:      Re: Major security-hole in kerberos rsh, rcp and rlogin.


The security hole in kerberos:

Affects:
kth-krb4

Background:
Every user on a kerberized system has a ticket-file. Only the owner should
be able to read this file. The name of the ticketfile is stored in the
environment-variable KRBTKFILE.

The hole:
The versions of rsh, rcp and rlogin in the kth-krb4 package are setuid to work
with bsd-style rshd and rlogind. When they attempt to read the ticketfile,
there is no check if the user starting the program has read access of the file.
Thus, a user can use any other user on the system's ticketfile by simply
changing an environment variable.

Quick Workaround:
Disable the suid-bits on rcp, rsh and rlogin. This will disable the program's
capabilities to fallback to the non-kerberised protocols if the a user fails
to authenticate himself.

Permanent fix:
Change the uid of the program to the user's uid as early as possible
(patches from the development team are included, plus two other
security patches for kth-kerberos which might be useful to the bugtraq
community).

_- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - _
| Mattias Amnefelt               | This is a Unix system, I know this. |
| email: mattiasa@stacken.kth.se |              - Lex, Jurassic Park   |
| phone: +46-(0)70-6970872       |                                     |
-_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ -


------- Start of forwarded mail -------

>From assar@sics.se Tue Nov  4 22:08:18 1997
Date: 03 Nov 1997 18:35:40 +0100
From: Assar Westerlund <assar@sics.se>
To: krb4@sics.se, krb4-announce@sics.se
Subject: security patches for 0.9.6

The enclosed patch to 0.9.6 fixes three security problems:

1. the tgetent buffer overflow.  This is fixed by simply not calling
tgetent.

2. vulnerability of setuid rsh, rlogin, and rcp.  (mentioned in a
confusion post on bugtraq).

3. missing IP-nummer check in telnetd.

NOTE: we recommend against running rsh/rlogin/rcp setuid.

This fix will of course be included in an upcoming version RSN.

Assar, Bjorn, and Johan

Index: appl/bsd/rcp.c
===================================================================
RCS file: /afs/pdc.kth.se/src/packages/kth-krb/src/krb4/appl/bsd/rcp.c,v
retrieving revision 1.43
retrieving revision 1.44
diff -u -w -r1.43 -r1.44
--- rcp.c       1997/05/13 09:41:26     1.43
+++ rcp.c       1997/11/03 11:18:02     1.44
@@ -49,6 +49,9 @@
 static uid_t   userid;
 static int pflag, iamremote, iamrecursive, targetshouldbedirectory;

+static int argc_copy;
+static char **argv_copy;
+
 #define        CMDNEEDS        64
 static char cmd[CMDNEEDS];             /* must hold "rcp -r -p -d\0" */

@@ -403,8 +406,9 @@
 kerberos(char **host, char *bp, char *locuser, char *user)
 {
         int sock = -1, err;
-again:
+
        if (use_kerberos) {
+               setuid(getuid());
                rem = KSUCCESS;
                errno = 0;
                if (dest_realm == NULL)
@@ -439,13 +443,11 @@
                    rem = sock;
 #endif
                if (rem < 0) {
-                       use_kerberos = 0;
-                       port = get_shell_port(use_kerberos, 0);
                        if (errno == ECONNREFUSED)
                            oldw("remote host doesn't support Kerberos");
                        else if (errno == ENOENT)
                            oldw("can't provide Kerberos authentication data");
-                       goto again;
+                       execv(_PATH_RCP, argv_copy);
                }
        } else {
                if (doencrypt)
@@ -906,8 +908,28 @@
 {
        int ch, fflag, tflag;
        char *targ;
+       int i;

        set_progname(argv[0]);
+
+       /*
+        * Prepare for execing ourselves.
+        */
+
+       argc_copy = argc + 1;
+       argv_copy = malloc((argc_copy + 1) * sizeof(*argv_copy));
+       if (argv_copy == NULL)
+           err(1, "malloc");
+       argv_copy[0] = argv[0];
+       argv_copy[1] = "-K";
+       for(i = 1; i < argc; ++i) {
+           argv_copy[i + 1] = strdup(argv[i]);
+           if (argv_copy[i + 1] == NULL)
+               errx(1, "strdup: out of memory");
+       }
+       argv_copy[argc + 1] = NULL;
+
+
        fflag = tflag = 0;
        while ((ch = getopt(argc, argv, OPTIONS)) != EOF)
                switch(ch) {                    /* User-visible flags. */
@@ -951,8 +973,10 @@
         * kshell service, pass 0 for no encryption */
        port = get_shell_port(use_kerberos, 0);

+       userid = getuid();
+
 #ifndef __CYGWIN32__
-       if ((pwd = k_getpwuid(userid = getuid())) == NULL)
+       if ((pwd = k_getpwuid(userid)) == NULL)
                errx(1, "unknown user %d", (int)userid);
 #endif

Index: appl/bsd/rlogin.c
===================================================================
RCS file: /afs/pdc.kth.se/src/packages/kth-krb/src/krb4/appl/bsd/rlogin.c,v
retrieving revision 1.61
retrieving revision 1.62
diff -u -w -r1.61 -r1.62
--- rlogin.c    1997/05/25 01:14:47     1.61
+++ rlogin.c    1997/11/03 11:18:09     1.62
@@ -594,14 +594,12 @@
                        usage();
                }
        optind += argoff;
-       argc -= optind;
-       argv += optind;

        /* if haven't gotten a host yet, do so */
-       if (!host && !(host = *argv++))
+       if (!host && !(host = argv[optind++]))
                usage();

-       if (*argv)
+       if (argv[optind])
                usage();

        if (!(pw = k_getpwuid(uid = getuid())))
@@ -609,7 +607,6 @@
        if (!user)
            user = pw->pw_name;

-
        if (user_port)
                sv_port = user_port;
        else
@@ -636,17 +633,8 @@

        get_window_size(0, &winsize);

-      try_connect:
        if (use_kerberos) {
-               struct hostent *hp;
-
-               /* Fully qualify hostname (needed for krb_realmofhost). */
-               hp = gethostbyname(host);
-               if (hp != NULL && !(host = strdup(hp->h_name))) {
-                   errno = ENOMEM;
-                   err(1, NULL);
-               }
-
+               setuid(getuid());
                rem = KSUCCESS;
                errno = 0;
                if (dest_realm == NULL)
@@ -659,15 +647,22 @@
                        rem = krcmd(&host, sv_port, user, term, 0,
                            dest_realm);
                if (rem < 0) {
-                       use_kerberos = 0;
-                       if (user_port == 0)
-                               sv_port = get_login_port(use_kerberos,
-                                                        doencrypt);
+                   int i;
+                   char **newargv;
+
                        if (errno == ECONNREFUSED)
                            warning("remote host doesn't support Kerberos");
                        if (errno == ENOENT)
                          warning("can't provide Kerberos auth data");
-                       goto try_connect;
+                   newargv = malloc((argc + 2) * sizeof(*newargv));
+                   if (newargv == NULL)
+                       err(1, "malloc");
+                   newargv[0] = argv[0];
+                   newargv[1] = "-K";
+                   for(i = 1; i < argc; ++i)
+                       newargv[i + 1] = argv[i];
+                   newargv[argc + 1] = NULL;
+                   execv(_PATH_RLOGIN, newargv);
                }
        } else {
                if (doencrypt)
Index: appl/bsd/rsh.c
===================================================================
RCS file: /afs/pdc.kth.se/src/packages/kth-krb/src/krb4/appl/bsd/rsh.c,v
retrieving revision 1.36
retrieving revision 1.37
diff -u -w -r1.36 -r1.37
--- rsh.c       1997/06/26 13:48:35     1.36
+++ rsh.c       1997/11/03 11:18:14     1.37
@@ -247,9 +247,6 @@
        err(1, "can't exec %s", _PATH_RLOGIN);
     }

-    argc -= optind;
-    argv += optind;
-
 #ifndef __CYGWIN32__
     if (!(pw = k_getpwuid(uid = getuid())))
        errx(1, "unknown user id.");
@@ -266,12 +263,12 @@
     if (doencrypt)
        nfork = 0;

-    args = copyargs(argv);
+    args = copyargs(argv+optind);

     sv_port=get_shell_port(use_kerberos, doencrypt);

-try_connect:
     if (use_kerberos) {
+       setuid(getuid());
        rem = KSUCCESS;
        errno = 0;
        if (dest_realm == NULL)
@@ -284,13 +281,22 @@
            rem = krcmd(&host, sv_port, user, args, &rfd2,
                        dest_realm);
        if (rem < 0) {
+           int i;
+           char **newargv;
+
            if (errno == ECONNREFUSED)
                warning("remote host doesn't support Kerberos");
            if (errno == ENOENT)
                warning("can't provide Kerberos auth data");
-           use_kerberos = 0;
-           sv_port=get_shell_port(use_kerberos, doencrypt);
-           goto try_connect;
+           newargv = malloc((argc + 2) * sizeof(*newargv));
+           if (newargv == NULL)
+               err(1, "malloc");
+           newargv[0] = argv[0];
+           newargv[1] = "-K";
+           for(i = 1; i < argc; ++i)
+               newargv[i + 1] = argv[i];
+           newargv[argc + 1] = NULL;
+           execv(_PATH_RSH, newargv);
        }
     } else {
        if (doencrypt)
Index: appl/bsd/pathnames.h
===================================================================
RCS file: /afs/pdc.kth.se/src/packages/kth-krb/src/krb4/appl/bsd/pathnames.h,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -w -r1.23 -r1.24
--- pathnames.h 1996/11/17 06:36:42     1.23
+++ pathnames.h 1997/11/03 11:17:19     1.24
@@ -65,6 +65,9 @@
 #undef _PATH_RSH               /* Redifine rsh */
 #define _PATH_RSH      BINDIR  "/rsh"

+#undef _PATH_RCP               /* Redifine rcp */
+#define _PATH_RCP      BINDIR  "/rcp"
+
 #undef _PATH_LOGIN
 #define _PATH_LOGIN    BINDIR "/login"

@@ -186,6 +189,8 @@
 #define        _PATH_RLOGIN    "/usr/athena/bin/rlogin"
 #undef  _PATH_RSH
 #define _PATH_RSH      "/usr/athena/bin/rsh"
+#undef  _PATH_RCP
+#define _PATH_RCP      "/usr/athena/bin/rcp"
 #undef  _PATH_LOGIN
 #define _PATH_LOGIN    "/usr/athena/bin/login"
 #endif


Index: appl/telnet/libtelnet/kerberos.c
===================================================================
RCS file: /afs/pdc.kth.se/src/packages/kth-krb/src/appl/telnet/libtelnet/kerberos.c,v
retrieving revision 1.34
retrieving revision 1.36
diff -u -w -r1.34 -r1.36
--- kerberos.c  1997/10/21 21:15:24     1.34
+++ kerberos.c  1997/11/03 06:12:14     1.36
@@ -265,9 +267,11 @@
 void
 kerberos4_is(Authenticator *ap, unsigned char *data, int cnt)
 {
+    struct sockaddr_in addr;
     char realm[REALM_SZ];
     char instance[INST_SZ];
     int r;
+    int addr_len;

     if (cnt-- < 1)
        return;
@@ -288,8 +292,17 @@
            printf("\r\n");
        }
        k_getsockinst(0, instance, sizeof(instance));
-       if (r = krb_rd_req(&auth, KRB_SERVICE_NAME,
-                          instance, 0, &adat, "")) {
+       addr_len = sizeof(addr);
+       if(getpeername(0, (struct sockaddr *)&addr, &addr_len) < 0) {
+           if(auth_debug_mode)
+               printf("getpeername failed\r\n");
+           Data(ap, KRB_REJECT, "getpeername failed", -1);
+           auth_finished(ap, AUTH_REJECT);
+           return;
+       }
+       r = krb_rd_req(&auth, KRB_SERVICE_NAME,
+                      instance, addr.sin_addr.s_addr, &adat, "");
+       if (r) {
            if (auth_debug_mode)
                printf("Kerberos failed him as %s\r\n", name);
            Data(ap, KRB_REJECT, (void *)krb_get_err_text(r), -1);
Index: appl/telnet/telnetd/telnetd.c
===================================================================
RCS file: /afs/pdc.kth.se/src/packages/kth-krb/src/appl/telnet/telnetd/telnetd.c,v
retrieving revision 1.47
retrieving revision 1.48
diff -u -w -r1.47 -r1.48
--- telnetd.c   1997/10/29 01:26:58     1.47
+++ telnetd.c   1997/11/03 06:08:26     1.48
@@ -647,21 +647,7 @@
 int
 terminaltypeok(char *s)
 {
-    char buf[1024];
-
-    if (terminaltype == NULL)
-       return(1);
-
-    /*
-     * tgetent() will return 1 if the type is known, and
-     * 0 if it is not known.  If it returns -1, it couldn't
-     * open the database.  But if we can't open the database,
-     * it won't help to say we failed, because we won't be
-     * able to verify anything else.  So, we treat -1 like 1.
-     */
-    if (tgetent(buf, s) == 0)
-       return(0);
-    return(1);
+    return 1;
 }

More Exploits!

The master index of all exploits is available here (Very large file)
Or you can pick your favorite operating system:
All OS's Linux Solaris/SunOS Micro$oft
*BSD Macintosh AIX IRIX
ULTRIX/Digital UNIX HP/UX SCO Remote exploits

This page is part of Fyodor's exploit world. For a free program to automate scanning your network for vulnerable hosts and services, check out my network mapping tool, nmap. Or try these Insecure.Org resouces:

[ Nmap | Sec Tools | Mailing Lists | Site News | About/Contact | Advertising | Privacy ]
AlienVault