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' #23 1987-03-11 (1 file, 7608 bytes)
SOURCE: http://securitydigest.org/exec/display?f=unix/archive/023.txt&t=text/plain
NOTICE: securitydigest.org recognises the rights of all third-party works.

START OF DOCUMENT


Date: Wed, 11 Mar 87 08:10:13 mst
Subject: Security Mailing List, # 23 [repost]

-------

I don't know what happened to Lyle's distribution near the end, but
many people have reported that their last issue was #22.5; I have a #23
and #24 in the archives, so to make sure everyone has 23 and 24 I am
simply sending them out again.

This is not really issue #23, but the first half (in terms of line count)
of the archive that houses 23 and 24.  Thus this message is not all of #23;
the next will be the rest of #23 and all of #24.  The headers below are
here simply because they were present in the archive.

In the near future I will send out the first NEW issue (to be #26);
which will include the current list membership.

Issue #23: 25-Jun-86
  13-Aug-85 john@basser.oz   Re: Unix PC's mv has the uid bit set
  4-Oct-85  setha@hercules   improved password checker
  10-Oct-85 mjs@sfdoc        What a "UNIX PC" is.
  23-Oct-85 gduncan@vax-populi ?Innocent? find(1) bug turned vicious
  15-Jan-86 parmelee@bullwinkle Re: Security List?
  20-Aug-85 madden@harvard   Re: One way encryptions
  25-Jun-86 lmc@cisden       public key encryptions broken
Issue #24: 1-July-86
  13-May-86 hosking@convex   crock in 4.2 kern_sig
  12-May-86 hedrick@topaz    Bridge terminal servers
  15-May-86 dave@lsuc        security hole in compress
  14-May-86 geoff@desint     more Bridge security comments
  13-May-86 ljp@trwrb        Pyramid security problems -- at(1) and the att universe
  19-May-86 romain@pyrnj     uusend setuid hole (bsd)
  23-May-86 john@basser.oz   Security publishing
  27-May-86 gduncan@vax-populi ?Innocent? find(1) bug turned vicious
  5-Jun-86  haynes@ucscc     I keep wondering
  5-Jun-86  haynes@ucscc     Followup on the /dev/tty story
  5-Jun-86  haynes@ucscc     Well that didn't work
  26-Jun-86 bzs@bu-cs        Re: creating new user accounts
  26-Jun-86 geoff@desint     choosing passwords in large numbers
  26-Jun-86 bees@infoswx     Re: One way encryptions (from #23)
  26-Jun-86 andrew@blade.me.brunel.ac.uk  /etc/passwd lockup
  27-Jun-86 daved@onficanim  Re: more mv with suid bit on

============================================================================

From: hao!seismo!munnari!basser.oz!john
Date: Tue, 13 Aug 85 03:05:36 EST
Subject: Re: Unix PC's mv has the uid bit set

> From: ihnp4!decvax!cwruecmp!nitrex!rob
>
> A friend just pointed this out, I don't really know if it is old news or not,
> but on the Unix Pc the system software is shipped with the set uid bit
> set on /bin/mv.

Sigh.  This is NOT (or at least should not be) a security hole; have you
ACTUALLY TRIED mv'ing things that you shouldn't have had permission to mv?
If not, for shame, mv is supposed to do all the right checks.  If so (and
I assume by Unix PC you mean 3B2, do please be more specific) then this
machine's mv is seriously broken, but the fact that it is setuid-root
is no accident, it *needs* that power.  Last I heard, you could use "mv"
to rename directories ("mv dir1 dir2") -- and like unlink(2) says, "It is
also illegal to unlink a driectory (except for the super-user)."  This
is because the code in unlink() is not really in a position to check
whether a directory is empty or not.  rmdir is setuid-root for the
same reason.

John Mackin, Basser Department of Computer Science,
             University of Sydney, Sydney, Australia
             ...!seismo!munnari!basser.oz!john

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

From: <hao!hplabs!tektronix!hercules!setha>
Date: Friday, 4 Oct 85 10:50:38 PDT
Subject: improved password checker

Several of us modified the password checking program which appeared
in an earlier edition of the mailing list.  The program now can
guess passwords backwords, try upper and lower case, read a list of
possible passwords from a file, and give you a list of its options.

Bill Landreth's "Out of the Inner Circle, a Hacker's Guide to
Computer Security" is a very good reference on how to protect
your system against teenage crackers.  Landreth includes a list
of commonly used passwords.  In addition to the words on the
list, Landreth also recommends trying the name or nickname of the
company or organization which owns the computer.  Here's
Landreth's commonly used passwords, followed by the improved
password guessing program.  To try this list, or another, put
the list into a file, and run the password checker and specify
the -w option.

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

love
sex
secret
demo
games
test
account
intro
password
alpha
hello
kill
beta
dollar
dead
system
computer
work
yes
no

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

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

#ifndef lint
static char *rcsid = "$Header: pwchkr.c,v 1.1 85/09/10 16:00:56 root Exp $";
#endif

/*
 * Warning: this program burns a lot of cpu.
 */
/*
 * Insecure - find accounts with poor passwords
        Date: Tue, 29 Nov 83 18:19:32 pst
        From: leres%ucbarpa@Berkeley (Craig Leres)
            Modified by Seth Alford, Roger Southwick, Steve Dum, and
            Rick Lindsley for Tektronix
 */

/*
 *      $Log:   pwchkr.c,v $
 *      Revision 1.1  85/09/10  16:00:56  root
 *      Initial revision
 *
 *
 * By default, this program only checks for accounts with passwords the same
 * as the login name. The following options add more extensive checking. (The
 * tradeoff is cpu time -- with all options enabled it can run into the 100's
 * of MINUTES.) Any argument that does not begin with a "-" is assumed to be
 * a file name. (A single '-' means stdin.) If no file name is given,
 * /etc/passwd is used.
 *
 * Options:
 *
 *              -v:     verbose -- list all guesses on stdout
 *              -u:     output the username on the line of the password file
 *                      currently being checked. If the program stops
 *                      abruptly you will then know how far it got.
 *              -w file: use the list of words contained in "file" as likely
 *                      passwords. Words in the file are one to a line.
 *              -b:     check all guesses backwards too
 *              -g:     use the Full Name portion of the gecos field to
 *                      generate more guesses
 *              -s:     check the single letters a-z, A-Z, 0-9 as passwords
 *              -c:     with each guess, check for all-lowercase and
 *                      all-uppercase versions too.
 *              -n:     complain about null passwords (default is to keep quiet)
 *              -p:     print the password when guessed
 */

int verbose = 0, singles = 0, backwards = 0, checkgecos = 0, checkcase = 0,
    chknulls = 0, printit = 0, users = 0, chkwords = 0;

char *index(), *reverse();
long atol();
FILE *fopen();
char *fgets();

char PASSWD[] = "/etc/passwd";
char EMPTY[] = "";
static FILE *pwf = NULL, *wlf = NULL;
char line[BUFSIZ+1];
struct passwd passwd;
char    *Curpw, *Wordlist = NULL;

main(argc, argv)
char **argv;
{
    register int i;
    register char *arg;
    int onedone = 0;

    if (getuid()) {
        printf("Did you really think we would let you run this?\n");
        exit(1);
        }
    for (i = 1; i < argc; i++)
        if ((arg = argv[i]) && *arg == '-')
            while (*++arg) {
                switch (*arg) {
                    case 'n':
                        /*
                         * complain about null passwords
                         */
                        chknulls++;
                        break;
                    case 'c':
                        /*
                         * check cases
                         */
                        checkcase++;
                        break;
                    case 'g':
                        /*
                         * use gecos
                         */
                        checkgecos++;
                        break;
                    case 'v':
                        /*
                         * turn on motormouth
                         */
                        verbose++;
                        break;
                    case 'b':
                        /*
                         * check all attempts forwards and backwards
                         */
                        backwards++;
                        break;
                    case 's':
                        /*
                         * carry out a more intensive search, checking for
                         * single letter passwords
                         */
                        singles++;
                        break;
                    case 'p':
                        /*
                         * print out the password when found
                         */
                        printit++;
                        break;
                    case 'u':
                        /*
                         * print out users as testing
                         */
                        users++;
                        break;
                    case 'w':
                        /*
                         * consult word list of likely passwords
                         */
                        if ((Wordlist = argv[i+1]) == NULL) {
                            fprintf(stderr,
                                "%s: No file supplied with -w option\n",
                                argv[0]);
                            exit (1);
                            }
                        argv[i+1] = NULL;
                        break;
                    case '\0':
                        /*
                         * read from stdin
                         */
                        break;
                    default:
                        fprintf(stderr,
                            "%s: unknown option '%c'. Options are:\n",argv[0],
                            *arg);
                        /* FALL THRU */
                    case '-':
                        fprintf(stderr,"-v:\t\tverbose -- list all guesses on stdout\n");
                        fprintf(stderr,"-u:\t\toutput the username currently being checked\n");
                        fprintf(stderr,"-w file:\tconsult the indicated file for words to check as passwords\n");
                        fprintf(stderr,"-b:\t\tcheck all guesses forwards and backwards\n");
                        fprintf(stderr,"-g:\t\tuse the Full name portion of the gecos field for more guesses\n");
                        fprintf(stderr,"-s:\t\tcheck the single letters a-z, A-Z, 0-9 as passwords\n");
                        fprintf(stderr,"-c:\t\tcheck the all-upper and all-lower case version of each guess\n");
                        fprintf(stderr,"-n:\t\tcomplain about null passwords\n");
                        fprintf(stderr,"-p:\t\tprint the password when guessed\n");
                        exit(1);
                    }
                argv[i] = NULL;
                }

    for (i = 1; i < argc; i++) {
        if (argv[i] == NULL) continue;
        onedone++;
        if (*(argv[i]) == '-') {
            /*
             * read from stdin; we'll cheat and set pwf directly
             */
            pwf = stdin;
            chkpw();
            /*
             * don't fclose stdin!
             */
            clearerr(stdin);
            }
        else {
            if (setpwent(argv[i])) {
                perror(argv[i]);
                continue;
                }
            Curpw = argv[i];
            chkpw();
            endpwent();
            }
        }
    if (!onedone) {
        Curpw = NULL;
        chkpw();
        }
    exit(0);
}

#define ARB_CONST       5

chkpw()

{
    register char       *cp, *cp2;
    register struct passwd *pwd;
    struct passwd       *getpwent();
    char                guess[100];
    char                *wordarray[ARB_CONST];
    char                *malloc(), **wordptr, **endptr;
    int                 done = 0;


    if (Wordlist)
    {
        if ((wlf = fopen(Wordlist,"r")) == NULL)
        {
            perror(Wordlist);
            exit(1);
        }

        wordptr = wordarray;
        /*
         * note that endptr points to space OUTSIDE of wordarray
         */
        endptr = wordarray + (sizeof(wordarray)/sizeof(char *));

        while (fscanf(wlf,"%[^\n]\n",guess) != EOF)
        {
            if (wordptr == endptr)
            {
                fprintf(stderr,"Ran out of wordlist space. ARB_CONST %d must be too small.\n", ARB_CONST);
                exit(1);
            }
            if ((*wordptr = malloc(1+strlen(guess))) == NULL)
            {
                fprintf(stderr,"malloc: no more memory for wordlist\n");
                exit (1);
            }
            strcpy(*wordptr,guess);
            wordptr++;
        }
        *wordptr = NULL;
    }

    while ((pwd = getpwent()) != 0 ) {

        if (verbose || users) {
            if (Curpw == NULL)
                printf("\t%s \"%s\"\n", pwd->pw_name, pwd->pw_gecos);
            else
                printf("%s -- \t%s \"%s\"\n", Curpw, pwd->pw_name,
                    pwd->pw_gecos);
            fflush(stdout);
            }
        if (*pwd->pw_passwd == '\0') {
            if (chknulls) {
                if (Curpw == NULL)
                    printf("Problem: null passwd:\t%s\tshell: %s\n",
                        pwd->pw_name, pwd->pw_shell);
                else
                    printf("%s -- Problem: null passwd:\t%s\tshell: %s\n",
                        Curpw, pwd->pw_name, pwd->pw_shell);
                fflush(stdout);
                }
            continue;
        }
        /*
         * Try the user's login name
         */
        if (uandltry(pwd,pwd->pw_name))
            continue;

        /*
         * Try names from the gecos field
         */
        if (checkgecos) {
            strcpy(guess, pwd->pw_gecos);
            cp = guess;
            if (*cp == '-') cp++;               /* special gecos field */
            if ((cp2 = index(cp, ';')) != NULL)
                *cp2 = '\0';

            for (;;) {
                if ((cp2 = index(cp, ' ')) == NULL) {
                    if (uandltry(pwd,cp))
                        done++;
                    break;
                    }

                *cp2 = '\0';

                if (uandltry(pwd,cp)) {
                    done++;
                    break;
                    }
                cp = ++cp2;
                }
            }

        if (!done && Wordlist)
        {
            /*
             * try the words in the wordlist
             */
            wordptr = wordarray;
            while (endptr != wordptr)
            {
                if (*wordptr == NULL)
                    break;
                if (uandltry(pwd,*wordptr++))
                {
                    done++;
                    break;
                }
            }
        }
        if (!done && singles) {
            /*
             * Try all single letters
             * (try digits too .  --Seth)
             */
            guess[1] = '\0';
            for (guess[0]='a'; guess[0] <= 'z'; guess[0]++)
                if (try(pwd,guess))
                    break;
            for (guess[0]='A'; guess[0] <= 'Z'; guess[0]++)
                if (try(pwd,guess))
                    break;
            for (guess[0]='0'; guess[0] <= '9'; guess[0]++)
                if (try(pwd,guess))
                    break;
            }
    }
}

/*
 * Stands for "upper and lower" try.  Calls the "real" try, below,
 * with the supplied version of the password, and with
 * an upper and lowercase version of the password. If the user doesn't
 * want to try upper and lower case then we just return after the one
 * check.
*/

uandltry (pwd,guess)
char *guess;
struct passwd *pwd;
{
    register char *cp;
    char buf[100];
    int alllower, allupper;

    alllower = allupper = 1;

    if (try(pwd,guess) || (backwards && try(pwd,reverse(guess)))) return (1);

    if (!checkcase) return(0);

    strcpy (buf, guess);
    cp = buf-1;
    while (*++cp) {
        if (isupper(*cp))
            alllower = 0;
        if (islower(*cp))
            allupper = 0;
        }

    if (!allupper) {
        for ( cp=buf; *cp != '\0'; cp++)
            if (islower (*cp))
                *cp += 'A' - 'a';

        if (try(pwd,buf) || (backwards && try(pwd,reverse(buf)))) return (1);
        }

    if (!alllower) {
        for ( cp = buf; *cp != '\0'; cp++)
            if (isupper (*cp))
                *cp += 'a' - 'A';

        if (try(pwd,buf) || (backwards && try(pwd,reverse(buf)))) return (1);
        }
    return (0);
}

try(pwd,guess)
char *guess;
register struct passwd *pwd;
{
    register char  *cp;
    char   *crypt ();

    if (verbose) {
        if (Curpw == NULL)
            printf ("Trying \"%s\" on %s\n", guess, pwd -> pw_name);
        else
            printf ("%s -- Trying \"%s\" on %s\n", Curpw, guess,
                pwd -> pw_name);
        fflush (stdout);
        }
    if (! guess || ! *guess) return(0);
    cp = crypt (guess, pwd -> pw_passwd);
    if (strcmp (cp, pwd -> pw_passwd))
        return (0);
    if (Curpw == NULL)
        if (printit)
            printf ("Problem: Guessed:\t%s\tshell: %s passwd: %s\n",
                pwd -> pw_name, pwd -> pw_shell, guess);
        else
            printf ("Problem: Guessed:\t%s\tshell: %s\n", pwd -> pw_name,
                pwd -> pw_shell);
    else
        if (printit)
            printf ("%s -- Problem: Guessed:\t%s\tshell: %s passwd: %s\n",
                Curpw, pwd -> pw_name, pwd -> pw_shell);
        else
            printf ("%s -- Problem: Guessed:\t%s\tshell: %s\n",
                Curpw, pwd -> pw_name, pwd -> pw_shell);
    fflush (stdout);
    return (1);
}
/* end of PW guessing program */

#define MAXUID 0x7fff   /* added by tonyb 12/29/83 */
                        /* altered to a reasonable number - mae 8/20/84 */

/*
 * Add a parameter to "setpwent" so I can override the file name.
 */

setpwent(file)
char *file;
{
        if ((pwf = fopen(file,"r")) == NULL)
            return(1);
        return(0);
}

endpwent()

{
    fclose(pwf);
    pwf = NULL;
}

char *
pwskip(p)
register char *p;
{
        while(*p && *p != ':' && *p != '\n')
                ++p;
        if(*p == '\n')
                *p = '\0';
        else if(*p)
                *p++ = '\0';
        return(p);
}

struct passwd *
getpwent()
{
        register char *p;
        long    x;

        if(pwf == NULL)
            if (setpwent(PASSWD)) {
                perror(PASSWD);
                return(NULL);
                }
        p = fgets(line, BUFSIZ, pwf);
        if(p == NULL)
                return(0);
        passwd.pw_name = p;
        p = pwskip(p);
        passwd.pw_passwd = p;
        p = pwskip(p);
        x = atol(p);
        passwd.pw_uid = (x < 0 || x > MAXUID)? (MAXUID+1): x;
        p = pwskip(p);
        x = atol(p);
        passwd.pw_gid = (x < 0 || x > MAXUID)? (MAXUID+1): x;
        passwd.pw_comment = EMPTY;
        p = pwskip(p);
        passwd.pw_gecos = p;
        p = pwskip(p);
        passwd.pw_dir = p;
        p = pwskip(p);
        passwd.pw_shell = p;
        (void) pwskip(p);

        p = passwd.pw_passwd;

        return(&passwd);

}


/*
 * reverse a string
 */
char *reverse(str)
char *str;

{
    register char *ptr;
    register int len;
    char        *malloc();

    if ((ptr = malloc((len = strlen(str))+1)) == NULL)
        return(NULL);
    ptr += len;
    *ptr = '\0';
    while (*str && (*--ptr = *str++))
        ;
    return(ptr);
}


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

From: hao!seismo!ihnp4!sfdoc!mjs
Date: 10 Oct 85 12:00:23 CDT (Thu)
Subject: What a "UNIX PC" is.

The UNIX PC is NOT the 3B2.  It is a 68010-based box with integral bitmap
display (display is similar to IBM PC), which runs mostly System V Release
2 and partly SVR1 and partly BSD.  According to what I've heard from outside
the company (I am at ATT-IS), it is being renamed the 3B1.  As was discussed
much earlier, the fact that /bin/mv is setuid-root is NOT a security hole,
for the reasons cited most recently by basser.oz!john.

        Marty Shannon
        ihnp4!attunix!mjs
        +1 201 522 6063

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

Date: Wed, 23 Oct 85 14:15:09 pdt
From: hao!seismo!nrl-css.arpa!vax-populi!gduncan (Gary Duncan)
Subject: ?Innocent? find(1) bug turned vicious

One of our local sites just had a very nasty experience with find(1).
The daily cron entry that uses find to remove all ordinary files with
names starting with "#" or ending with ".CKP" that haven't been
accessed in three days, ran amuck and destroyed 99% of the files in two
filesystems.  We initially thought it might be a security breach, but
finally traced it to a bug in find.  The problem is that the character
array "Pathname" is declared with a length of "200".  For those of you
with the Mt. Xinu bug list it is bug usr.bin/59 as reported by
decvax!popvax!neilr (9 May 84).

The reported bug (and fix -- change "200" to "MAXPATHLEN+1") only notes
that you get a segmentation fault and a core dump (didn't we wish).
What happened in our case is that the offending (garbage) pathname just
overflowed into the predicate list data structure "Node" (which
immediately follows "Pathname") replacing the first entry with a valid
one that caused find to match all file names.  An experiment where the
length of the path was two characters shorter did cause the reported
segmentation fault.

What led us to suspect a security breach was that the removals were
confined to only two of the user filesystems, and all accounts in both
were affected.  Directories (although now almost always empty) and
(most) "." files were still around.  This made it look like someone did
"rm * */* ..." as root.  There were however a few ordinary files left,
which seemed to blow holes in this theory.  It just so happened that
the offending file was almost the first file (using directory order) on
the first of these affected filesystem, and these were themselves last
(again directory order) overall.  Also all the remaining "." and other
files were recently accessed (eg. on login, etc.) except for the very
few before the offending file.

This happened under 4.2BSD but probably exists in others.  I strongly
urge all sites to check for and fix this bug.  Any knowledgeable user
could create the necessary magic file name and plant it in an innocent
and early place.
- --
Gary Duncan, Dept of CS, U of Victoria, Victoria BC, CANADA (604) 721-7302
uucp:   {ubc-vision,uw-beaver,ssc-vax}!uvicctr!vax-populi!gduncan
~arpa:  vax-populi!gduncan@nrl-css.ARPA
ean:    gduncan@vax-populi.UVic.CDN
bitnet: gduncan@uvunix

END OF DOCUMENT