home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume25
/
crack
/
part04
< prev
next >
Wrap
Text File
|
1991-11-03
|
57KB
|
2,090 lines
Newsgroups: comp.sources.misc,alt.security
From: aem@aberystwyth.ac.uk (Alec Muffett)
Subject: v25i008: crack - The Password Cracker, version 4.0a, Part04/05
Message-ID: <1991Nov3.231604.10335@sparky.imd.sterling.com>
X-Md4-Signature: 6fa07ca5e64c0102b7cdae08238af70d
Date: Sun, 3 Nov 1991 23:16:04 GMT
Approved: kent@sparky.imd.sterling.com
Submitted-by: aem@aber.ac.uk (Alec David Muffett)
Posting-number: Volume 25, Issue 8
Archive-name: crack/part04
Environment: UNIX
Supersedes: crack: Volume 23, Issue 1-5
#! /bin/sh
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 4 (of 5)."
# Contents: Docs/README.ms Sources/crack-pwc.c
# Wrapped by aem@aberda on Thu Oct 24 11:14:44 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Docs/README.ms' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Docs/README.ms'\"
else
echo shar: Extracting \"'Docs/README.ms'\" \(28316 characters\)
sed "s/^X//" >'Docs/README.ms' <<'END_OF_FILE'
X.de C
X.ie n .B "\\$1" \\$2
X.el .CW "\\$1" \\$2
X..
X.TL
X"Crack Version 4.0a"
X.br
XA Sensible Password Checker for Unix
X.AU
XAlec D.E. Muffett
X.AI
XComputer Unit, University College of Wales
XAberystwyth, Wales, SY23 3DB
X.I aem@aber.ac.uk
X+44 970 622492
X.AB
X.B Crack
Xis a freely available program designed to find standard Unix
Xeight-character DES encrypted passwords by standard guessing techniques
Xoutlined below. It is written to be flexible, configurable and fast,
Xand to be able to make use of several networked hosts via the Berkeley
X.C rsh
Xprogram (or similar), where possible.
X.AE
X.NH 1
XIntroduction to Version 4.0
X.LP
XCrack is now into it's fourth version, and has been reworked extensively
Xto provide extra functionality, and the purpose of this release is to
Xconsolidate as much of this new functionality into as small a package as
Xpossible. To this end, Crack may appear to be less configurable: it has
Xbeen written on the assumption that you run a fairly modern Unix, one
Xwith BSD functionality, and then patched in order to run on other
Xsystems.
X.LP
XThis, surprisingly enough, has led to neater code, and has made possible
Xthe introduction of greater flexibility which supercedes many of the
Xoptions that could be configured in earlier versions of Crack. In the
Xsame vein, some of the older options are now mandatory. These, such as
X.I "feedback mode"
Xand
X.C CRACK_PRINTOUT
Xare no longer supported as options and probably never will be again.
XThere is just a lot of wastage in not running with them, and too many
Xdependencies in other functions to bother programming around them.
X.LP
XThe user interface is basically identical to the previous versions,
Xalthough some people have asked about providing X-windows GUI's to
XCrack, I think it would be a waste of time to do so. Crack has far
Xless options than your ordinary version of
X.C /bin/ls .
X.LP
XWith all that over, let's kick some (ass|arse|but(t)?)\**
X.FS
XAn obscure
X.I lex
Xjoke, inserted only for the purpose of allowing an example footnote for
Xmy reference - sorry - AEM
X.C 8-)
X.FE
X.NH 1
XCrack Methodology - Part 1: Internals
X.LP
XCrack takes a series of password files and throws logic and dictionaries
Xat the passwords therein, in order to find passwords which are based
Xupon personal information or dictionary words, and are therefore
Xinsecure. It does
X.B not
Xattempt to remedy this situation, and it shoult
X.B NOT
Xbe used in place of getting a really good secure
X.C passwd
Xprogram replacement.
X.LP
XThe above statement defines the purpose of Crack, and embodies a great
Xamount to hard work, graft, screams of
X.I Eureka! ,
Xand a fair amount of swearing too. There is a great deal of thinking
Xbehind the way that Crack attacks password files, and although not
Xperfect, I certainly hope that Crack will out-do most of it's
Xcompetitors.
X.LP
XCrack works by making several passes over the password entries that you
Xsupply to it. Each pass works by generating password guesses based upon
Xa sequence of assertions, or rules, supplied to the program by the user.
XThe rules are specified in a simplistic language, in the files
X.C gecos.rules
Xand
X.C dicts.rules
Xin the
X.C Scripts
Xdirectory.
XThe distinction between these two files will be made clear later.
X.LP
XThe rules are written as a simple string of characters, with one rule to
Xa line. Blank lines, and comment lines beginning with a hash character
X.B #
Xare ignored. Trailing whitespace is also ignored. The instructions in
Xthe word are followed left to right, and are applied to the dictionary
Xwords in sequence. A couple of simple pattern matching primitives are
Xsupplied for selection purposes. The syntax is as follows:
X.IP :
XNo-op; do nothing to the word. This is useful as a space delimiter.
X.IP <n
XReject the word unless it is
X.B "LESS THAN"
X.I n
Xcharacters long, where
X.I n
Xis a digit 0-9, or a letter a-z for the values 10-35, respectively.
X.IP >n
XReject the word unless it is
X.B "MORE THAN"
X.I n
Xcharacters long, where
X.I n
Xis a digit 0-9, or a letter a-z for the values 10-35, respectively.
X.IP /x
XReject the word unless it contains the character 'x'.
X.IP !y
XReject the word unless it does not contain the character 'y'.
X.IP ^x
XPrepend character 'x' to the word.
X.IP $y
XAppend character 'y' to the word.
X.IP l
XForce the word to lowercase.
X.IP u
XForce the word to uppercase.
X.IP c
XCapitalise the word, lowercasing all other letters.
X.IP r
XReverse the word back-to-front.
X.IP d
XDuplicate the word, so that
X.I fred
Xbecomes
X.I fredfred
X.IP f
XReflect the word (mirror image), so that
X.I fred
Xbecomes
X.I fredderf
X.IP p
XMake best attempt to pluralise the word, assuming that it is lowercase.
X.IP sxy
XSubstitute 'x' for 'y' throughout the word.
X.IP xnm
XExtract the string starting at position 'n' (starts at 0) for a length
Xof up to 'm' characters, where 'n' and 'm' are digits in the range 0-9,
Xor letters a-z for the values 10-35, respectively.
X.sp 1v
X.LP
XSo, example rules could be:
X.IP c
XCapitalise the word.
X.I fred
Xbecomes
X.I Fred
X.IP l$?
XLowercase the word and append a questionmark.
X.I fred
Xbecomes
X.I fred?
X.IP l/oso0c
XLowercase the word, select it only if it contains the letter 'o' and
Xsubstitute all o's for zeros, and capitalise it.
XBoth
X.I COLLEGE
Xand
X.I college
Xbecome
X.I C0llege
X.IP <8l/i/olsi1so0$=
XReject the word unless it is less that 8 characters long, lowercase the
Xword, reject it if it does not contain both the letter 'i' and the
Xletter 'o', substitute all i's for 1's, substitute all o's for 0's, and
Xappend an = sign.
X.IP
XThe reasoning for the 8 character test is that since, with standard
X.I crypt()
Xtype algorithms, the password is truncated at 8 characters, there is no
Xpoint in bolting a letter onto the end of a word if it is 8 or more
Xcharacters long already.
X.IP <7l^($)
XReject the word unless it is less than 7 characters long, lowercase it,
Xprepend a '(' and append a ')'. Thus
X.I fred
Xbecomes
X.I (fred)
X.IP "$ :"
X(ie: <dollar><space><colon>) Append a space character to the word (note
Xthat if you do not add the trailing no-op after the space, a syntax
Xerror will be generated since there is nothing to delineate the space
Xcharacter - remember: trailing whitespace is ignored).
X.sp 1v
X.LP
XBefore you go on, I suggest you browse through the
X.C Scripts/*.rules
Xfiles, and take a look at the rules that I supply as defaults, and try
Xto work out what they do.
X.LP
XThe rules are stored in two different files for two different purposes.
XRules in
X.C Scripts/gecos.rules
Xare applied to data generated by Crack from the pw_gecos and pw_gecos
Xentries of the user's password entry.
X.LP
XThe data generated by Crack and fed to the gecos rules
Xfor the user
X.I "aem",
Xwho is
X.I "Alec David Muffett, Compunit"
Xwould be:
X.I "aem",
X.I "Alec",
X.I "David",
X.I "Muffett",
X.I "Compunit",
Xand a series of permutations of those words, either re-ordering the
Xwords and joining them together (eg:
X.I "AlecMuffett" ),
Xor making up new words based on initial letters of one word taken with
Xthe rest of another (eg:
X.I "AMuffett" ).
X.LP
XThe entire set of rules in gecos.rules is applied to each of these
Xwords, which creates many more permutations and combinations, all of
Xwhich are tested. Hence testing the password gecos information under
XCrack v4.0 takes somewhat longer than it used to, but it is far more
Xthorough.
X.sp 1v
X.LP
XAfter a pass has been made over the data based on gecos information,
XCrack makes further passes over the password data using successive rules
Xfrom the
X.C Scripts/dicts.rules
Xby loading the entire
X.C Dicts/bigdict
Xfile into memory, with the rule being applied to each word from that
Xfile. This generates a
X.I "resident dictionary" ,
Xwhich is generated is sorted and uniqued so as to prevent wasting time
Xon repetition. After each pass is completed, the memory used by the
Xresident dictionary is freed up, and (hopefully) re-used when the next
Xdictionary is loaded.
X.LP
XThe
X.C Dicts/bigdict
Xdictionary is created by Crack by merging, sorting, and uniq'ing the
Xsource dictionaries, which are to be found in the directory
X.C DictSrc
Xor, alternatively, may be named in the Crack shellscript, via the
X.C $STDDICT
Xvariable. The default dictionary named in the Crack script is
X.C /usr/dict/words .
X.LP
XThe file
X.C DictSrc/bad_pws.dat
Xwhich is meant to provide many of those common, non-dictionary
Xpasswords, such as
X.I 12345678
Xor
X.I qwerty .
XIf you wish to add a dictionary of your own, just copy it into the
X.C DictSrc
Xdirectory (and use
X.C compress
Xon it if you wish to save space; Crack will unpack it whilst generating
Xthe big dictionary) and then delete the contents of the
X.C Dicts
Xdirectory by running
X.C Scripts/spotless .
XYour new dictionary will be merged in on the next run.
XFor more information on dictionary attacks, see the paper called
X"Foiling the Cracker: A Survey of, and Improvements to, Password
XSecurity" by Daniel Klein, available from
X.I "ftp.sei.cmu.edu"
Xin
X.I "~/pub/dvk/passwd.*" .
XAlso, please read the
X.C APPENDIX
Xfile supplied with this distribution.\**
X.FS
XExtra dictionaries (those detailed in Dan Klein's paper) can be
Xobtained via anonymous FTP from
X.I uunet.uu.net
X(192.48.96.2) as
X.I ~/pub/dictionaries.tar.Z ;
XCheck an
X.I Archie
Xdatabase for other possible sources of dictionaries.
X.FE
X.LP
XHaving described the method of cracking, perhaps we should now
Xinvestigate the algorithm used to overlay the cracking mechanism.
X.NH 1
XCrack Methodology - Part 2: Feedback Filters
X.LP
XAs is stated above, Crack v4.0 permutes and loads dictionaries directly
Xinto memory, sorts and uniques them, before attempting to use each of
Xthe words as a guess for each users' password. If Crack correctly
Xguesses a password, it marks the user as 'done' and does not waste
Xfurther time on trying to break that users password.
X.LP
XOnce Crack has finished a dictionary pass, it sweeps the list of users
Xlooking for the passwords it has cracked. It stores the broken passwords
Xin both plaintext and encrypted forms in a
X.I "feedback file"
Xin the directory
X.C Runtime .
XFeedback files have names of the form
X.C Runtime/F.* .
X.LP
XThe purpose of this is so that, when Crack is next invoked, it may
Xrecognise passwords that it has successfully cracked before, and filter
Xthem from the input to the password cracker. This provides an
X.I instant
Xlist of crackable users who have not changed their passwords since the
Xlast time Crack was run. This list appears in a file named
X.C out.i*
Xin the
X.C $CRACK_OUT
Xdirectory, or on
X.I stdout ,
Xif foreground mode is invoked (see
X.I Options ,
Xbelow).
X.LP
XIn a similar vein, when a Crack run terminates normally, it writes out
Xto the feedback file all encrypted passwords that it has
X.B NOT
Xsucceeded in cracking. Crack will then ignore all of these passwords
Xnext time you run it.
X.LP
XObviously, this is not desirable if you frequently change your
Xdictionaries or rules, and so there is a script provided,
X.C Scripts/mrgfbk
Xwhich sorts your feedback files, merges them into one, and optionally
Xremoves all traces of 'uncrackable' passwords, so that your next Crack
Xrun can have a go at passwords it has not succeeded in breaking before.
X.LP
X.C Mrgfbk
Xis invoked automatically if you run
X.C Scripts/spotless .
X.NH 1
XCrack Methodology - Part 3: Execution and Networking
X.LP
XEach time Crack is invoked, whether networked or not, it generates a
X.I diefile
Xwith a name of the form
X.C Runtime/D.*
X(for network cracks, this file is generated by RCrack, and is of the form
X.C Runtime/D.rem*
Xwhich points to a
X.B real
Xdiefile, named
X.C Runtime/RD.*
X- see below for details).
X.LP
XThese diefiles contain debugging information about the job, and are
Xgenerated so that all the jobs on the entire network can be called
Xquickly by invoking
X.C Scripts/plaster .
XDiefiles delete themselves after they have been run.
X.LP
XAs you will read in the sections below, Crack has a
X.C "-network"
Xoption: This is designed to be a simple method of automatically
Xspreading the load of password cracking out over several machines on a
Xnetwork, preferably if they are connected by some form of networked
Xfilestore.
X.LP
XWhen
X.C "Crack -network"
Xis invoked, it filters its input in the ordinary way, and then splits
Xits load up amongst several machines which are specified in the file
X.C Scripts/network.conf .
X.LP
XThis file contains a series of hostnames, power ratings, flags, etc,
Xrelevant to the running of Crack on each machine. Crack then calls
X.C Scripts/RCrack
Xto use the
X.C rsh
Xcommand (or similar) to invoke Crack on the other hosts. See the RCrack
Xscript, and the example network.conf file for details.
X.NH 1
XInstallation
X.LP
XCrack is one of those most unusual of beasties, a self-installing
Xprogram. Some people have complained about this apparent weirdness, but
Xit has grown up with Crack ever since the earliest network version, when
XI could not be bothered to log into several different machines with
Xseveral different architectures, just in order to build the binaries.
XOnce the necessary configuration options have been set, the executables
Xare created via
X.C make
Xby running the Crack shellscript .
X.LP
XCrack's configuration lies in two files, the
X.C Crack
Xshell script, which contains all the installation specific configuration
Xdata, and the file
X.C Sources/conf.h ,
Xwhich contains configuration options specific to various binary platforms.
X.LP
XIn the Crack shellscript, you will have to edit the
X.C CRACK_HOME
Xvariable to the correct value. This variable should be set to an
Xabsolute path name (names relative to
X.I ~username
Xare OK, so long as you have some sort of
X.C csh )
Xthrough which the directory containing Crack may be accessed on
X.B ALL
Xthe machines that Crack will be run on. There is a similar variable
X.C CRACK_OUT
Xwhich specifies where Crack should put its output files - by default,
Xthis is the same as
X.C "$CRACK_HOME" .
X.LP
XYou will also have to edit the file
X.C Sources/conf.h
Xand work out which switches to enable. Each
X.C #define
Xhas a small note explaining its purpose. Where I have been in doubt about
Xthe portability of certain library functions, usually I have re-written
Xit, so you should be OK. Let me know of your problems, if you have any.
X.LP
XIf you will be using
X.C "Crack -network"
Xyou will then have to generate a
X.C Scripts/network.conf
Xfile. This contains a list of hostnames to
X.C rsh
Xto, what their
X.I "binary type"
Xis (useful when running a network Crack on several different
Xarchitectures), a guesstimate of their
X.I "relative power"
X(take your slowest machine as unary, and measure all others relative to
Xit), and a list of per-host
X.I flags
Xto
X.B add
Xto those specified on the
X.C Crack
Xcommand line, when calling that host. There is an example of such a
Xfile provided in the Scripts directory - take a look at it.
X.LP
XIf ever you wish to specify a more precise figure as to the relative
Xpower of your machines, or you are simply at a loss, play with the
Xcommand
X.C "make tests"
Xin the source code directory. This can provide you with the number of
Xfcrypt()s that your machine can do per second, which is a number that
Xyou can plug into your
X.C network.conf
Xas a measure of your machines' power (after rounding the value to an
Xinteger).
X.NH 1
XUsage
X.LP
XOkay, so, let's assume that you have edited your
X.C Crack
Xscript, and your
X.C Sources/conf.h
Xfile, where do you go from here ?
X.LP
X.DS B
X.fi
X.C Crack
X[\c
X.I options ]
X[\c
X.I bindir ]
X.C /etc/passwd
X[...other passwd files]
X.sp 1v
X.C "Crack -network"
X[\c
X.I options ]
X.C /etc/passwd
X[...other passwd files]
X.DE
X.LP
XWhere
X.B bindir
Xis the optional name of the directory where you want the binaries
Xinstalled. This is useful where you want to be able to run versions of
XCrack on several different architectures. If
X.B bindir
Xdoes not exist, a warning will be issued, and the directory created.
X.QP
XNote:
X.B bindir
Xdefaults to the name
X.C generic
Xif not supplied.
X.QP
X.LP
X.B "Notes for Yellow Pages (NIS) Users:"
XI have occasional queries about how to get Crack running from a YP
Xpassword file. There are several methods, but by far the simplest is to
Xgenerate a passwd format file by running:-
X.DS B
X.C "ypcat passwd > passwd.yp"
X.DE
Xand then running Crack on this file.
X.NH 1
XOptions
X.IP "\fB-f\fP"
XRuns Crack in
X.I foreground
Xmode, ie: the password cracker is not backgrounded, and messages appear
Xon stdout and stderr as you would expect. This option is only really
Xuseful for very small password files, or when you want to put a wrapper
Xscript around Crack.
X.IP
XForeground mode is disabled if you try running
X.C "Crack -network -f"
Xon the command line, because of the insensibility of
X.C rsh ing
Xto several machines in turn, waiting for each one to finish before
Xcalling the next. However, please read the section about
X.I "Network Cracking without NFS/RFS" ,
Xbelow.
X.IP "\fB-v\fP"
XSets verbose mode, whereby Crack will print every guess it is trying on
Xa per-user basis. This is a very quick way of flooding your filestore,
Xbut useful if you think something is going wrong.
X.IP "\fB-m\fP"
XSends mail to any user whose password you crack by invoking
X.C Scripts/nastygram
Xwith their username as an argument. The reason for using the script is
Xso that a degree of flexibility in the format of the mail message is
Xsupplied; ie: you don't have to recompile code in order to change the
Xmessage.\**
X.FS
XI'm uncertain about the wisdom of mailing someone like this. If someone
Xbrowses your cracked user's mail somehow, it's like a great big neon
Xsign pointing at the user saying "This Is A Crackable Account - Go For
XIt!". Not to mention the false sense of security it engenders in the
XSystem Manager that he's "informed" the user to change his password.
XWhat if the user doesn't log on for 3 months? However, so many people
Xhave wired it into their own versions of Crack, I suppose it
X.B must
Xbe provided... AEM
X.FE
X.IP "\fB-nvalue\fP"
XSets the process to be
X.C nice() ed
Xto
X.I value ,
Xso, for example, the switch
X.C \&-n19
Xsets the Crack process to run at the lowest priority.
X.IP "\fB-network\fP"
XThrows Crack into network mode, in which it reads the
X.C Scripts/network.conf
Xfile, splits its input into chunks which are sized according to the
Xpower of the target machine, and calls
X.C rsh
Xto run Crack on that machine. Options for Crack running on the target
Xmachine may be supplied on the command line (eg: verbose or recover
Xmode), or in the network.conf file if they pertain to specific hosts
X(eg:
X.C nice()
Xvalues).
X.IP "\fB-r<pointfile>\fP"
XThis is only for use when running in
X.I recover
Xmode. When a running Crack starts pass 2, it periodically saves its
Xstate in a
X.I pointfile ,
Xwith a name of the form
X.C "Runtime/P.*"
XThis file can be used to recover where you were should a host crash.
XSimply invoke Crack in
X.B exactly
Xthe same manner as the last time, with the addition of the
X.C "-r"
Xswitch, (eg:
X.C "-rRuntime/P.12345" )
Xswitch. Crack will startup and read the file, and jump to roughly where
Xit left off. If you are cracking a very large password file, this can
Xsave oodles of time after a crash.
X.IP
XIf you were running a
X.I network
XCrack, then the jobs will again be spawned onto all the machines of the
Xoriginal Crack. The program will then check that the host it is running
Xon is the same as is mentioned in the pointfile. If it is not, it will
Xquietly die. Thus, assuming that you supply the same input data and do
Xnot change your
X.C network.conf
Xfile, Crack should pick up where it left off. This is a bit inelegant,
Xbut it's better than nothing at the moment.
X.IP
XThe method of error recovery outlined above causes headaches for users
Xwho want to do multiprocessing on parallel architectures. Crack is in
Xno way parallel, and because of the way it's structured (reading stdin
Xfrom shellscript frontends) it is a pain to divide the work amongst
Xseveral processes via
X.C fork() ing.
X.IP
XThe hack solution to get several copies of Crack running on one machine
Xwith
X.I n
Xprocessors at the moment is to insert
X.I n
Xcopies of the entry for your parallel machine into the
X.C Scripts/network.conf
Xfile. If you use the
X.C \&-r
Xoption in these circumstances however, you will get
X.I n
Xcopies of the recovered process running, only one of them will have the
Xcorrect input data.
X.IP
XThe old solution to this problem (see old documentation if you are
Xinterested) has been negated by the introduction of feedback mode, so
Xthe best bet in this particular situation is to wait until the other
Xjobs are done (and have written out lists of uncrackable passwords), and
Xthen re-start the jobs from scratch. Anyone whose password was not
Xcracked on the first run will be ignored on the second, if they have not
Xchanged it since. This is inelegant, but it's the best I can do in the
Xlimited time available.
X.NH
XSupport Scripts
X.LP
XThe
X.C Scripts
Xdirectory contains a small number of support and utility scripts, some
Xof which are designed to help Crack users check their progress.
XBriefly, the most useful ones are:-
X.IP "\fBScripts/shadmrg\fP"
XThis is a small (but hopefully readable) script for merging
X.C /etc/passwd
Xand
X.C /etc/shadow
Xon System V style shadow password systems. It produces the merged data
Xto stdout, and will need redirecting into a file before Crack can work
Xon it. The script is meant to be fairly lucid, on the grounds that I
Xworry that there are many shadowing schemes out there, and perhaps not
Xall have the same data format.
X.IP
X.B "I have not"
Xwired this facility into the Crack command itself because the world does
X.B NOT
Xrevolve around System V yet, regardless of what some people would have
Xme believe, and I believe that the lack of direct support for NIS
Xoutlined above, sets a precedent. There are just too many
Xincompatibilities in shadow password schemes for me to hardwire
Xanything.
X.IP "\fBScripts/plaster\fP"
Xwhich is named after a dumb joke, but is a simple frontend to the
X.C "Runtime/D.*"
Xdiefiles that each copy of the password cracker generates. Invoking
X.C Scripts/plaster
Xwill kill off all copies of the password cracker you are running, over
Xthe network or otherwise.
X.IP "\fBScripts/status\fP"
XThis script
X.C rsh es
Xto each machine mentioned in the
X.C Scripts/network.conf
Xfile, and provides some information about processes and uptime on that
Xmachine. This is useful when you want to find out just how well your
Xpassword crackers are getting on during a
X.C "Crack -network" .
X.IP "\fBScripts/{clean,spotless}\fP"
XThese are really just frontends to a makefile. Invoking
X.C Scripts/clean
Xtidies up the Crack home directory, and removes probably unwanted files,
Xbut leaves the pre-processed dictionary
X.C bigdict
Xintact.
X.C Scripts/spotless
Xdoes the same as
X.C Scripts/clean
Xbut obliterates
X.C bigdict
Xand old output files too, and compresses the feedback files into one.
X.IP "\fBScripts/nastygram\fP"
XThis is the shellscript that is invoked by the password cracker to send
Xmail to users who have guessable passwords, if the
X.C -m
Xoption is used. Edit it at your leisure to suit your system.
X.IP "\fBScripts/guess2fbk\fP"
XThis script takes your
X.C out.*
Xfiles as arguments and reformats the 'Guessed' lines into a slightly
Xmessy
X.I feedback
Xfile, suitable for storing with the others.
X.IP
XAn occasion where this might be useful is when your cracker has guessed
Xmany peoples passwords, and then died for some reason (a crash?) before
Xwriting out the guesses to a feedback file. Running
X.DS B
X.C "Scripts/guess2fbk out.* >> Runtime/F.new"
X.DE
Xwill save the work that has been done.
X.NH 1
XNetwork Cracking without NFS/RFS
X.LP
XFor those users who have some form of
X.C rsh
Xcommand, but do not have a a networked filestore running between hosts,
Xthere is now a solution which will allow you to do networked cracking,
Xproposed to me by Brian Tompsett at Hull. Personally, I consider the
Xidea to be potty, but it fills in missing functionality in a wonderfully
Xtacky manner.
X.LP
XFrom the documentation above, you will note that Crack will undo the
X.C "-f"
X.I "(output in foreground)"
Xoption, if it is invoked with the
X.C "-network"
Xswitch at the same time (see the
X.I Options
Xsection above). This is true, but it does not apply if you specify
X.C "-f"
Xoption in the
X.C network.conf
Xfile.
X.LP
XThe practical upshot of doing this is that remote copies of Crack
Xcan be made to read from
X.I stdin
Xand write to
X.I stdout
Xover a network link, and thus remote processing is accomplished. I have
Xtweaked Crack in such a way, therefore, that if the
X.C "-f"
Xoption is specified amongst the crack-flags of a host in the
Xnetwork.conf, rather than backgrounding itself on the remote host, the
X.C rsh
Xcommand on the
X.B server
Xis backgrounded, and output is written directly to the files on the
Xserver's filestore.
X.LP
XThere are restrictions upon this method, mostly involving the number of
Xprocesses that a user may run on the server at any one time, and that
Xyou will have to collect feedback output together manually (dropping it
Xinto the
X.C Runtime
Xdirectory on the server). However, it works. Also, if you try to use
X.C rsh
Xas another user, you will suffer problems if
X.C rsh
Xinsists on reading something from your terminal (eg: a password for the
Xremote account). Also, recovering using checkpointing goes out the
Xwindow unless you specify the name of the pointfile as it is named
Xon the remote machine.
X.NH 1
XNotes on fast crypt() implementations
X.LP
XThe stdlib version of the
X.C crypt()
Xsubroutine is incredibly slow. It is a
X.I massive
Xbottleneck to the execution of Crack and on typical platforms that you
Xget at universities, it is rare to find a machine which will achieve
Xmore than 50 standard crypt() s per second. On low-end diskless
Xworkstations, you may expect 2 or 3 per second. It was this slowness of
Xthe crypt() algorithm which originally supplied much of the security
XUnix needed.\**
X.FS
XSee: "Password Security, A Case History" by Bob Morris & Ken Thomson, in
Xthe Unix Programmer Docs.
X.FE
X.LP
XThere are now
X.B many
Ximplementations of faster versions of crypt()
Xto be found on the network. The one supplied with Crack v3.2 and
Xupwards is called
X.C fcrypt() .
XIt was originally written in May 1986 by Robert Baldwin at MIT, and is a
Xgood version of the crypt() subroutine. I received a copy from Icarus
XSparry at Bath University, who had made a couple of portability
Xenhancements to the code.
X.LP
XI rewrote most of the tables and the KeySchedule generating algorithm in
Xthe original
X.I fdes-init.c
Xto knock 40% off the execution overhead of fcrypt() in the form that it
Xwas shipped to me. I inlined a bunch of stuff, put it into a single
Xfile, got some advice from Matt Bishop and Bob Baldwin [both of whom I
Xam greatly indebted to] about what to do to the
X.C xform()
Xroutine and to the fcrypt function itself, and tidied up some
Xalgorithms. I have also added more lookup tables and reduced several
Xformula for faster use. Fcrypt() is now barely recognisable as being
Xbased on its former incarnation, and it is 3x faster.
X.LP
XOn a DecStation 5000/200, fcrypt() is about 16 times faster than the
Xstandard crypt (your mileage may vary with other architectures and
Xcompilers). This speed puts fcrypt() into the "moderately fast" league
Xof crypt implementations. There
X.B are
Xfaster versions of crypt to be had (eg:
X.C UFC )
Xwhich may be found on the network. The advantage of fcrypt() is that I
Xsupport it, understand it, and can distribute and fix it without hassle.
XIf you want to play around with other crypts, that is up to you. Feel
Xfree.
X.C 8-)
X.NH 1
XConclusions
X.LP
XWhat can be done about brute force attacks on your password file ?
X.LP
XYou must get a drop-in replacement for the
X.C passwd
Xand
X.C yppasswd
Xcommands; one which will stop people from choosing bad passwords in the
Xfirst place. There are several programs to do this; Matt Bishop's
X.C "passwd+"
Xand Clyde Hoover's
X.C "npasswd"
Xprogram are good examples which are freely available. Consult an
X.B Archie
Xdatabase for more details on where you can get them from.
X.LP
XIt would be nice if an organisation (such as
X.B CERT ?)
Xcould be persuaded to supply skeletons of
X.I sensible
Xpasswd commands for the public good, as well as an archive of security
Xrelated utilities\**
Xon top of the excellent
X.C COPS .
X.FS
X.C COPS
Xis available for anonymous FTP from
X.I "cert.sei.cmu.edu"
X(128.237.253.5) in
X.I ~/cops
X.FE
XHowever, for Unix security to improve on a global scale, we will also
Xrequire pressure on the vendors, so that programs are written correctly
Xfrom the beginning.
END_OF_FILE
if test 28316 -ne `wc -c <'Docs/README.ms'`; then
echo shar: \"'Docs/README.ms'\" unpacked with wrong size!
fi
# end of 'Docs/README.ms'
fi
if test -f 'Sources/crack-pwc.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Sources/crack-pwc.c'\"
else
echo shar: Extracting \"'Sources/crack-pwc.c'\" \(23895 characters\)
sed "s/^X//" >'Sources/crack-pwc.c' <<'END_OF_FILE'
X/*
X * This program is copyright Alec Muffett 1991 except for some portions of
X * code in "crack-fcrypt.c" which are copyright Robert Baldwin, Icarus
X * Sparry and Alec Muffett. The author(s) disclaims all responsibility or
X * liability with respect to it's usage or its effect upon hardware or
X * computer systems, and maintain copyright as set out in the "LICENCE"
X * document which accompanies distributions of Crack v4.0 and upwards.
X */
X
X#include "crack.h"
X
X#define DOTFILESIZE 1024
X#define WORDSTACKSIZE 1024
X
X/*
X * crack-pwc.c - an optimised password cracker. (c) ADE Muffett, Oct 1991. If
X * this won't break your password file, it's unlikely that anything else
X * will.
X */
X
Xchar version[] = "4.0a"; /* version of prog */
Xchar runtime[] = "Runtime";
Xchar feedback_string[] = "!fb!";
Xchar rulefile[] = "Scripts/dicts.rules";
Xchar gecosfile[] = "Scripts/gecos.rules";
Xchar nastygram[] = "Scripts/nastygram";
X
X/* runtime variable declarations */
X
Xint pid; /* current process ID */
Xint pwlength = 8; /* significant length of a password */
Xstruct USER *userroot; /* root of linked list of users */
Xstruct RULE *ruleroot; /* root of linked list of rules */
Xstruct RULE *gecosroot; /* root of linked list of (gecos) rules */
Xstruct DICT *dictroot; /* root of linked list of words */
Xchar **dictbase; /* root of array of words */
X
X/* datafile variables */
X
Xchar diefile[STRINGSIZE]; /* where die output goes... */
Xchar feedbackfile[STRINGSIZE]; /* where feedback ouytput goes */
Xchar opfile[STRINGSIZE]; /* where Log() output goes */
Xchar pointfile[STRINGSIZE]; /* checkpointing */
Xchar this_hostname[STRINGSIZE]; /* gethostname() hack */
X
X/* recover variables */
X
Xchar old_hostname[STRINGSIZE]; /* next 4 vars used in recovery */
Xchar old_dictname[STRINGSIZE];
Xchar old_rule[STRINGSIZE];
Xint old_usernum;
Xchar old_username[STRINGSIZE];
X
X/* switches */
Xchar input_file[STRINGSIZE];
Xint foreground_bool;
Xint remote_bool;
Xint nice_value;
Xint recover_bool;
Xchar recover_file[STRINGSIZE];
Xint verbose_bool;
Xchar supplied_name[STRINGSIZE];
Xint mail_bool;
X
X/* compare two struct DICTs lexically - hook for qsort() function */
X
Xint
XDictCmp (a, b)
X char **a;
X char **b;
X{
X return (strcmp (*a, *b));
X}
X/* log anything to datafile. */
X
Xvoid
XLog (fmt, a, b, c, d, e, f, g, h, i, j)
X char *fmt;
X long int a, b, c, d, e, f, g, h, i, j;
X{
X long t;
X
X time (&t);
X printf ("pwc: %-15.15s ", ctime (&t) + 4);
X printf (fmt, a, b, c, d, e, f, g, h, i, j);
X fflush (stdout);
X}
X/* print a guess, giving a single place to mod where necessary */
X
Xvoid
XPrintGuess (eptr, guess)
X register struct USER *eptr;
X char *guess;
X{
X eptr -> done = 1;
X eptr -> passwd_txt = Clone (guess, 0); /* ESSENTIAL to FeedBack() */
X
X Log ("Guessed %s%s (%s in %s) [%s] %s\n",
X (eptr -> passwd.pw_uid ? "" : "ROOT PASSWORD "),
X eptr -> passwd.pw_name,
X eptr -> passwd.pw_shell,
X eptr -> filename,
X guess,
X eptr -> passwd.pw_passwd);
X if (mail_bool)
X {
X char dobuff[STRINGSIZE];
X
X sprintf ("%s %s", nastygram, eptr -> passwd.pw_name);
X system (dobuff);
X }
X}
X/* trap a signal on shutdown */
X
Xvoid
XCatchTERM ()
X{
X /* bury magnets */
X /* swallow the rapture */
X /* let's gather feathers */
X /* don't fall on me - from 'Fall in Me' by R.E.M. */
X Log ("Caught a SIGTERM! Commiting suicide...\n");
X Log ("<argh!>\n");
X sync ();
X exit (0);
X}
X/* write a pointfile out */
X
Xvoid
XSetPoint (dict, rule, usernum, username)
X char *dict;
X char *rule;
X int usernum;
X char *username;
X{
X FILE *fp;
X long t;
X
X if (!(fp = fopen (pointfile, "w")))
X {
X perror (pointfile);
X return;
X }
X time (&t);
X fprintf (fp, "host=%s pid=%d pointtime=%s",
X this_hostname, pid, ctime (&t));
X fprintf (fp, "%s\n", this_hostname);
X fprintf (fp, "%s\n", dict);
X fprintf (fp, "%s\n", rule);
X fprintf (fp, "%d\n", usernum);
X fprintf (fp, "%s\n", username);
X fclose (fp);
X}
X/* read a pointfile in... */
X
Xint
XGetPoint (pf)
X char *pf;
X{
X FILE *fp;
X char buffer[STRINGSIZE];
X
X if (!(fp = fopen (pf, "r")))
X {
X perror (pf);
X return (-1);
X }
X /* junk */
X if (!fgets (buffer, STRINGSIZE, fp))
X {
X return (-2);
X }
X /* hostname */
X if (!fgets (old_hostname, STRINGSIZE, fp))
X {
X return (-3);
X }
X /* dictname */
X if (!fgets (old_dictname, STRINGSIZE, fp))
X {
X return (-4);
X }
X /* rule */
X if (!fgets (old_rule, STRINGSIZE, fp))
X {
X return (-5);
X }
X /* usernum */
X if (!fgets (buffer, STRINGSIZE, fp))
X {
X return (-6);
X }
X /* username */
X if (!fgets (old_username, STRINGSIZE, fp))
X {
X return (-7);
X }
X Trim (old_hostname);
X if (strcmp (old_hostname, this_hostname))
X {
X return (-8);
X }
X Trim (old_dictname);
X Trim (old_rule);
X old_usernum = atoi (buffer);
X Trim (old_username);
X fclose (fp);
X return (0);
X}
X/* jump ':' separated fields in an input */
X
Xchar *
XPWSkip (p)
X register char *p;
X{
X while (*p && *p != ':')
X {
X p++;
X }
X if (*p)
X {
X *p++ = '\0';
X }
X return (p);
X}
X/* parse and store a password entry */
X
Xstruct USER *
XParse (buffer)
X register char *buffer;
X{
X register char *p;
X register struct USER *retval;
X
X retval = (struct USER *) malloc (sizeof (struct USER));
X retval -> next = retval -> across = NULL;
X retval -> passwd_txt = NULL;
X retval -> done = 0;
X Trim (buffer);
X
X p = Clone (buffer, 0);
X retval -> filename = p;
X p = PWSkip (p);
X retval -> passwd.pw_name = p;
X p = PWSkip (p);
X retval -> passwd.pw_passwd = p;
X p = PWSkip (p);
X retval -> passwd.pw_uid = atoi (p);
X p = PWSkip (p);
X retval -> passwd.pw_gid = atoi (p);
X p = PWSkip (p);
X retval -> passwd.pw_gecos = p;
X p = PWSkip (p);
X retval -> passwd.pw_dir = p;
X p = PWSkip (p);
X retval -> passwd.pw_shell = p;
X return (retval);
X}
X/* load pre-formatted password entries off stdin into linked list */
X
Xint
XLoadData ()
X{
X char *ptr;
X char salt[2];
X char buffer[STRINGSIZE];
X int numlines;
X int numentries;
X register struct USER *new_element;
X register struct USER *current_line;
X
X numlines = 0;
X numentries = 0;
X current_line = NULL;
X salt[0] = salt[1] = '*';
X
X while (fgets (buffer, STRINGSIZE, stdin))
X {
X if (!*buffer || isspace (*buffer))
X {
X continue;
X }
X new_element = Parse (buffer);
X
X ptr = new_element -> passwd.pw_passwd;
X if (!ptr[0])
X {
X Log ("Warning! %s (%s in %s) has a NULL password!\n",
X new_element -> passwd.pw_name,
X new_element -> passwd.pw_shell,
X new_element -> filename);
X continue;
X }
X if (strchr (ptr, '*') ||
X strchr (ptr, '!') ||
X strchr (ptr, ' '))
X {
X Log ("User %s (in %s) has a locked password:- %s\n",
X new_element -> passwd.pw_name,
X new_element -> filename,
X new_element -> passwd.pw_passwd);
X continue;
X }
X if (strlen (ptr) < 13)
X {
X Log ("User %s (in %s) has a short crypted password - ignoring.\n",
X new_element -> passwd.pw_name,
X new_element -> filename);
X continue;
X }
X if (strlen (ptr) > 13)
X {
X Log ("User %s (in %s) has a long crypted password - truncating.\n",
X new_element -> passwd.pw_name,
X new_element -> filename);
X ptr[13] = '\0';
X }
X numentries++;
X
X if (ptr[0] == salt[0] && ptr[1] == salt[1])
X {
X new_element -> across = current_line;
X current_line = new_element;
X } else
X {
X if (current_line)
X {
X current_line -> next = userroot;
X }
X userroot = current_line;
X current_line = new_element;
X numlines++;
X salt[0] = ptr[0];
X salt[1] = ptr[1];
X }
X }
X
X if (current_line) /* last one tends to hang about */
X {
X current_line -> next = userroot;
X userroot = current_line;
X numlines++;
X }
X Log ("Loaded %d password entries into %d salted lines.\n",
X numentries, --numlines);
X
X return (numentries);
X}
X/* and load rules from a standard file into a similar list */
X
Xint
XLoadRules (file, rootpos)
X char *file;
X struct RULE **rootpos;
X{
X int i;
X FILE *fp;
X struct RULE *tmproot;
X char buffer[STRINGSIZE];
X register struct RULE *scratch;
X
X if (!(fp = fopen (file, "r")))
X {
X Log ("cannot open %s\n", file);
X perror (file);
X return (-1);
X }
X i = 0;
X tmproot = (struct RULE *) 0;
X
X while (fgets (buffer, STRINGSIZE, fp))
X {
X Trim (buffer);
X if (!buffer[0] || buffer[0] == '#') /* skip comments in dicts */
X {
X continue;
X }
X if (!tmproot)
X {
X scratch = (struct RULE *) malloc (sizeof (struct RULE));
X tmproot = scratch;
X } else
X {
X scratch -> next = (struct RULE *) malloc (sizeof (struct RULE));
X scratch = scratch -> next;
X }
X scratch -> rule = Clone (buffer, 0); /* full copy */
X scratch -> next = (struct RULE *) 0; /* forward order */
X i++;
X }
X fclose (fp);
X Log ("Loaded %d rules from '%s'.\n", i, file);
X *rootpos = tmproot;
X return (i);
X}
X/* load a dictionary into a linked list, sort it into an array */
X
Xint
XLoadDict (file, rule)
X char *file;
X char *rule;
X{
X register int i;
X int nelem;
X int tabled;
X int discarded;
X int rejected;
X char *lastptr;
X FILE *fp;
X register char *mangle;
X register struct DICT *scratch;
X char buffer[STRINGSIZE];
X
X if (!(fp = fopen (file, "r")))
X {
X perror (file);
X return (-1);
X }
X nelem = 0;
X rejected = 0;
X while (fgets (buffer, STRINGSIZE, fp))
X {
X Trim (buffer);
X if (!buffer[0])
X {
X continue;
X }
X mangle = Mangle (buffer, rule);
X
X if (!mangle)
X {
X rejected++;
X if (verbose_bool)
X {
X Log ("Rejected '%s' due to rule specs.\n", buffer);
X }
X continue;
X }
X if (dictroot && !strncmp (mangle, dictroot -> word, pwlength))
X {
X rejected++;
X if (verbose_bool)
X {
X Log ("'%s' ignored on load; duplicated to %d chars.\n",
X buffer, pwlength);
X }
X continue;
X }
X scratch = (struct DICT *) malloc (sizeof (struct DICT));
X scratch -> word = Clone (mangle, pwlength);
X scratch -> next = dictroot;
X dictroot = scratch;
X nelem++;
X
X if (verbose_bool)
X {
X Log ("Loaded '%s' as '%s' using '%s'\n", buffer, scratch -> word,
X rule);
X }
X }
X fclose (fp);
X
X if (nelem <= 0)
X {
X return (0);
X }
X Log ("Loaded %d words from '%s' using rule '%s'\n", nelem, file, rule);
X Log ("(Rejected %d words during loading)\n", rejected);
X
X dictbase = (char **) calloc (nelem, sizeof (char *));
X if (!dictbase)
X {
X Log ("PANIC: Cannot allocate memory for dictbase structure...\n");
X exit (1);
X }
X tabled = 0;
X for (scratch = dictroot; scratch; scratch = scratch -> next)
X {
X dictbase[tabled++] = scratch -> word;
X }
X
X Log ("Stored %d words in table for sorting\n", tabled);
X
X qsort (dictbase, tabled, sizeof (struct DICT *), DictCmp);
X
X discarded = 0;
X lastptr = dictbase[0];
X for (i = 1; i < tabled; i++)
X {
X /*
X * no point in putting a test-first-char STRCMP macro here, since in
X * sorted data, the first char is usually the same...
X */
X if (!strcmp (lastptr, dictbase[i]))
X {
X dictbase[i] = (char *) 0;
X discarded++;
X } else
X {
X lastptr = dictbase[i];
X }
X }
X
X Log ("Discarded %d duplicate words in sorted table\n", discarded);
X return (nelem);
X}
X/* lose the current dictionary */
X
Xint
XDropDict ()
X{
X struct DICT *scratch;
X
X while (dictroot)
X {
X free (dictroot -> word);
X scratch = dictroot -> next;
X free (dictroot);
X dictroot = scratch;
X }
X free (dictbase);
X return (0);
X}
X
X/*
X * write a feedback file if there is anything to save - return number
X * uncracked users
X */
X
Xint
XFeedBack (log_notdone)
X int log_notdone;
X{
X register FILE *fp;
X static char fmt[] = "%s:%s:%s:%s\n";
X register struct USER *head;
X register struct USER *arm;
X int done;
X int notdone;
X
X notdone = done = 0;
X
X Log ("Sweeping data looking for feedback.\n");
X
X fp = (FILE *) 0;
X
X for (head = userroot; head; head = head -> next)
X {
X for (arm = head; arm; arm = arm -> across)
X {
X if (arm -> done)
X {
X done++;
X /* horrible little hack, vile, sick, I love it */
X if (!fp)
X {
X if (!(fp = fopen (feedbackfile, "w")))
X {
X perror (feedbackfile);
X return(-1);
X }
X Log ("Feedback file opened for writing.\n");
X }
X fprintf (fp,fmt,feedback_string,
X arm -> passwd.pw_passwd,"Y",arm -> passwd_txt);
X } else
X {
X notdone++;
X if (log_notdone)
X {
X if (!fp) /* and again !!! heheheheheheh */
X {
X if (!(fp = fopen (feedbackfile, "w")))
X {
X perror (feedbackfile);
X return(-1);
X }
X Log ("Feedback file opened for writing.\n");
X }
X /* I think I'm going slightly warped */
X fprintf (fp,fmt,feedback_string,
X arm -> passwd.pw_passwd,"N","");
X }
X }
X
X }
X }
X if (fp)
X {
X fclose (fp);
X Log ("Closing feedback file.\n");
X }
X Log("FeedBack: %d users done, %d users left to crack.\n", done, notdone);
X return(notdone);
X}
X/* try a chain of users with the same salt */
X
Xint
XTryManyUsers (eptr, guess) /* returns 0 if all done this chain */
X register struct USER *eptr;
X char *guess;
X{
X register int retval;
X char guess_crypted[STRINGSIZE];
X
X if (eptr -> done && !eptr -> across)
X {
X return (0);
X }
X
X strcpy (guess_crypted, crypt (guess, eptr -> passwd.pw_passwd));
X
X retval = 0;
X
X while (eptr)
X {
X if (verbose_bool)
X {
X Log ("Trying '%s' on %s from line %s\n",
X guess,
X eptr -> passwd.pw_name,
X eptr -> filename);
X }
X if (!eptr->done && !STRCMP (guess_crypted, eptr -> passwd.pw_passwd))
X {
X PrintGuess (eptr, guess);
X }
X retval += (!(eptr -> done));
X eptr = eptr -> across;
X }
X
X return (retval);
X}
X/* try a word on an individual */
X
Xint
XTryOneUser (eptr, guess) /* returns non-null on guessed user */
X register struct USER *eptr;
X register char *guess;
X{
X if (!guess || !*guess || eptr -> done)
X {
X return (0);
X }
X if (verbose_bool)
X {
X Log ("Trying '%s' on %s from %s\n",
X guess,
X eptr -> passwd.pw_name,
X eptr -> filename);
X }
X if (strcmp (crypt (guess, eptr -> passwd.pw_passwd),
X eptr -> passwd.pw_passwd))
X {
X return (0);
X }
X PrintGuess (eptr, guess);
X
X return (1);
X}
X/* frontend to TryOneUser() to save hassle */
X
Xint
XWordTry (entry_ptr, guess)
X register struct USER *entry_ptr;
X register char *guess;
X{
X register int i;
X struct RULE *ruleptr;
X register char *mangle;
X
X if (!guess[0] || !guess[1])
X {
X return (0);
X }
X for (ruleptr = gecosroot; ruleptr; ruleptr = ruleptr -> next)
X {
X if (mangle = Mangle (guess, ruleptr -> rule))
X {
X if (TryOneUser (entry_ptr, mangle))
X {
X return (1);
X }
X }
X }
X return (0);
X}
X/* Special manipulations for the GECOS field and dotfiles */
X
Xint
XParseBuffer (entry_ptr, buffer, advanced)
X register struct USER *entry_ptr;
X char *buffer;
X int advanced;
X{
X int wordcount;
X register int i;
X register int j;
X register char *ptr;
X char junk[STRINGSIZE];
X char *words[WORDSTACKSIZE];
X
X /* zap all punctuation */
X for (ptr = buffer; *ptr; ptr++)
X {
X if (ispunct (*ptr) || isspace (*ptr))
X {
X *ptr = ' ';
X }
X }
X
X /* break up all individual words */
X wordcount = 0;
X ptr = buffer;
X while (*ptr)
X {
X while (*ptr && isspace (*ptr))
X {
X ptr++;
X }
X if (*ptr)
X {
X words[wordcount++] = ptr;
X if (wordcount >= WORDSTACKSIZE)
X {
X Log ("ParseBuffer: Abort: Stack Full !\n");
X return (0);
X }
X }
X while (*ptr && !isspace (*ptr))
X {
X ptr++;
X }
X
X if (*ptr)
X {
X *(ptr++) = '\0';
X }
X }
X
X words[wordcount] = (char *) 0;
X
X /* try all the words individually */
X if (verbose_bool)
X {
X Log ("Trying individual words\n");
X }
X for (i = 0; i < wordcount; i++)
X {
X if (WordTry (entry_ptr, words[i]))
X {
X return (1);
X }
X }
X
X if (!advanced)
X {
X return (0);
X }
X
X /* try pairings of words */
X if (verbose_bool)
X {
X Log ("Trying paired words\n");
X }
X for (j = 1; j < wordcount; j++)
X {
X for (i = 0; i < j; i++)
X {
X /* Skip initials for next pass */
X if (!words[i][1] || !words[j][1])
X {
X continue;
X }
X strcpy (junk, words[i]);
X strcat (junk, words[j]);
X if (WordTry (entry_ptr, junk))
X {
X return (1);
X }
X }
X }
X
X /* try initials + words */
X if (verbose_bool)
X {
X Log ("Trying initial'ed words\n");
X }
X for (j = 1; j < wordcount; j++)
X {
X for (i = 0; i < j; i++)
X {
X junk[0] = words[i][0];
X if (islower (junk[0]))
X {
X junk[0] = toupper (junk[0]);
X }
X junk[1] = '\0';
X strcat (junk, words[j]);
X if (WordTry (entry_ptr, junk))
X {
X return (1);
X }
X }
X }
X
X return (0);
X}
X/* run over password entries looking for passwords */
X
Xvoid
XPass1 ()
X{
X int i;
X int j;
X FILE *fp;
X int cracked;
X char junk[DOTFILESIZE];
X char filename[STRINGSIZE];
X struct USER *head;
X register char *ptr;
X register struct USER *this;
X static char *dotfiles[] =
X {
X ".plan",
X ".project",
X ".signature",
X (char *) 0
X };
X
X Log ("Starting pass 1 - password information\n");
X
X for (head = userroot; head; head = head -> next)
X {
X for (this = head; this; this = this -> across)
X {
X strcpy (junk, this -> passwd.pw_gecos);
X
X if (WordTry (this, this -> passwd.pw_name) ||
X ParseBuffer (this, junk, 1))
X {
X continue;
X }
X#ifdef CRACK_DOTFILES
X for (i = 0; dotfiles[i]; i++)
X {
X sprintf (filename, "%s/%s", this -> passwd.pw_dir, dotfiles[i]);
X
X if (!(fp = fopen (filename, "r")))
X {
X continue;
X }
X
X j = fread (junk, 1, DOTFILESIZE, fp);
X
X fclose (fp);
X
X if (j <= 1)
X {
X continue;
X }
X
X junk[j - 1] = '\0'; /* definite terminator */
X
X if (verbose_bool)
X {
X Log("DOTFILES: Checking %d bytes of %s\n", j, filename);
X }
X
X if (ParseBuffer (this, junk, 0))
X {
X continue;
X }
X }
X#endif CRACK_DOTFILES
X }
X }
X return;
X}
X
Xvoid
XPass2 (dictfile)
X char *dictfile;
X{
X int i;
X int pointuser;
X int dictsize;
X struct USER *headptr;
X struct RULE *ruleptr;
X
X Log ("Starting pass 2 - dictionary words\n");
X headptr = (struct USER *) 0;
X ruleptr = (struct RULE *) 0;
X
X /* check if we are recovering from a crash */
X if (recover_bool)
X {
X recover_bool = 0; /* switch off */
X for (ruleptr = ruleroot;
X ruleptr && strcmp (ruleptr -> rule, old_rule);
X ruleptr = ruleptr -> next);
X if (!ruleptr)
X {
X Log ("Fatal: Ran off end of list looking for rule '%s'\n",
X old_rule);
X exit (1);
X }
X for (headptr = userroot; /* skip right number of users */
X headptr && old_usernum--;
X headptr = headptr -> next);
X if (!headptr)
X {
X Log ("Fatal: Ran off end of list looking for user '%s'\n",
X old_username);
X exit (1);
X }
X }
X
X /* start iterating here */
X for (ruleptr = (ruleptr ? ruleptr : ruleroot);
X ruleptr;
X ruleptr = ruleptr -> next)
X {
X if ((dictsize = LoadDict (dictfile, ruleptr -> rule)) <= 0)
X {
X Log ("Oops! I got an empty dictionary! Skipping rule '%s'!\n",
X ruleptr -> rule);
X continue;
X }
X pointuser = 0;
X
X /* iterate all the users */
X for (headptr = (headptr ? headptr : userroot);
X headptr;
X headptr = headptr -> next)
X {
X SetPoint (dictfile,
X ruleptr -> rule,
X pointuser++,
X headptr -> passwd.pw_name);
X
X /* iterate all the words */
X for (i = 0; i < dictsize; i++)
X {
X /* skip repeated words... */
X if (dictbase[i] && !TryManyUsers (headptr, dictbase[i]))
X {
X break;
X }
X }
X }
X /* free up memory */
X DropDict ();
X /* write feedback file */
X if (!FeedBack (0))
X {
X Log("FeedBack: information: all users are cracked after this pass\n");
X return;
X }
X /* on next pass, start from top of user list */
X headptr = (struct USER *) 0;
X }
X}
X
Xint
Xmain (argc, argv)
X int argc;
X char *argv[];
X{
X int i;
X int uerr;
X long t;
X int die_bool = 0;
X FILE *fp;
X char *file;
X char *crack_out;
X extern int optind;
X extern char *optarg;
X static char getopt_string[] = "i:fX:n:r:vml:";
X
X uerr = 0;
X if (argc == 1)
X {
X uerr++;
X }
X while ((i = getopt (argc, argv, getopt_string)) != EOF)
X {
X switch (i)
X {
X case 'i':
X strcpy (input_file, optarg);
X if (!freopen (input_file, "r", stdin))
X {
X perror (input_file);
X exit (1);
X }
X if (!strncmp(input_file, "/tmp/pw.", 7))
X {
X unlink(input_file);
X }
X break;
X case 'm':
X mail_bool = 1;
X break;
X case 'f':
X foreground_bool = 1;
X break;
X case 'X':
X remote_bool = 1;
X strcpy (supplied_name, optarg);
X break;
X case 'l':
X pwlength = atoi (optarg);
X break;
X case 'n':
X nice_value = atoi (optarg);
X nice (nice_value);
X break;
X case 'r':
X recover_bool = 1;
X strcpy (recover_file, optarg);
X break;
X case 'v':
X verbose_bool = 1;
X break;
X default:
X case '?':
X uerr++;
X break;
X }
X }
X
X if (optind >= argc)
X {
X uerr++;
X }
X if (uerr)
X {
X fprintf (stderr,
X "Usage:\t%s -%s dictfile [dictfile...]\n",
X argv[0],
X getopt_string);
X exit (1);
X }
X time (&t);
X pid = getpid ();
X if (!(crack_out = (char *) getenv ("CRACK_OUT")))
X {
X crack_out = ".";
X }
X sprintf (opfile, "%s/out.%d", crack_out, pid);
X if (remote_bool)
X {
X sprintf (diefile, "%s", supplied_name);
X } else
X {
X sprintf (diefile, "%s/D.%d", runtime, pid);
X }
X sprintf (pointfile, "%s/P.%d", runtime, pid);
X sprintf (feedbackfile, "%s/F.%d", runtime, pid);
X
X if (gethostname (this_hostname, STRINGSIZE))
X {
X perror ("gethostname");
X }
X if (!foreground_bool)
X {
X if (!freopen (opfile, "w", stdout))
X {
X perror ("freopen(stdout)");
X exit (1);
X }
X if (!freopen (opfile, "a", stderr))
X {
X perror ("freopen(stderr)");
X exit (1);
X }
X }
X /*
X * don't generate a die file unless we are not 'attached' to a
X * terminal... except when we are remote as well...
X */
X
X if (!foreground_bool || (foreground_bool && remote_bool))
X {
X if (!(fp = fopen (diefile, "w")))
X {
X perror (diefile);
X exit (1);
X }
X die_bool = 1;
X fprintf (fp, "#!/bin/sh\n");
X fprintf (fp, "# host=%s pid=%d starttime=%s",
X this_hostname, pid, ctime (&t));
X fprintf (fp, "kill -TERM %d && rm $0", pid);
X fclose (fp);
X chmod (diefile, 0700);
X }
X Log ("Crack v%s: The Password Cracker, (c) ADE Muffett, 1991\n", version);
X
X#ifdef FCRYPT
X init_des ();
X#endif
X
X /* Quick, verify that we are sane ! */
X
X if (strcmp (crypt ("fredfred", "fredfred"), "frxWbx4IRuBBA"))
X {
X Log ("Version of crypt() being used internally is not compatible with standard.\n");
X Log ("This could be due to byte ordering problems - see the comments in Sources/conf.h\n");
X Log ("If there is another reason for this, edit the source to remove this assertion.\n");
X Log ("Terminating...\n");
X exit (0);
X }
X signal (SIGTERM, CatchTERM);
X
X Log ("Loading Data, host=%s pid=%d\n", this_hostname, pid);
X
X if (LoadData () <= 0)
X {
X Log ("Nothing to Crack. Exiting...\n");
X exit (0);
X }
X if (LoadRules (rulefile, &ruleroot) < 0 ||
X LoadRules (gecosfile, &gecosroot) < 0)
X {
X exit (1);
X }
X if (!recover_bool)
X {
X /* We are starting afresh ! Ah, the birds in May ! */
X Pass1 ();
X if (!FeedBack (0))
X {
X Log("FeedBack: information: all users are cracked after gecos pass\n");
X goto finish_crack;
X }
X } else
X {
X int rval;
X if (rval = GetPoint (recover_file))
X {
X Log ("Recovery from file %s not permitted on this host [code %d]\n",
X recover_file,
X rval);
X exit (0);
X }
X /* Some spodulous creep pulled our plug... */
X while ((optind < argc) && strcmp (argv[optind], old_dictname))
X {
X optind++;
X }
X }
X
X for (i = optind; i < argc; i++)
X {
X Pass2 (argv[i]);
X }
X
X Log ("Tidying up files...\n");
X FeedBack (1);
X
Xfinish_crack:
X
X if (die_bool)
X {
X unlink (diefile);
X }
X unlink (pointfile);
X
X Log ("Done.\n");
X
X return (0);
X}
END_OF_FILE
if test 23895 -ne `wc -c <'Sources/crack-pwc.c'`; then
echo shar: \"'Sources/crack-pwc.c'\" unpacked with wrong size!
fi
# end of 'Sources/crack-pwc.c'
fi
echo shar: End of archive 4 \(of 5\).
cp /dev/null ark4isdone
MISSING=""
for I in 1 2 3 4 5 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 5 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
exit 0 # Just in case...
--
Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD UUCP: uunet!sparky!kent
Phone: (402) 291-8300 FAX: (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.