The 'Security Digest' Archives (TM)

Archive: About | Browse | Search | Contributions | Feedback
Site: Help | Index | Search | Contact | Notices | Changes

ARCHIVE: Unix 'Security Mailing List' - Archives (1984 - 1987)
DOCUMENT: Unix 'Security Mailing List' #10 1985-03-17 (1 file, 4963 bytes)
SOURCE: http://securitydigest.org/exec/display?f=unix/archive/010.txt&t=text/plain
NOTICE: securitydigest.org recognises the rights of all third-party works.

START OF DOCUMENT


Date: 17 Mar 1985 2323-MST (Sunday)
Subject: Security Mailing List, # 10

----------------------------------------------------------------------------
Editor's corner
        Nothin' new to say.

Newcomers to the list since last issue:
        Bernie Cosell (bbn-labs-b!cosell@ihnp4)
        Clifford Neuman (bcn@mit-eddie)
        Bjorn Eriksen (ber@enea)
        Carter (carter@gatech)
        Michael Dove (emacs@ucscc)
        Jim Guyton (guyton@randvax)
        Johan Finnved (jf@sal)
        Mike Hammond (mike@tesla)
        Mark Plotnick (mp@allegra)
        Larry Pajakowski (root@extel)
        Sarge Wong (sarge@cbosgd)
        Kevin Smallwood (security@purdue)

----------------------------------------------------------------------------

Date: 12 Mar 85 12:45:45 CST (Tue)
From: ihnp4!ucla-cs!lcc!gm
Subject:        SUID shell scripts --and-- mesg [ y ] [ n ]

The best way I know of to plug the SUID shell script security problem
involving #! and scripts beginning with '-' is to fix the kernel so
that it puts the name of the interpreter (typically /bin/sh or
/bin/csh) into argv[0] instead of the name of the script.  There is no
observable difference within the script because in either case, the
shell provides the shell provides the script's name in $0.  This also
cures the annoying problem with using the SVR2 /bin/sh to interpret
scripts that contain the letter 'r' in their last path-component--if
the shell sees an 'r' it makes the shell restricted!  We originally
fixed our kernel to put the interpreter name in argv[0] to get around
the restricted shell problem, but I quickly recognized that it fixes
the security problem also.  Last but not least, it really is more correct.

As for the technique of snatching control of another's terminal via
setpgrp() and TIOCSTI if the terminal is writeable, I propose the
following:  Make talk(1) and write(1) setuid root. (yuk)   Make ttys
mode 711 by default.  Make talk(1) and write(1) examine the execute
bit to determine whether the user is open to conversation.  It will
not be possible for another user to open(2) or write(2) to a terminal
directly, but conversation via talk(1) and write(1) will still be available.

Greg McGary
Locus Computing Corporation                                    lcc!gm@ucla-cs
                                                {ucivax,trwrb}!lcc!gm
                 {ihnp4,randvax,sdcrdcf,ucbvax,trwspp}!ucla-cs!lcc!gm

----------------------------------------------------------------------------

Date: Tue, 12 Mar 85 18:54:37 est
From: ihnp4!watmath!sunybcs!loverso (John Robert LoVerso)
Subject: Re: addition to unix security list

Enclosed is the stuff on sendmail as mailed to me by Keith Muller:
--
Date: Wed, 12 Sep 84 20:16:10 pdt
From: rocksvax!amd!ihnp4!sdcsvax!sdcc3!muller (Keith Muller)
Subject: sendmail bugs

NOTE: PLEASE PROTECT THIS LETTER. A lot of sites exsist that have these
      bugs that do not have source. ALSO DO NOT post to netnews as the
      backlash from this is much worse than the fix. There are a lot
      of sites that do not read net.bugs and they won't appreciate this
      "how to bust their system letter".

      PLEASE pass this info on to any other system people you know of.

      UCB knows about these bugs.
-----------------------------------------------------------------------
There are two VERY SERIOUS security holes in sendmail. If sendmail runs
with the setuid root bit on, ANY user can get a root shell. The other
problem allows any user to read ANY file in the system.

Problem 1) Reading any file in the system. 

To see if you have this problem:
        cd /tmp
        /usr/lib/sendmail -Cno_READ_file >& OUTPUT&

        Where file is some file that the user who executes this
        command SHOULD NOT be able to read. If you have the contents
        of no_READ_file in the file OUTPUT you have the bug.

The -C flag allows you to specify a configuration file other than the
default sendmail.cf. The routines in readcf.c blindly opens the file and
start parsing it. If the file is NOT a proper sendmail.cf file,
sendmail complains and ECHOS the offending file to standard output. The
fix requires placing an access call before the fopen(cfname. "r") in
readcf.c.
-------------------------readcf.c-------------------------------
        #include <sys/file.h>

        if (access(cfname, R_OK) != 0){
                syserr("cannot access %s", cfname);
                exit(EX_OSFILE);
        }
        cf = fopen(cfname, "r");
        if (cf == NULL)
        {
                syserr("cannot open %s", cfname);
                exit(EX_OSFILE);
        }
-------------------------------------------------------------------

2) Problem 2 is MUCH WORSE!

You have this problem if one of the following sequence of commands gives
you a root shell.

        /usr/lib/sendmail -bs
        ---some output muck-----
        you type: wiz
        it then prints: Please pass, oh mighty wizard
        you type: shell

            ---or---
        (this case if a sendmail.fc exsists but is null or messed up)

        cp /usr/lib/sendmail.cf foo.cf
        /usr/lib/sendmail -Cfoo.cf -bs
        ---some output muck-----
        you type: wiz
        it then prints: Please pass, oh mighty wizard
        you type: shell

NOTE: This bug also will exsist if you run a sendmail smtp server as root
and some smart user writes the trival program to connect to the server. This
means that if your machine is on an eithernet anyone on the eithernet can
get root on your machine without having an account on your machine.

The problem involves some questionable code in srvrsmtp.c involving WizWord.
The problem is twofold. The code as written allows empty passwords.
The second part is the way the actual encrypted string is assigned
to the variable WizWord. If a value is found for WizWord (which is
defined as char *WizWord = NULL) in the cf file space is allocated for it
by a call to malloc and that address is placed in WizWord.
(WizWord = newstr(val), where newstr uses malloc()). 

Now the problem occurs when the frozen config files are used. The way the
code is writen a frozen file consists of the entire contents of the
UNINITIALIZED data segment. When sendmail starts up that file is read up
and sets all the UNINITIALIZED global variables. Now the string that contains
the wizards password is in this file (because it was obtained with malloc),
but the pointer variable IS NOT due to the fact that it was defined as:
        char *WizWord = NULL;

So this sendmail has an empty wizards password even though one was defined
in the cf file.

The fix can be done in many ways. If you want to keep the wizard option:

---------------------------srvrsmtp.c--------------------------
Change the defination of WizWord to:

char *WizWord;

change the routine in the case CMDDBGWIZ: should read:

                  case CMDDBGWIZ:       /* become a wizard */
                        if (WizWord != NULL)
                        {
                                char seed[3];
                                extern char *crypt();

                                strncpy(seed, WizWord, 2);
                                if (strcmp(WizWord, crypt(p, seed)) == 0)
                                {
                                        IsWiz = TRUE;
                                        message("200", "Please pass, oh mighty wizard");
                                        break;
                                }
                        }
                        message("500", "You are no wizard!");
                        break;

                --------end of case fix---------

The other way (if you really want to remove all the "trojan horse" code)
is to enclose the nasty commands inside an ifdef WIZMODE that is not defined.

-------alternate delete the nasty code fix-------------

                  case CMDDBGDEBUG:     /* set debug mode */
                        tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
                        tTflag(p);
                        message("200", "Debug set");
                        break;

# ifdef WIZMODE
                  case CMDDBGKILL:      /* kill the parent */
                        if (!iswiz())
                                break;
                        if (kill(MotherPid, SIGTERM) >= 0)
                                message("200", "Mother is dead");
                        else
                                message("500", "Can't kill Mom");
                        break;

                        :
                        : lines left out here for this letter
                        :

                  case CMDDBGWIZ:       /* become a wizard */
                        if (WizWord != NULL)
                        {
                                char seed[3];
                                extern char *crypt();

                                strncpy(seed, WizWord, 2);
                                if (strcmp(WizWord, crypt(p, seed)) == 0)
                                {
                                        IsWiz = TRUE;
                                        message("200", "Please pass, oh mighty wizard");
                                        break;
                                }
                        }
                        message("500", "You are no wizard!");
                        break;
# endif WIZMODE

-------------end of delete the code fix------------

--------------------end of fixes--------------------------

Keith Muller
UCSD Computer Center


----------------------------------------------------------------------------

/*
From: ihnp4!sun!l5!gnu (John Gilmore)
Date: 13 Mar 1985 1910-PST (Wednesday)
Subject: Re: Checking for trivial passwords

Here's a program that's been passed around awhile for checking your
password file against stupidity.  I got it from Brian Reid who got it
from (Berkeley?).  I added the stuff that reads from standard input
(requires copying /usr/src/usr.lib/libc/gen/getpwent.c onto the end of
this) so you can rcp or ftp /etc/passwd from a bunch of machines and do
the validation on a separate machine.  It burns a lot of CPU.
*/

/*
Date: Wednesday, 30 November 1983 08:19:06-PST
From: Brian Reid <reid@Glacier>
Subject: Re: Can you mail me the password-guessing program?
*/

/*
 * Insecure - find accounts with poor passwords
        Date: Tue, 29 Nov 83 18:19:32 pst
        From: leres%ucbarpa@Berkeley (Craig Leres)
 */

#include <stdio.h>
#include <pwd.h>

/* #define DEBUG */
/* #define SINGLETTER */

struct  passwd *pwd;
char *index();

main(argc, argv)
char **argv;
{
    struct passwd *getpwent();
    char guess[100];
    char *cp, *cp2;

    setpwfile(stdin);           /* Read password file from stdin */

    while ((pwd = getpwent()) != 0 ) {
#ifdef DEBUG
        printf("\t%s \"%s\"\n", pwd->pw_name, pwd->pw_gecos);
        fflush(stdout);
#endif
        if (*pwd->pw_passwd == '\0') {
            printf("Null passwd:\t%s\tshell: %s\n",
             pwd->pw_name, pwd->pw_shell);
            fflush(stdout);
            continue;
        }
        /*
         * Try the user's login name
         */
        if (try(pwd->pw_name))
            continue;
        /*
         * Try names from the gecos field
         */
        strcpy(guess, pwd->pw_gecos);
        cp = guess;
        if ((cp2 = index(cp, ',')) != 0)
            *cp2 = '\0';

        for (;;) {
            if ((cp2 = index(cp, ' ')) == 0) {
                if (*cp != '&')
                    try(cp);
                break;
            }
            *cp2 = '\0';
            if (*cp == '&')
                continue;
            if (try(cp))
                break;
            cp = ++cp2;
        }
            
#ifdef SINGLETTER
        /*
         * Try all single letters
         */
        guess[1] = '\0';
        for (guess[0]='a'; guess[0] <= 'z'; guess[0]++)
            if (try(guess))
                break;
#endif
    }
    endpwent();
}

try(guess)
char *guess;
{
    register char *cp;
    char *crypt();

#ifdef DEBUG
    printf("Trying \"%s\" on %s\n", guess, pwd->pw_name);
    fflush(stdout);
    return(0);
#else
    cp = crypt(guess, pwd->pw_passwd);
    if (strcmp(cp, pwd->pw_passwd))
        return(0);
    printf("Guessed:\t%s\tshell: %s\n", pwd->pw_name, pwd->pw_shell);
    fflush(stdout);
    return(1);
#endif
}
/* end of PW guessing program */

/*
 * Add a function to "getpwent" so I can override the file name.
 *
 * This doesn't really work with the standard library routine, because
 * it declares pwf as "static".  You have to copy the source into
 * here instead.
 */
extern FILE *pwf;

setpwfile(file)
FILE *file;
{
        pwf = file;
}


----------------------------------------------------------------------------

From: ihnp4!mhuxi!princeton!down!honey
Date: 14 Mar 1985 13:09-EST
Subject: Re: Treatise on uucp needed

old-and-tired uucp is a hopeless case.  it is impossible to provide a
reasonable level of protection.  furthermore, the defaults are to leave
your system wide open.  i urge you to consider honey danber for your
uucp needs.
        peter

----------------------------------------------------------------------------

                    The UNIX security issues mail list

               Ignore the headers on this list and mail to:
           ...denelcor!security            (mail for the list).
            ...denelcor!sec-request         (administrativia).

END OF DOCUMENT