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: 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 #include #include #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