|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T c
Length: 22280 (0x5708) Types: TextFile Names: »crack-pwc.c«
└─⟦4f9d7c866⟧ Bits:30007245 EUUGD6: Sikkerheds distributionen └─⟦this⟧ »./crack/Sources/crack-pwc.c«
/* * This program is copyright Alec Muffett 1991 except for some portions of * code in "crack-fcrypt.c" which are copyright Robert Baldwin, Icarus Sparry * and Alec Muffett. The author(s) disclaims all responsibility or liability * with respect to it's usage or its effect upon hardware or computer * systems, and maintain copyright as set out in the "LICENCE" document which * accompanies distributions of Crack v4.0 and upwards. */ #include "crack.h" #define DOTFILESIZE 1024 #define WORDSTACKSIZE 512 /* * crack-pwc.c - an optimised password cracker. (c) ADE Muffett, Feb 1992. If * this won't break your password file, it's unlikely that anything else * will. */ /* trap a signal on shutdown */ void CatchTERM () { /* bury magnets */ Log ("Caught a SIGTERM! Commiting suicide...\n"); /* swallow the rapture */ Log ("<argh!>\n"); /* let's gather feathers */ sync (); /* don't fall on me */ exit (0); /* 'Fall on Me' by R.E.M. */ } /* jump ':' separated fields in an input */ char * PWSkip (p) register char *p; { while (*p && *p != ':') { p++; } if (*p) { *p++ = '\0'; } return (p); } char * Archive (myword) register char *myword; { register int i; register struct DICT *ptr; static struct DICT *arch_root; for (ptr = arch_root; ptr; ptr = ptr -> next) { if (!STRCMP (ptr -> word, myword)) { return (ptr -> word); } } i = strlen (myword); ptr = (struct DICT *) malloc (sizeof (struct DICT) + i); if (ptr) { strcpy (ptr -> word, myword); ptr -> word[i] = '\0'; ptr -> next = arch_root; arch_root = ptr; } else { Log ("Archive/malloc() failed! Fatal lack of memory!\n"); exit (1); } return (ptr -> word); } /* parse and store a password entry */ struct USER * Parse (buffer) register char *buffer; { register char *p; register struct USER *retval; retval = (struct USER *) malloc (sizeof (struct USER)); if (!retval) { Log ("Parse/malloc() failed! Fatal lack of memory!\n"); exit (1); } retval -> next = retval -> across = NULL; retval -> passwd_txt = NULL; retval -> done = 0; Trim (buffer); p = PWSkip (buffer); retval -> filename = Archive (buffer); p = Clone (p); if (!p) { Log ("Parse/Clone() failed! Fatal lack of memory!\n"); exit (1); } retval -> passwd.pw_name = p; p = PWSkip (p); retval -> passwd.pw_passwd = p; p = PWSkip (p); retval -> passwd.pw_uid = atoi (p); p = PWSkip (p); retval -> passwd.pw_gid = atoi (p); p = PWSkip (p); retval -> passwd.pw_gecos = p; p = PWSkip (p); retval -> passwd.pw_dir = p; p = PWSkip (p); retval -> passwd.pw_shell = p; return (retval); } /* load pre-formatted password entries off stdin into linked list */ int LoadData () { int i; char *ptr; char salt[2]; char buffer[STRINGSIZE]; long int numlines; long int numentries; register struct USER *new_element; register struct USER *current_line; numlines = 0L; numentries = 0L; current_line = NULL; salt[0] = salt[1] = '*'; while (fgets (buffer, STRINGSIZE, stdin)) { if (!*buffer || isspace (*buffer)) { continue; } new_element = Parse (buffer); ptr = new_element -> passwd.pw_passwd; if (!ptr[0]) { Log ("Warning! %s (%s in %s) has a NULL password!\n", new_element -> passwd.pw_name, new_element -> passwd.pw_shell, new_element -> filename); continue; } if (strchr (ptr, '*') || strchr (ptr, '!') || strchr (ptr, ' ')) { Log ("User %s (in %s) has a locked password:- %s\n", new_element -> passwd.pw_name, new_element -> filename, new_element -> passwd.pw_passwd); continue; } i = strlen (ptr); if (i < 13) { Log ("User %s (in %s) has a short pw_passwd field - skipping.\n", new_element -> passwd.pw_name, new_element -> filename); continue; } if (i > 13) { Log ("User %s (in %s) has a long pw_passwd field - truncating.\n", new_element -> passwd.pw_name, new_element -> filename); ptr[13] = '\0'; } numentries++; if (ptr[0] == salt[0] && ptr[1] == salt[1]) { new_element -> across = current_line; current_line = new_element; } else { if (current_line) { current_line -> next = userroot; } userroot = current_line; current_line = new_element; numlines++; salt[0] = ptr[0]; salt[1] = ptr[1]; } } if (current_line) /* last one tends to hang about */ { current_line -> next = userroot; userroot = current_line; numlines++; } --numlines; if (numentries) { Log ("Loaded %ld password entries with %ld different salts: %d%%\n", numentries, numlines, ((numlines * 100) / numentries)); } else { Log ("No input supplied: everything removed by feedback ?\n"); } return (numentries); } /* and load rules from a standard file into a similar list */ int LoadRules (file, rootpos) char *file; struct RULE **rootpos; { FILE *fp; int numrules; struct RULE fencepost; register struct RULE *addinto; register struct RULE *scratch; char buffer[STRINGSIZE]; if (!(fp = fopen (file, "r"))) { Log ("cannot open rulefile %s\n", file); perror (file); return (-1); } numrules = 0; addinto = &fencepost; addinto -> next = (struct RULE *) 0; while (fgets (buffer, STRINGSIZE, fp)) { Trim (buffer); if (!buffer[0] || buffer[0] == '#') { continue; } scratch = (struct RULE *) malloc (sizeof (struct RULE)); if (!scratch) { Log ("LoadRules/malloc() failed! Fatal lack of memory!\n"); exit (1); } scratch -> rule = Clone (buffer); if (!scratch -> rule) { Log ("LoadRules/Clone() failed! Fatal lack of memory!\n"); exit (1); } scratch -> next = (struct RULE *) 0; addinto -> next = scratch; addinto = scratch; numrules++; } fclose (fp); Log ("Loaded %d rules from '%s'.\n", numrules, file); *rootpos = fencepost.next; return (numrules); } /* load a dictionary into a linked list, and sort it */ long int LoadDict (file, rule, contdict) char *file; char *rule; int contdict; { int i; int memfilled; long int nelem; long int rejected; register char *mangle; register struct DICT *scratch; char pipebuff[STRINGSIZE]; static FILE *fp; char buffer[STRINGSIZE]; if (contdict && fp) { goto files_open; } #ifdef COMPRESSION if (!Suffix (file, ".Z")) { sprintf (pipebuff, "%s %s", zcat, file); if (!(fp = (FILE *) popen (pipebuff, "r"))) { perror (pipebuff); return (0); } } else if (!Suffix (file, ".z")) { sprintf (pipebuff, "%s %s", pcat, file); if (!(fp = (FILE *) popen (pipebuff, "r"))) { perror (pipebuff); return (0); } } else #endif /* COMPRESSION */ { pipebuff[0] = '\0'; if (!(fp = fopen (file, "r"))) { perror (file); return (0); } } files_open: nelem = 0; rejected = 0; memfilled = 0; dictroot = (struct DICT *) 0; Log ("%s rule '%s' to file '%s'\n", contdict ? "Continuing" : "Applying", rule, file); while (fgets (buffer, STRINGSIZE, fp)) { Trim (buffer); if (!buffer[0] || buffer[0] == '#') { continue; } mangle = Mangle (buffer, rule); if (!mangle) { rejected++; if (verbose_bool) { Log ("Rejected '%s' due to rule specs.\n", buffer); } continue; } if (dictroot && !strncmp (mangle, dictroot -> word, pwlength)) { rejected++; if (verbose_bool) { Log ("Rejected '%s'; duplicated to %d chars.\n", buffer, pwlength); } continue; } i = strlen (mangle); if (i > pwlength) { i = pwlength; } scratch = (struct DICT *) malloc (sizeof (struct DICT) + i); if (!scratch) { Log ("LoadDict/malloc() failed! Shameful lack of memory!\n"); memfilled = 1; goto words_loaded; } strncpy (scratch -> word, mangle, i); scratch -> word[i] = '\0'; scratch -> next = dictroot; dictroot = scratch; nelem++; if (verbose_bool) { Log ("Loaded '%s' as '%s' using '%s'\n", buffer, scratch -> word, rule); } } if (pipebuff[0]) { pclose (fp); } else { fclose (fp); } fp = (FILE *) 0; words_loaded: if (nelem == 0) { return (0); } Log ("Rejected %ld words on loading, %ld words left to sort\n", rejected, nelem); dictroot = (struct DICT *) SortDict (dictroot, nelem); if (memfilled) { nelem = -nelem; } return (nelem); /* not strict number anymore... */ } /* lose the current dictionary */ int DropDict () { register struct DICT *scratch1; register struct DICT *scratch2; scratch1 = dictroot; while (scratch1) { scratch2 = scratch1 -> next; free (scratch1); scratch1 = scratch2; } return (0); } /* * write a feedback file if there is anything to save - return number * uncracked users */ int FeedBack (log_notdone) int log_notdone; { register FILE *fp; static char fmt[] = "%s:%s:%s:%s\n"; register struct USER *head; register struct USER *arm; int done; int notdone; notdone = done = 0; if (verbose_bool) { Log ("Sweeping data looking for feedback.\n"); } fp = (FILE *) 0; for (head = userroot; head; head = head -> next) { for (arm = head; arm; arm = arm -> across) { if (arm -> done) { done++; /* horrible little hack, vile, sick, I love it */ if (!fp) { if (!(fp = fopen (feedbackfile, "w"))) { perror (feedbackfile); return (-1); } if (verbose_bool) { Log ("Feedback file opened for writing.\n"); } } fprintf (fp, fmt, feedback_string, arm -> passwd.pw_passwd, "Y", arm -> passwd_txt); } else { notdone++; if (log_notdone) { if (!fp) /* and again !!! heheheheheheh */ { if (!(fp = fopen (feedbackfile, "w"))) { perror (feedbackfile); return (-1); } if (verbose_bool) { Log ("Feedback file opened for writing.\n"); } } /* I think I'm going slightly warped */ fprintf (fp, fmt, feedback_string, arm -> passwd.pw_passwd, "N", ""); } } } } if (fp) { fclose (fp); Log ("Closing feedback file.\n"); } Log ("FeedBack: %d users done, %d users left to crack.\n", done, notdone); return (notdone); } /* try a chain of users with the same salt */ int TryManyUsers (eptr, guess) /* returns 0 if all done this chain */ register struct USER *eptr; char *guess; { register int retval; char guess_crypted[STRINGSIZE]; if (eptr -> done && !eptr -> across) { return (0); } strcpy (guess_crypted, crypt (guess, eptr -> passwd.pw_passwd)); retval = 0; while (eptr) { if (verbose_bool) { Log ("Trying '%s' on %s from line %s\n", guess, eptr -> passwd.pw_name, eptr -> filename); } if (!eptr -> done && !STRCMP (guess_crypted, eptr -> passwd.pw_passwd)) { PrintGuess (eptr, guess); } retval += (!(eptr -> done)); eptr = eptr -> across; } return (retval); } /* try a word on an individual */ int TryOneUser (eptr, guess) /* returns non-null on guessed user */ register struct USER *eptr; register char *guess; { if (!guess || !*guess || eptr -> done) { return (0); } if (verbose_bool) { Log ("Trying '%s' on %s from %s\n", guess, eptr -> passwd.pw_name, eptr -> filename); } if (strcmp (crypt (guess, eptr -> passwd.pw_passwd), eptr -> passwd.pw_passwd)) { return (0); } PrintGuess (eptr, guess); return (1); } /* frontend to TryOneUser() to save hassle */ int WordTry (entry_ptr, guess) register struct USER *entry_ptr; register char *guess; { struct RULE *ruleptr; register char *mangle; if (!guess[0] || !guess[1]) { return (0); } for (ruleptr = gecosroot; ruleptr; ruleptr = ruleptr -> next) { if (mangle = Mangle (guess, ruleptr -> rule)) { if (TryOneUser (entry_ptr, mangle)) { return (1); } } } return (0); } /* Special manipulations for the GECOS field and dotfiles */ int ParseBuffer (entry_ptr, buffer, advanced) register struct USER *entry_ptr; char *buffer; int advanced; { int wordcount; register int i; register int j; register char *ptr; char junk[STRINGSIZE]; char *words[WORDSTACKSIZE]; /* zap all punctuation */ for (ptr = buffer; *ptr; ptr++) { if (ispunct (*ptr) || isspace (*ptr)) { *ptr = ' '; } } /* break up all individual words */ wordcount = 0; ptr = buffer; while (*ptr) { while (*ptr && isspace (*ptr)) { ptr++; } if (*ptr) { words[wordcount++] = ptr; if (wordcount >= WORDSTACKSIZE) { Log ("ParseBuffer: Abort: Stack Full !\n"); return (0); } } while (*ptr && !isspace (*ptr)) { ptr++; } if (*ptr) { *(ptr++) = '\0'; } } words[wordcount] = (char *) 0; /* try all the words individually */ if (verbose_bool) { Log ("Trying individual words\n"); } for (i = 0; i < wordcount; i++) { if (WordTry (entry_ptr, words[i])) { return (1); } } if (!advanced) { return (0); } /* try pairings of words */ if (verbose_bool) { Log ("Trying paired words\n"); } for (j = 1; j < wordcount; j++) { for (i = 0; i < j; i++) { /* Skip initials for next pass */ if (!words[i][1] || !words[j][1]) { continue; } strcpy (junk, words[i]); strcat (junk, words[j]); if (WordTry (entry_ptr, junk)) { return (1); } strcpy (junk, words[j]); strcat (junk, words[i]); if (WordTry (entry_ptr, junk)) { return (1); } } } /* try initials + words */ if (verbose_bool) { Log ("Trying initial'ed words\n"); } for (j = 1; j < wordcount; j++) { for (i = 0; i < j; i++) { junk[0] = words[i][0]; junk[0] = CRACK_TOUPPER (junk[0]); strcpy (junk + 1, words[j]); if (WordTry (entry_ptr, junk)) { return (1); } } } return (0); } /* run over password entries looking for passwords */ void Pass1 () { struct USER *head; char junk[DOTFILESIZE]; register struct USER *this; #ifdef CRACK_DOTFILES #ifdef CRACK_DOTSANE #include <sys/types.h> #include <sys/stat.h> struct stat sb; #endif /* CRACK_DOTSANE */ int i; int j; FILE *fp; char filename[STRINGSIZE]; static char *dotfiles[] = { ".plan", ".project", ".signature", (char *) 0 }; #endif /* CRACK_DOTFILES */ Log ("Starting pass 1 - password information\n"); for (head = userroot; head; head = head -> next) { for (this = head; this; this = this -> across) { strcpy (junk, this -> passwd.pw_gecos); if (WordTry (this, this -> passwd.pw_name) || ParseBuffer (this, junk, 1)) { continue; } #ifdef CRACK_DOTFILES for (i = 0; dotfiles[i]; i++) { sprintf (filename, "%s/%s", this -> passwd.pw_dir, dotfiles[i]); #ifdef CRACK_DOTSANE if (stat (filename, &sb) < 0) { continue; } if ((!(sb.st_mode & S_IFREG)) #ifdef S_IFSOCK || ((sb.st_mode & S_IFSOCK) == S_IFSOCK) #endif /* S_IFSOCK */ ) { continue; } #endif /* CRACK_DOTSANE */ if (!(fp = fopen (filename, "r"))) { continue; } j = fread (junk, 1, DOTFILESIZE, fp); fclose (fp); if (j <= 2) { continue; } junk[j - 1] = '\0'; /* definite terminator */ if (verbose_bool) { Log ("DOTFILES: Checking %d bytes of %s\n", j, filename); } if (ParseBuffer (this, junk, 0)) { continue; } } #endif /* CRACK_DOTFILES */ } } return; } void Pass2 (dictfile) char *dictfile; { int pointuser; struct USER *headptr; struct RULE *ruleptr; struct DICT *dictptr; Log ("Starting pass 2 - dictionary words\n"); headptr = (struct USER *) 0; ruleptr = (struct RULE *) 0; /* check if we are recovering from a crash */ if (recover_bool) { recover_bool = 0; /* switch off */ for (ruleptr = ruleroot; ruleptr && strcmp (ruleptr -> rule, old_rule); ruleptr = ruleptr -> next); if (!ruleptr) { Log ("Fatal: Ran off end of list looking for rule '%s'\n", old_rule); exit (1); } for (headptr = userroot;/* skip right number of users */ headptr && old_usernum--; headptr = headptr -> next); if (!headptr) { Log ("Fatal: Ran off end of list looking for user '%s'\n", old_username); exit (1); } } /* start iterating here */ for (ruleptr = (ruleptr ? ruleptr : ruleroot); ruleptr; ruleptr = ruleptr -> next) { long int rval; int continue_dict; continue_dict = 0; load_dict: rval = LoadDict (dictfile, ruleptr -> rule, continue_dict); if (rval == 0) { Log ("Oops! I got an empty dictionary! Skipping rule '%s'!\n", ruleptr -> rule); continue; } pointuser = 0; /* iterate all the users */ for (headptr = (headptr ? headptr : userroot); headptr; headptr = headptr -> next) { SetPoint (dictfile, ruleptr -> rule, pointuser++, headptr -> passwd.pw_name); /* iterate all the words */ for (dictptr = dictroot; dictptr; dictptr = dictptr -> next) { /* skip repeated words... */ if (!TryManyUsers (headptr, dictptr -> word)) { break; } } } /* free up memory */ DropDict (); /* write feedback file */ if (!FeedBack (0)) { Log ("FeedBack: All Users Are Cracked! Bloody Hell!\n"); return; } /* on next pass, start from top of user list */ headptr = (struct USER *) 0; /* did we REALLY finish this dictionary ? */ if (rval < 0) { continue_dict = 1; goto load_dict; } } } int main (argc, argv) int argc; char *argv[]; { int i; long t; int uerr; int die_bool = 0; FILE *fp; char *crack_out; extern int optind; extern char *optarg; static char getopt_string[] = "i:fX:n:r:vml:"; uerr = 0; if (argc == 1) { uerr++; } while ((i = getopt (argc, argv, getopt_string)) != EOF) { switch (i) { case 'i': strcpy (input_file, optarg); if (!freopen (input_file, "r", stdin)) { perror (input_file); exit (1); } if (!strncmp (input_file, "/tmp/pw.", 7)) { unlink (input_file); } break; case 'm': mail_bool = 1; break; case 'f': foreground_bool = 1; break; case 'X': remote_bool = 1; strcpy (supplied_name, optarg); break; case 'l': pwlength = atoi (optarg); break; case 'n': nice_value = atoi (optarg); nice (nice_value); break; case 'r': recover_bool = 1; strcpy (recover_file, optarg); break; case 'v': verbose_bool = 1; break; default: case '?': uerr++; break; } } if (optind >= argc) { uerr++; } if (uerr) { fprintf (stderr, "Usage:\t%s -%s dictfile [dictfile...]\n", argv[0], getopt_string); exit (1); } pid = getpid (); if (gethostname (this_hostname, STRINGSIZE)) { perror ("gethostname"); } if (!(crack_out = (char *) getenv ("CRACK_OUT"))) { crack_out = "."; } sprintf (opfile, "%s/out.%s%d", crack_out, this_hostname, pid); if (remote_bool) { sprintf (diefile, "%s", supplied_name); } else { sprintf (diefile, "%s/D%s%d", runtime, this_hostname, pid); } sprintf (pointfile, "%s/P%s%d", runtime, this_hostname, pid); sprintf (feedbackfile, "%s/F%s%d", runtime, this_hostname, pid); if (!foreground_bool) { if (!freopen (opfile, "w", stdout)) { perror ("freopen(stdout)"); exit (1); } if (!freopen (opfile, "a", stderr)) { perror ("freopen(stderr)"); exit (1); } } /* * don't generate a die file unless we are not 'attached' to a * terminal... except when we are remote as well... */ time (&t); if (!foreground_bool || (foreground_bool && remote_bool)) { if (!(fp = fopen (diefile, "w"))) { perror (diefile); exit (1); } die_bool = 1; fprintf (fp, "#!/bin/sh\n"); fprintf (fp, "# ID=%s.%d start=%s", this_hostname, pid, ctime (&t)); fprintf (fp, "kill -TERM %d && rm $0", pid); fclose (fp); chmod (diefile, 0700); } Log ("Crack v%s: The Password Cracker, (c) Alec D.E. Muffett, 1992\n", version); #ifdef FCRYPT init_des (); #endif /* Quick, verify that we are sane ! */ if (strcmp (crypt ("fredfred", "fredfred"), "frxWbx4IRuBBA")) { Log ("Version of crypt() being used internally is not compatible with standard.\n"); Log ("This could be due to byte ordering problems - see the comments in Sources/conf.h\n"); Log ("If there is another reason for this, edit the source to remove this assertion.\n"); Log ("Terminating...\n"); exit (0); } #ifndef AMIGA signal (SIGTERM, CatchTERM); #endif Log ("Loading Data, host=%s pid=%d\n", this_hostname, pid); if (LoadData () <= 0) { Log ("Nothing to Crack. Exiting...\n"); exit (0); } if (LoadRules (rulefile, &ruleroot) < 0 || LoadRules (gecosfile, &gecosroot) < 0) { exit (1); } if (!recover_bool) { /* We are starting afresh ! Ah, the birds in May ! */ Pass1 (); if (!FeedBack (0)) { Log ("FeedBack: information: all users are cracked after gecos pass\n"); goto finish_crack; } } else { int rval; if (rval = GetPoint (recover_file)) { Log ("Recovery from file %s not permitted on this host [code %d]\n", recover_file, rval); exit (0); } /* Some spodulous creep pulled our plug... */ while ((optind < argc) && strcmp (argv[optind], old_dictname)) { optind++; } } for (i = optind; i < argc; i++) { Pass2 (argv[i]); } Log ("Tidying up files...\n"); FeedBack (1); finish_crack: if (die_bool) { unlink (diefile); } unlink (pointfile); Log ("Done.\n"); return (0); }