APPENDIX 100600 5661 132 33203 5222357122 7571 0 0 ecd ftp 1 0 I'd like to thank Chris Samuel and Peter Grandi for all their help in
beta-testing early versions of Crack, and in Peter's case especially,
for dropping me into the deep end of troff. Die, you bastard. As for
Chris's major contribution, see "Scripts/plaster". 8->
For the v3.? versions of Crack, I'd like to thank Chris Myers, Randal
Schwartz, Chris Lewis, and M.Maclaren. Also Brian Tompsett, for
pointing me at the now infamous v3.2 bug, and for suggestions, patches,
and enormous amounts of debugging information. To him should go the
prize for "Most Vociferous Beta Tester Ever".
For Crack v4.1, the greatest help has come from the members of the crack
beta team, the most vociferous of whom are:
[email protected],
[email protected],
[email protected],
[email protected],
[email protected],
[email protected],
[email protected],
[email protected],
[email protected],
[email protected],
[email protected],
[email protected],
[email protected],
[email protected],
[email protected],
[email protected],
[email protected],
[email protected],
[email protected]
- especially Fred "Mr Statistics" Korz, Paul Leyland, and shabby@purdue
for all the debugging info. Also a bit thanks to Michael Glad for being
so helpful while we were writing a decent software interface between
Crack and UFC.
I also wish to acknowledge the help of Kent Landfield (moderator of
comp.sources.misc) and Dan "COPS" Farmer, both of them for goading me
into releasing a version of Crack with fcrypt() installed. Without
them, I probably would have been too timid...
Finally, my gratitude goes to my girlfriend Gilly, for her support
during the bad times. You are the everything.
--
INET:
[email protected] JANET:
[email protected] BITNET: aem%aber@ukacrl
UUCP: ...!mcsun!ukc!aber!aem ARPA: aem%
[email protected]
Alec Muffett, Somewhere in the UK, Probably lying under a tree drinking cider
**********************************************************************
Several people have asked me why I don't write Crack so that it
distributes dictionaries over the network and hacks the same password
file on each machine, as opposed to spreading users over the network and
using the same dictionaries.
There are several reasons for this, which I will outline.
The reasoning that spreading the dictionaries over the network is faster
is correct in the case of cracking the passwords of ONE user - it is
most efficient to run different dictionaries on him on several machines,
and you will break his password eventually.
Scaling this by a factor of 'n' users causes problems. Firstly, if a
machine guesses one persons password, it must inform all others on the
network not to waste time cracking him, but to get on with the other
users. This is difficult and nasty.
Secondly, it is not what Crack was designed to do. The name "Crack" is
actually a misnomer - Crack really ought to be called "Passwdcheck" or
something similar, but such names lack sex appeal.
Crack is not a program designed to break the password of every user in
the file. Rather, it is designed to find weak passwords in the file, by
attacking those sorts of bad passwords which are most likely to be used,
in the order in which they would most easily be found (ie: are most
likely to be used by a moronic user).
Crack is not designed to break user passwords; it is designed to break
password files. This is a subtle but important distinction.
If you want to break into a safe, you do not take a hammer at every bit
of it in turn; instead, first you try some simple combinations, then you
try blowing the hinges off, then you get out an acetylene torch and go
for the bolt. If that doesnt work, THEN you start on the walls. You go
for the bits which are most likely to be weak first.
Consider a password file with 'n' users in it. Say that your ordinary,
serial password cracker (eg: the one supplied with COPS) has a
dictionary of 1000 words, and tries each word 6 ways (upper/lower/mixed
case, permuted with forwards/backwards)
Also consider that out of that 1000 users, only one (the last one) has a
guessable password - "fred".
Also say that it takes time 'T' seconds to encrypt a word.
If you use the "try each user in turn" method, like the COPS password
cracker, you will have to wait for a time:-
999 users * 1000 words * 6 ways * T = 5,994,000 T seconds
before you get to that last user. Spreading this load around on a
network only alleviates the number of words to be searched (divides them
by the number of machines you are working on).
Thus, if you use 10 machines, the machine which will guess "fred" will
get to that last user in:-
999 * (1000 / 10) * 6 ways = 599,400 T seconds.
Alternatively you can try it the Crack way - "fred" is a word which
appears in a forwards dictionary. You will only wait:-
999 users * 1000 words * 1st way * T = 999,000 T seconds
to get to that user. Now split the users across 10 machines (for
simplicity, as outlined above):-
(999 / 10) users * 1000 words * 1st way = 99,900 T seconds
To get to his password, in ONLY 17% of the time taken by networking
using the serial cracking method. This is only a boundary case, but I
hope I have illustrated the concept.
**********************************************************************
Crack has several other optimisations because of its structured password
guesses. The figures below are entirely empirical, but I reckon that
they're as good as any:
The first pass that Crack makes is over the user data user information
gleaned from the users' password field. In my test file, this gets
about 4% of the passwords (out of a total of 15% guessed). This pass
also completes very quickly, working as it does from a very small
amount of data, but one which is very frequently used for passwords.
The first sweep of the second pass, consisting of lowercase dictionary
words, gets about another 5% of the passwords. The length of the first
sweep depends on how much CPU and how many dictionaries I supply, but
using the Ultrix /usr/dict/words and my bad_pws.dat, over 4 CPUs, it
doesn't take much more that a few hours.
For the further sweeps, the percentages cracked per sweep tail off, 2%,
1%, 0.5%... But they are the people with fairly exotic passwords, and
it's only common sense that that they will take some time to crack.
**********************************************************************
There is another major optimisation that I haven't mentioned.
Because of the way the UNIX crypt() algorithm works, each encryption is
"salted" with a two letter sequence which is stored as the first two
characters of the encrypted password. This salting means that the word
"fred" can be encrypted and appear in a password file in (literally)
thousands of different ways - so long as each encryption has a
different salt.
Hence, it makes sense to do things in this manner:
1) sort and group the input data by encryption salt.
2) for each different groups' encryption salt
* get a dictionary word
* encrypt it using that salt (This is the time consuming bit)
* compare the encryption with each member of the group with that salt
* if it matches, you have guessed that users password.
This knocks (empirical guesswork time again) up to one third of the
dictionary encryptions off - thus saving you 0.3 of the time all the
dictionary sweeps would ordinarily take.
Crack gives this statistic when it says
pwc: Loaded 'n' password entries into 'm' salted lines. (x%)
where 'x' is the percentage of the total passwords loaded which have
different salts.
**********************************************************************
Some people have asked me how to generate safe passwords. This, has
become a religious issue, and there are now several vociferous
"password geeks" on USENET, who will say "my method is the best", in
the same way that some mathematicians will try to compare so-called
"random number generating algorithms".
Such statements are pointless. I'm sorry for adding to the confusion,
but I must say that I think they are wrong.
Okay, so I am a security fatalist and a security philosopher, but I am
not going to give and hard and fast answers; rather, I'd like to make
some points and recommendations to the people out there. Security isn't
a tangible thing, it is applied psychology.
The whole point of a password is to prevent people accessing your
system, getting into it from outside. Once someone is inside your
system, assuming that they have the relevant knowledge of your O/S, it
is safest to assume that anyone can get to be 'superuser'. Your only
security once someone is on your system is called "security by
obscurity". If your user has sufficient knowledge, you've "had it".
The question isn't "How secure can my system be made?".
The question really should be, "How much do I care, how much can I trust?".
A system can be perfectly secure without any passwords at all, so long
as it is in an environment of people who recognise its purpose and
depend on it. I say this after having had acounts on several 'public'
machines, which could have been taken to bits by any competent Unix
person, but were largely safe - because when someone worked out who did
anything nasty, the culprit was ostracised from the community. There
_is_ a caveat to this, however.
The problem is the sort of people who go around the world 'collecting'
computer accounts and breaking machines, those who have either a
childish mentality or an ulterior motive.
The former are like the little boys who go around breaking windows and
vandalising things 'for kicks'. They are the ones who see every
password file as a "NO ENTRY" sign, and therefore, driven by what they
think is anarchy and fun, they break in and smash the place up. Tell
them that they are behaving like children, and they will behave moreso.
The latter are driven by personal motives or money. Their reasons are
too complex for me to analyse here.
The 'babyish' hackers need a lesson (which I hope that eventually they
learn) that true anarchy is for the general good, and is best achieved
by fiat amongst the community. USENET is a good example - there is a
lot of petty bickering and arguing, but an incredible amount of good
comes out of it. It is anarchy that the greek philosophers would have
approved of.
What I am trying to say is that, when I say that if someone gets into
your system, you've "had it", you should consider whether there is
anything to have "had" in the first place. There is no point in getting
yourself paranoid over security - if you do, you'll lose out. Don't be
too paranoid. Be SENSIBLE instead, and secure your system according to
it's needs, and not according to some 'holy bible' of absolute security.
If someone gets into your system, you find out how they did it, patch
the hole, check for back doors, brush yourself off, and start again.
It's not the end of the world.
What this statement doesn't address (yet) is the needs of system
managers who have a REAL need for security - be it corporate data or
research work - on their system. As I have said before, most O/S's have
gaping holes in them that cannot be entirely filled, and so the crackers
must be stopped on the doorstep. At the password login.
People who say that they have a way of generating safe passwords are
misinformed, IMHO. Saying that the password "wyufwqpl" is secure is as
meaningful as saying that the number "4" is random. Password security,
like any other form of computer security, is not absolute, but should
be taken in context.
You can't say that a certain method will provide secure, random
passwords, because, in defining an algorithm to create these passwords,
you will use only a subset of all the possible passwords that could ever
exist. You have shrunk the 'search space' for the passwords.
Someone merely has to write a password cracker which will search this
small subset of passwords, in order to break your system. Passwords
generated by any algorithm, human or computer based, are merly
pseudo-secure, in the same way that numbers can be pseudo-random. For
illustration of this aspect of password security, read the document
"Password Security, A Case History" by Morris and Thompson.
There is an incredibly large set of possible passwords in the world, and
the best approach toward choosing a password is not to try to find a way
to generate 'secure' passwords - there are no such things - but rather
you should learn to choose passwords which are not easily searched for.
Passwords which are out of the 'search space' of most password crackers
like 'Crack'.
Read the Crack documentation. See what sort of things other programs
like Crack would search for. Think of some yourself. I am not going to
specifically mention methods, you should really work something out for
yourself.
At the bottom line, the password "fred" is just as secure (random) as
the password "blurflpox"; the only problem is that "fred" is in a more
easily searched part of the "password space".
Both of these passwords are more easily found than "Dxk&2+15^N" however.
Now you must ask yourself if you can cope with remembering "Dxk&2+15^N".
**********************************************************************
Some time ago, I was listening to the REM album 'Green' on the way back
from the Cropredy folk festival, whilst thinking over things to do to
Crack, and I was struck (not for the first time) by the words of the
first verse to 'World Leader Pretend':-
I sit at my table, and wage war upon myself.
It seems like it's all, it's all for nothing.
I know the barricades, and I know the mortar in the wall
I recognise the weapons, I use them well.
This is my mistake, let me make it good,
I raised the wall, and I will be the one to knock it down...
- writing password cracking programs gets to you after a bit.
etylene torch and go
for the bolt. If that doesnt work, THEN you start on the walls. You go
for the bits which are most likely to be weak first.
Consider a password file with 'n' users in it. Say that your ordinary,
serial password cracker (eg: the one supplied with COPS) has a
dictionary of 1000 words, and tries each word 6 ways (upper/lower/mixed
case, permuted with forwarBUGS 100600 5661 132 2130 5222357015 5707 0 0 1 0 Bugs as of 1 Mar 1992:-
* Crack: is known to occasionally hang during a "Crack -network" whilst
rshing from machine to machine on some architectures. It's a persistent
problem at some sites, when Crack rsh'es to a particular machine and
stays there, and thus never calls the next machine.
FIX: mark machines that hang Crack with the "-f" option in network.conf
file, then the 'rsh' will be backgrounded and Crack will continue to the
next machine. The tweak in Crack v4.1 to close descriptors 0->9 on all
machines (esp Apollos) may help this.
* Beta testers on DEC 5500s have reported crack-pwc crashing when
compiled with the optimiser. This apparently doesn't happen using GCC
or when optimisation is turned off (heisenbug?)
Be warned.
* Earlyish System V type systems will have problems if the environment
variable SHELL is not set to "/bin/sh" - this is because SV will
blithely ignore the "#!/bin/sh" line and invoke a csh anyway, if thats
what you prefer.
This is probably most easily diagnosed when Crack bails out like this:
CRACK_HOME=/your/crack/directory: Command not found.
- or similar.
a total of 15% guessed). This pass
also completes very quickly, working as it does from a very small
amount of data, but one which is very frequently used for passwords.
The first sweep of the second pass, consisting of lowercase dictionary
words, gets about another 5% of the passwords. The length of the first
sweep depends on how much CPU and how many dictionaries I supply, but
using the Ultrix /usr/dict/words and myCrack 100700 5661 132 15122 5222357125 6222 0 0 1 0 #!/bin/sh
###
# This program is copyright Alec Muffett 1991, and is provided as part of
# the Crack v4.1 Password Cracking package. The author disclaims all
# responsibility or liability with respect to it's usage or its effect
# upon hardware or computer systems, and maintains copyright as set out in
# the "LICENCE" document which accompanies distributions of Crack v4.0 and
# upwards. So there...
###
###
# CRACK_HOME: You must put DOUBLE QUOTES around this and have /bin/csh if
# you work relative to ~username - this is the Crack installation directory.
# (currently developing on "dougal")
###
CRACK_HOME="~aem/dougal/crack41f"
###
# CRACK_OUT: This is the directory into which all the password guesser
# output files are to be stored. This affects only the "out*" files, and
# not "D*" or "P*", due to restraints on the support scripts.
###
CRACK_OUT="$CRACK_HOME"
###
# Umask for security's sake - stops files being world readable (if you
# don't have it in your .login)
###
umask 077
###
# DEFAULT_BIN : For non-network cracks, you can leave this as 'generic'.
# Setting this to `arch` is non-portable.
###
DEFAULT_BIN="generic"
###
# List of standard dictionaries that you should have to provide words;
#
###
STDDICT="/usr/dict/words"
###
# Compress: name of a compression prog (compress & pack supported) to be
# applied to the bigdict to save filespace
###
compress="/usr/ucb/compress"
###
############### FROM HERE ON IN IT'S ALL MY FAULT ###############
###
version="4.1f RELEASE" # version number
pwl="" # user specified
domail="" # user specified
fgnd="" # user specified
remote="" # program specified
nice="" # user specified
rcvr="" # user specified
inputfile="/tmp/pw.$$" # program specified, also in pwc.c
verbose="" # user specified
cf_file="Scripts/network.conf" # program specified
bigdict="Dicts/bigdict" # program specified
lockdict="Dicts/.lockfile" # program specified
CRACK_HOME_UNRES="$CRACK_HOME"
if [ -f "/bin/csh" ] # -x bombs on Ultrix
then
CRACK_OUT=` /bin/csh -fc "echo $CRACK_OUT" `
CRACK_HOME=` /bin/csh -fc "echo $CRACK_HOME" `
fi
if [ ! -d "$CRACK_OUT" ]
then
echo "Warning: CRACK_OUT directory reset to directory '.'"
CRACK_OUT="."
fi
export CRACK_HOME
export CRACK_OUT
export DEFAULT_BIN
export CRACK_HOME_UNRES
###
# Check existance of a home directory
###
if [ "$CRACK_HOME" != "" -a -d "$CRACK_HOME" ]
then
cd $CRACK_HOME || exit 1
else
echo "Fatal error: the directory $CRACK_HOME does not exist."
echo ""
echo "Please set the value of CRACK_HOME in the 'Crack' script to the name of
echo "the installation directory."
echo ""
echo "The current working directory is" `pwd`"
exit 1
fi
###
# Announce ourselves.
###
echo "Crack $version, The Password Cracker (c) Alec D.E. Muffett, 1992"
echo "Invoked as: $0 $*"
if [ $# = 0 ]
then
echo "Usage: $0 [options] [bindir] passwdfile [...]"
echo "Or: $0 -network [options] passwdfile [...]"
echo "Options:-"
echo " -v - to produce verbose output"
echo " -nnicevalue - to run niced to 'nicevalue'"
echo " -rpointfile - to recover a crashed-out job"
echo " -Rpointfile - to recover (with verify) a crashed-out job"
echo " -f - to run in foreground (output to stdout)"
echo " -m - to mail the user a warning message if cracked"
exit 1
fi
###
# Make the dictionaries. God this is SOOOOO much simpler...
###
if [ ! -f $lockdict ]
then
echo "Making dictionary $bigdict - This may take some time..."
(
for dictfile in $STDDICT DictSrc/*
do
case $dictfile in
*.Z)
zcat $dictfile
;;
*.z)
pcat $dictfile
;;
*)
cat $dictfile
;;
esac
done
) |
grep -v '^#' |
sort |
uniq > $bigdict
# I do not do "tr A-Z a-z" here because of words like LaTeX and
# BiCapitalisation, which are potential passwords, but the structure of
# which would be irrecoverably destroyed by lowercaseing.
echo touch $lockdict # for future refs.
touch $lockdict
if [ "x$compress" != "x" -a -f "$compress" ]
then
echo $compress $bigdict
# if this fails, tweak the $compress definition above...
$compress $bigdict || exit 1
fi
else
echo Dictionary Dicts/* intact
fi
###
# Check your invocation...
###
if [ "x$1" = "x-network" ]
then
shift
Scripts/Crack.network $*
exit 0
fi
while :
do
case $1 in
-network)
echo "Error: -network (if specified) must be first argument"
exit 1
;;
-X*)
remote=$1
shift
;;
-m*)
domail=$1
shift
;;
-l*)
pwl=$1
shift
;;
-f*)
fgnd=$1
shift
;;
-n*)
nice=$1
shift
;;
-r*)
rcvr=$1
shift
;;
-v*)
verbose=$1
shift
;;
-*)
echo "Error: unknown argument $1"
shift
;;
*)
break
;;
esac
done
###
# Test first non-switch argument for existance, hence where to put binaries
###
if [ -f "$1" ]
then
CRACK_ARCH="$CRACK_HOME/$DEFAULT_BIN"
else
CRACK_ARCH="$CRACK_HOME/$1"
shift
fi
export CRACK_ARCH
echo "Binary directory: $CRACK_ARCH"
###
# Make the password cracker
###
Scripts/do_pwc $CRACK_ARCH || exit 1
###
# Process input to the program
###
echo "Sorting data for Crack."
if [ "x$remote" != "x" ]
then
cat > $inputfile
else
out_init=$CRACK_OUT/out.$$
Scripts/do_join $out_init $* > $inputfile || exit 1
if [ "x$domail" != "x" ]
then
MISCREANTS=`awk '/Guessed/{print $6}' < $out_init`
echo Sending Warning Mail to $MISCREANTS
Scripts/nastygram $MISCREANTS
fi
if [ "x$fgnd" != "x" ]
then
cat $out_init || exit 1
rm -f $out_init
fi
fi
###
# Check the runtime scratch file directory for pwc
###
if [ ! -d Runtime ]
then
echo "Creating Runtime Directory."
mkdir Runtime || exit 1
fi
###
# Kick it off into the background ?
###
# This is the message which has drawn the most complaints... However, I
# have no way of knowing the name in advance, and I can't have crack-pwc
# print it on stdout due to hanging file descriptors which bollox a
# network crack. Hence I HAVE to be vague...
###
flags="$remote $fgnd $XXdomail $pwl $nice $rcvr $verbose -i $inputfile"
echo "Flags:" $flags Dicts/*
if [ "x$fgnd" != "x" ]
then
echo "Running program in foreground"
$CRACK_ARCH/crack-pwc $flags Dicts/* < /dev/null 2>&1
else
echo "Running program in background"
# Apollos/Suns need first 7 descriptors closed to bg properly
# from ksh - hence overkill - AEM
nohup $CRACK_ARCH/crack-pwc $flags Dicts/* </dev/null >/dev/null \
2>&1 3>&1 4>&1 5>&1 6>&1 7>&1 8>&1 9>&1 &
echo "Output will be written to a file in directory $CRACK_OUT"
echo "named 'out<something>'"
fi
sleep 1
test -f nohup.out && rm nohup.out
###
# There are horrible timeraces involved in removing $tmpfile, so I dont.
# Crack-pwc does. Still. Hohum.
###
exit 0
n' on the way back
from the Cropredy folk festival, whilst thinking over things to do to
Crack, and I was struck (not for the first time) by the words of the
first verse to 'World Leader Pretend':-
I sit at my table, and wage war upon myself.
It seems like it's all, it's all for nothing.
I know the barricades, and I know the mortar in the wall
I recognise the weapons, I use them well.
This is my mistake, let me make it DictSrc/ 40755 5661 132 0 5222357130 6474 5 0 1 0 DictSrc/jargon 100600 5661 132 7135 5222357020 10601 0 37777777777 1 0 # From: eric%snark.thyrsus.com%
[email protected] (Eric S. Raymond)
# Subject: improved Jargon File wordlist for crack 4.0
# Eric S. Raymond =
[email protected] (mad mastermind of TMN-Netnews)
ACK
ALT
AOS
BBS
BFI
BIFF
BITNET
BLT
BOF
BQS
BRS
BSD
BWQ
BartleMUD
Berzerkeley
BiCapitalization
CI
CLM
CTY
DDT
DEADBEEF
DEChead
DP
DPB
DPer
DRECNET
DWIM
Discordianism
EMACS
ENQ
EOL
EOU
EXCH
EXE
Eris
FAQL
FOAF
FOD
FTP
FUBAR
FUD
FidoNet
Foonly
Fortrash
GC
GECOS
GFR
GIGO
GIPS
GNUMACS
GOSMACS
GPL
GPV
Godzillagram
Gosperism
HAKMEM
HCF
HHOK
HHOS
HLL
Hackintosh
IMHO
INTERCAL
IRC
IWBNI
IYFEG
JEDR
JFCL
JRST
K&R
KIPS
LDB
LER
LERP
LN
LPT
MEGO
MFTL
MIPS
MOTAS
MOTOS
MOTSS
Macintoy
Macintrash
Moof
NAK
NMI
NeWS
PBD
PD
PETSCII
POM
POPJ
PPN
Perl
QWERTY
RETI
RFC
RFE
RL
RSN
RTFAQ
RTFM
RTI
RTM
SCSI
SMOP
SPACEWAR
SysVile
TCB
TECO
TELNET
TLA
TMRC
TWENEX
TeX
TechRef
UBD
USENET
UTSL
UUCPNET
VAXectomy
VAXen
VMS
VR
WIBNI
WOMBAT
WYSIAYG
WYSIWYG
Weenix
XOFF
XXX
YABA
YAUN
Zork
abbrev
adger
admin
annoybot
app
attoparsec
autobogotiphobia
avatar
awk
bagbiter
bamf
barf
barfulation
barfulous
baz
bboard
berklix
biff
bignum
bitblt
bixie
blargh
bletch
bletcherous
blinkenlights
blit
blitter
blivet
bogometer
bogon
bogosity
bogotify
boink
bonk
boxen
boxology
bozotic
braino
breedle
broket
buglix
bytesexual
careware
cdr
chad
chanop
charityware
clustergeeking
codewalker
cokebottle
computron
condom
copybroke
copyleft
copywronged
corge
cray
crayola
crippleware
crlf
crudware
cruft
cruftsmanship
crufty
cryppie
cuspy
cybercrud
cyberpunk
cyberspace
daemon
dd
deckle
dehose
delint
depeditate
devo
dink
doc
doco
dodgy
dogcow
dogwash
dongle
donuts
doorstop
droid
dynner
email
emoticon
erve
excl
fab
featurectomy
feep
feeper
filk
finn
firebottle
firefighting
firmy
flamage
flarp
flippy
flytrap
followup
foo
foobar
fora
fred
frednet
freeware
friode
fritterware
frob
frobnicate
frobnitz
frotz
frotzed
frowney
fuggly
fuzzball
gabriel
garply
geef
gen
gensym
gillion
glark
glassfet
glork
gnarly
gonk
gonkulator
gonzo
gorp
gotcha
grault
gritch
grok
gronk
gronked
grunge
gubbish
guiltware
gumby
gunch
gurfle
gweep
hackish
hackishness
hackitude
hakspek
handwave
hardcoded
hardwarily
hardwired
heisenbug
hexit
hing
hobbit
hungus
i14y
i18n
initgame
jupiter
kahuna
kgbvax
klone
kluge
kremvax
kyrka
laundromat
legalese
letterbomb
lexiphage
livelock
liveware
lossage
luser
macdink
machoflops
macrology
macrotape
maggotbox
mandelbug
marketroid
martian
meatware
meeces
meg
megapenny
meme
memetics
menuitis
meta
mickey
microLenat
minifloppies
moby
moria
mouso
mudhead
multician
mumblage
munchkin
nano
nanoacre
nanobot
nanocomputer
nanofortnight
nanotechnology
nastygram
neophilia
netburp
netdead
nethack
netiquette
netlag
netnews
netrock
newbie
newsfroup
newsgroup
nickle
noddy
nooze
notwork
nuke
nybble
nyetwork
offline
oif
ooblick
op
param
parm
payware
pdl
perf
phreaking
playte
plingnet
plokta
plonk
plugh
pnambic
prestidigitization
prettyprint
proglet
psychedelicware
psyton
ques
quux
qux
ravs
regexp
retcon
retrocomputing
rot13
sagan
salescritter
salsman
sandbender
screwage
scrog
scrool
scrozzle
segfault
seggie
segv
shareware
shelfware
shitogram
showstopper
sitename
skrog
slopsucker
smiley
smurf
snarf
sneakernet
snivitz
softcopy
softwarily
softy
spam
spl
spooge
stiffy
stubroutine
studlycaps
sysadmin
sysop
tayste
terminak
terpri
thinko
thunk
tinycrud
toeprint
toto
trit
tty
tunafish
turist
twink
twonkie
upload
upthread
vadding
vannevar
vaporware
var
vaxherd
vaxism
vaxocentrism
vdiff
veeblefester
verbage
vgrep
videotex
wabbit
waldo
wango
wank
wannabee
wedgie
wedgitude
weeble
weenie
wetware
whalesong
whizzy
winkey
winnage
winnitude
wirehead
wonky
workaround
xor
xref
xyzzy
zen
zigamorph
zipperhead
zorch
zorkmid
# program specified
nice="" # user specified
rcvr="" # user specified
inputfile="/tmp/pw.$$" # program specified, also in pwc.c
verbose="" # user specified
cf_file="Scripts/network.conf" # program specified
bigdict="Dicts/bigdict" # program specified
lockdict="Dicts/.lockfile" # program specified
CRACK_HOME_UNRES="$CRACK_HOME"
if [ -f "/bin/csh" ] # -x bombs on Ultrix
then
CRACK_OUT=` /bin/csDictSrc/bad_pws.dat 100600 5661 132 14574 5222357131 10726 0 0 1 0 0
1
123456
12345678
2
3
4
5
6
7
8
9
A
a
aaa
abc
abcd
abcde
abcdef
abcdefg
abcdefgh
academia
academic
access
ada
admin
Adrian
Adrianna
aerobics
airplane
Alasdair
albany
albatross
Albert
Alex
Alexander
alf
algebra
alias
aliases
Alice
Alicia
Alisa
Alison
Alistair
Alister
Allison
alpha
alphabet
ama
amadeus
Amanda
Amber
amorphous
Amy
analog
anchor
Andrea
andromache
Anduin
andy
Angela
Angie
animal
animals
Anita
Ann
Anna
Anne
Annette
answer
anthropogenic
anvils
anything
April
aria
ariadne
Arlene
arrow
Arthur
asd
asdfgh
asm
asshole
Athena
atmosphere
aztecs
azure
B
b
bacchus
badass
Bailey
banana
bananas
bandit
banks
Barbara
barber
baritone
Bart
Bartman
basic
bass
bassoon
batch
batman
BBROYGBVGW
beach
beater
beauty
beaver
Becky
beethoven
beetledrive
beloved
benz
beowulf
berkeley
berlin
berliner
Beryl
beta
Beth
Betsie
Betty
Beverly
bicameral
Bishop
bitch
bizzy
Bob
Bongpoo
bradley
Brandi
Brandy
Brenda
brian
Bridget
broadway
bsd
buggerall
bumbling
burgess
buzby
C
c
cad
Calvin
Camille
campanile
Candi
Candy
cantor
cardinal
Caren
Carla
Carmen
carmen
Carol
Carole
Carolina
carolina
Caroline
Carrie
carson
cascades
castle
cat
Catherine
Cathy
cayuga
Cecily
celtics
cerulean
change
Charity
Charles
charles
charming
charon
chat
cheesecake
chem
chemistry
chess
chester
chocolate
Christina
Christine
Christy
cigar
Cindy
cinelli
class
classic
Claudia
cluster
clusters
code
coffee
coke
Collins
collins
commrades
computer
comrade
comrades
condo
condom
connect
Connie
console
cookie
cookie
cooper
Cornelius
cornelius
couscous
create
creation
creator
creosote
cretin
criminal
Cristina
Crystal
cshrc
Cynthia
D
d
daemon
Daisy
Dana
dancer
Daniel
daniel
Danielle
danny
dapper
data
dave
Dawn
Deb
Debbie
Deborah
december
default
defoe
deluge
Denise
Desiree
desperate
develop
device
dial
Diana
Diane
diet
dieter
digital
disc
discbox
discovery
disk
disney
dog
Doobrie
dos
drought
Dulce
Duncan
E
e
eager
earth
easier
easy
eatme
edges
edinburgh
edwin
Edwina
egghead
eiderdown
Eileen
Einstein
Elaine
Elanor
elephant
Elizabeth
Ellen
email
emerald
Emily
Emmanuel
enemy
engine
engineer
enterprise
enzyme
Erica
Erika
Erin
ersatz
establish
estate
eternity
euclid
eugene
Evelyn
extension
F
f
fairway
Felicia
fender
fermat
ferrari
fidelity
field
file
finite
fishers
flakes
float
flower
flowers
foolproof
football
foresight
format
forsythe
fourier
fred
friend
frighten
fun
function
fungible
G
g
Gabriel
gabriel
games
gardner
garfield
gatt
gauss
George
george
Gertrude
gertrude
gibson
Gilly
Gina
Ginger
glacier
gnu
golf
golfer
gorgeous
gorges
gosling
gouge
graham
grahm
grass
group
gryphon
gucci
guess
guest
guitar
gumption
guntis
gweledigaeth
H
h
hack
hacker
hal
hamlet
handily
happening
harmony
harold
Harvey
hawaii
Heather
hebrides
Heidi
heinlein
hello
help
herbert
Hiawatha
hibernia
hidden
Hobbes
hobbit
Holly
homework
honey
horse
horus
hutchins
hydrogen
I
ibm
iluvben
imbroglio
imperial
include
ingres
ingress
Ingrid
inna
innocuous
internet
Irene
irishman
isis
izzy
J
j
Jackie
Jane
Janet
Janice
Janie
japan
Jasmin
Jean
Jeanne
Jen
Jenni
Jennifer
Jenny
Jessica
jester
Jill
jixian
Joanne
Jody
Johnny
johnny
Joseph
Joshua
Joy
Joyce
Judith
Judy
juggle
Julia
Julie
June
jupiter
K
k
kalajira
Karen
Karie
Karina
Kate
Kathleen
Kathrine
Kathy
Katina
Katrina
Kelly
Keri
kermit
kernel
Kerri
Kerrie
Kerry
key
Kim
Kimberly
kipper
kirkland
Kitten
knight
Krista
Kristen
Kristi
Kristie
Kristin
Kristine
Kristy
L
l
ladle
lager
lambda
lamination
Lana
Lara
larkin
larry
Laura
lazarus
Leah
lebesgue
lee
leland
leroy
Leslie
lewis
library
light
Linda
Lisa
lisp
Liz
llareggub
lock
lockout
Lois
Lori
Lorin
Lorraine
Louis
Louise
love
Lucy
Lynn
Lynne
M
m
mac
macintosh
mack
maggot
magic
mail
maint
Malcolm
malcom
manager
Mara
Marci
Marcy
Maria
Marietta
mark
markus
Marni
mars
marty
marvin
Mary
master
math
Maurice
maurice
Meagan
Megan
Melissa
mellon
memory
mercury
merlin
mets
mgr
Michael
michael
Michele
Michelle
Mickey
mike
minimum
minsky
mit
modem
mogul
moguls
Monica
moose
morley
Mortis
mortis
mouse
mozart
muser
mutant
MVEMJSUNP
N
n
nagel
Nancy
napoleon
nasa
nepenthe
neptune
ness
net
network
new
news
newton
next
Nicole
Nita
nobody
Noreen
noxious
nuclear
nutrition
nyquist
O
o
oceanography
ocelot
oerhrdle
office
olivetti
Olivia
olivia
open
operator
oracle
orca
orchid
orwell
osiris
outlaw
oxford
P
p
pacific
pad
painless
pakistan
Pam
Pamela
paper
papers
pass
password
Pat
Patricia
Patty
Paula
pencil
Penelope
penguin
penis
peoria
percolate
persimmon
persona
pete
peter
philip
phoenix
phone
Pierre
pierre
pizza
plane
playboy
plover
pluto
plymouth
Polly
polynomial
pondering
pork
porsche
poster
power
praise
precious
prelude
presto
prince
princeton
priv
private
privs
professor
profile
program
protect
protozoa
pub
public
pumpkin
puneet
puppet
Q
q
qwerty
qwertyui
R
r
rabbit
Rachel
Rachelle
rachmaninoff
rainbow
raindrop
raleigh
random
rascal
reagan
really
Rebecca
regional
remote
Renee
rick
ripple
risc
rje
Robin
robot
robotics
Robyn
Rochelle
rochester
rodent
rolex
romano
Ronald
ronald
Ronnie
root
Rose
rosebud
Rosemary
roses
ruben
rules
ruth
S
s
sal
Samantha
Sandra
Sandy
Sara
Sarah
saturn
saxon
scamper
scheme
school
scott
scotty
secret
security
sensor
serenity
service
sesame
sex
Shannon
sharc
shark
sharks
Sharon
sharon
sheffield
sheldon
shell
Sherri
Shirley
shit
shitforbrains
shiva
shivers
shuttle
signature
silverlake
simon
simple
simpsons
singer
single
sirte
smile
smiles
smooch
smother
Snarfel
snatch
snoopy
soap
socrates
somebody
Sondra
Sonia
Sonya
sossina
sparrows
spit
splatter
splodge
spring
springer
squires
Stacey
Staci
Stacie
Stacy
Steph
Stephanie
strangle
stratford
student
stuttgart
subway
success
sucker
summer
sun
super
superstage
superuser
support
supported
surfer
Susan
Susanne
Susie
Suzanne
Suzie
swearer
Sybil
symmetry
sys
sysadmin
system
T
t
Tamara
Tami
Tamie
Tammy
tangerine
tape
Tara
target
tarragon
taylor
teabag
tech
telephone
temptation
tennis
terminal
test
thailand
thanatos
Theresa
Tiffany
tiger
Tina
toggle
tomato
topography
tortoise
toxic
toyota
Traci
Tracie
Tracy
trails
transfer
Trisha
trivial
trombone
tty
tubas
tuttle
U
u
umesh
unhappy
unicorn
unix
unknown
uranus
urchin
Ursula
util
utility
uucp
V
v
Valerie
vasant
venus
Veronica
vertigo
Vicky
village
virgin
Virginia
visitor
vortex
W
w
wargames
Warren
warren
water
weenie
Wendi
Wendy
whatever
whatnot
whiting
Whitney
whitney
wholesale
will
William
william
williamsburg
Willie
willie
Wilma
winston
wisconsin
wizard
wizzy
WOBAFGKMRNS
wombat
woodwind
word
work
wormwood
wyoming
X
x
xerox
xfer
xmodem
xyz
Y
y
yaco
yang
yellowstone
Yolanda
yosemite
Z
z
zap
zerox
zimmerman
zmodem
zxcvbn
MS
VR
WIBNI
WOMBAT
WYSIAYG
WYSIWYG
Weenix
XOFF
XXX
YABA
YAUN
Zork
abbrev
adger
admin
annoybot
app
attoparsec
autobogotiphobia
avatarDicts/ 40755 5661 132 0 5222357021 6206 5 0 1 0 Docs/ 40755 5661 132 0 5222357210 6030 5 0 1 0 Docs/readme.ms 100600 5661 132 70506 5222357172 7752 0 0 1 0 .de C
ie n .B "\\$1" \\$2
el .CW "\\$1" \\$2
.
TL
"Crack Version 4.1"
br
A Sensible Password Checker for Unix
AU
Alec D.E. Muffett
AI
Unix Software Engineer
Aberystwyth, Wales, UK
I "(
[email protected] or
[email protected])"
AB
B Crack
is a freely available program designed to find standard Unix
eight-character DES encrypted passwords by standard guessing techniques
outlined below. It is written to be flexible, configurable and fast,
and to be able to make use of several networked hosts via the Berkeley
C rsh
program (or similar), where possible.
AE
NH 1
Statement of Intent
LP
This package is meant as a proving device to aid the construction of
secure computer systems. Users of Crack are advised that they may get
severly hassled by authoritarian type sysadmin dudes if they run Crack
without proper authorisation.
NH 1
Introduction to Version 4.0
LP
Crack is now into it's fourth version, and has been reworked extensively
to provide extra functionality, and the purpose of this release is to
consolidate as much of this new functionality into as small a package as
possible. To this end, Crack may appear to be less configurable: it has
been written on the assumption that you run a fairly modern Unix, one
with BSD functionality, and then patched in order to run on other
systems.
LP
This, surprisingly enough, has led to neater code, and has made possible
the introduction of greater flexibility which supercedes many of the
options that could be configured in earlier versions of Crack. In the
same vein, some of the older options are now mandatory. These, such as
I "feedback mode"
and
C CRACK_PRINTOUT
are no longer supported as options and probably never will be again.
There is just a lot of wastage in not running with them, and too many
dependencies in other functions to bother programming around them.
LP
The user interface is basically identical to the previous versions,
although some people have asked about providing X-windows GUI's to
Crack, I think it would be a waste of time to do so. Crack has far
less options than your ordinary version of
C /bin/ls .
NH 1
Introduction to Version 4.1
LP
Version 4.1 of the Crack program is an attempt to extend the features
introduced in v4.0 and provide hooks for external libraries such as
Michael Glad's wonderful
B UFC
crypt() implementation, which (on some platforms) can outperform my
fcrypt() by a factor of 3. I have also been burdened with the task of
making Crack's memory handling bombproof (hah!) in the vague hope that
it will survive running out of memory on small machines.\**
FS
- or even on large ones. Brian Tompsett at Hull tweaked Crack v3.3
until it could run to completion after filling the swapspace on each of a
network of SparcStation2's. Due to restructuring work on v4.0, I have
had to write my own sorting algorithm & re-implement all of his tweaks
from scratch, and can only hope that I have emulated the bombproofness
of this desirable (?) functionality.
FE
LP
The extensions that I mention above regard the addition of extra
primitives to the dictionary processing language which permit the
production of more concise dictionaries containing words, more of which
are likely to be passwords. The idea is to gain efficiency by removing
some of the dross from the generated dictionaries.
LP
Crack should (generally) be more disk-space efficient now that the
program can spot dictionaries which have been compressed using
I compress
or
I pack
and will uncompress them on the fly as necessary (using
I zcat
or
I pcat
respectively).\**
FS
Note to people who are short on memory or swap: do remember that to do
this Crack will have to
I fork()
(via
I popen() )
and might not be able to create the uncompressing process. Hence, if
you intend to swaplock your machine, don't compress the dictionaries.
Switch this off by editing the
C Crack
shellscript.
FE
NH 1
Crack Methodology - Part 1: Internals
LP
Crack takes as its input a series of password files and source
dictionaries. It merges the dictionaries, turns the password files into
a sorted list, and generates lists of possible passwords from the merged
dictionary or from information gleaned about users from the password
file.
It does
B not
attempt to remedy the problem of allowing users to have guessable
passwords, and it should
B NOT
be used in place of getting a really good, secure
C passwd
program replacement.\**
FS
See the end of ths document for more information about
I passwd
replacements.
FE
LP
The above paragraphs define the purpose of Crack, and embody a great
deal of hard work, screams of
I Eureka! ,
drunkeness, and a fair amount of swearing too. There is a lot
of thinking, philosophy, and empirical guesswork behind the way that
Crack attacks password files, and although it is not perfect, I
certainly hope that Crack will out-do most of it's competitors.
LP
Crack works by making many individual passes over the password entries
that you supply to it. Each pass generates password guesses based upon
a sequence of rules, supplied to the program by the
user. The rules are specified in a simplistic language in the files
C gecos.rules
and
C dicts.rules ,
to be found in the
C Scripts
directory.
The distinction between these two files will be made clear later.
LP
The rules are written as a simple string of characters, with one rule to
a line. Blank lines, and comment lines beginning with a hash character
B #
are ignored. Trailing whitespace is also ignored. The instructions in
the rule are followed from left to right, and are applied to the
dictionary words one by one, as the words are loaded. Some simple
pattern matching primitives are provided for selection purposes, so that
if the dictionary word does not match the pattern, it is ignored. This
saves on time and memory. Before carrying on, I suggest that you browse
through
C Scripts/dicts.rules ,
take a look at the rules supplied as defaults, and try to work out what
they do.
LP
The rules are stored in two different files for two different purposes.
Rules in
C Scripts/gecos.rules
are applied to data generated by Crack from the pw_gecos and pw_gecos
entries of the user's password entry. The data fed to the gecos rules
for the user
I "aem",
who is
I "Alec David Muffett, Systems"
would be:
I "aem",
I "Alec",
I "David",
I "Muffett",
I "Systems",
and a series of permutations of those words, either re-ordering the
words and joining them together (eg:
I "AlecMuffett" ),
or making up new words based on initial letters of one word taken with
the rest of another (eg:
I "AMuffett" ).\**
FS
- and
I ASystems
and
I DSystems ,
and
I MSystems ,
etc... because Crack does not differentiate. Hence, care should be
taken to check for redundancy when adding new rules, so as not to waste
time during the gecos pass.
FE
LP
The entire set of rules in gecos.rules is applied to each of these
words, which creates many more permutations and combinations, all of
which are tested. Hence testing the password gecos information under
Crack v4.0 and upwards takes somewhat longer than previously, but it is
far more thorough.
sp 1v
LP
After a pass has been made over the data based on gecos information,
Crack makes further passes over the password data using successive rules
from the
C Scripts/dicts.rules
by loading the whole of
C Dicts/bigdict
file into memory, with the rule being applied to each word from that
file. This generates a
I "resident dictionary" ,
which is sorted and uniqued so as to prevent wasting time on repetition.
After each pass is completed, the memory used by the resident dictionary
is freed up, and (hopefully) re-used when the next dictionary is loaded.
LP
The
C Dicts/bigdict
dictionary is created by Crack by merging, sorting, and uniq'ing the
source dictionaries, which are to be found in the directory
C DictSrc
and which may also be named in the Crack shellscript, via the
C $STDDICT
variable. (The default value of $STDDICT is
C /usr/dict/words ).
LP
The file
C DictSrc/bad_pws.dat
is a dictionary which is meant to provide many of those common but
non-dictionary passwords, such as
I 12345678
or
I qwerty .
LP
If you wish to provide a dictionary of your own, just copy it into the
C DictSrc
directory (use
C compress
on it if you wish to save space; Crack will unpack it whilst generating
the big dictionary) and then delete the contents of the
C Dicts
directory by running
C Scripts/spotless .
Your new dictionary will be merged in on the next run. For more
information on dictionary attacks, see the
I excellent
paper called "Foiling the Cracker: A Survey of, and Improvements to,
Password Security" by Daniel Klein, available from
I "ftp.sei.cmu.edu"
in
I "~/pub/dvk/passwd.*" .
Also, please read the
C APPENDIX
file supplied with this distribution.\**
FS
Extra dictionaries (those detailed in Dan Klein's paper) can be
obtained via anonymous FTP from
I ftp.uu.net
(137.39.1.9) as
I ~/pub/dictionaries.tar.Z ;
or check an
I Archie
database for other possible sources of dictionaries.
FE
LP
Having described the method of cracking, perhaps we should now
investigate the algorithm used to overlay the cracking mechanism.
NH 1
Crack Methodology - Part 2: Feedback Filters
LP
As is stated above, Crack permutes and loads dictionaries directly
into memory, sorts and uniques them, before attempting to use each of
the words as a guess for each users' password. If Crack correctly
guesses a password, it marks the user as
I done
and does not waste
further time on trying to break that users password.
LP
Once Crack has finished a dictionary pass, it sweeps the list of users
looking for the passwords it has cracked. It stores the cracked passwords
in both plaintext and encrypted forms in a
I "feedback file"
in the directory
C Runtime .
Feedback files have names of the form
C Runtime/F* .
LP
The purpose of this is so that, when Crack is next invoked, it may
recognise passwords that it has successfully cracked before, and filter
them from the input to the password cracker. This provides an
I instant
list of crackable users who have not changed their passwords since the
last time Crack was run. This list appears in a file with name
C out*
in the
C $CRACK_OUT
directory, or on
I stdout ,
if foreground mode is invoked (see
I Options ,
below).
LP
In a similar vein, when a Crack run terminates normally, it writes out
to the feedback file all encrypted passwords that it has
B NOT
succeeded in cracking. Crack will then ignore all of these passwords
next time you run it.
LP
Obviously, this is not desirable if you frequently change your
dictionaries or rules, and so there is a script provided,
C Scripts/mrgfbk
which sorts your feedback files, merges them into one, and optionally
removes all traces of 'uncrackable' passwords, so that your next Crack
run can have a go at passwords it has not succeeded in breaking before.
LP
C Mrgfbk
is invoked automatically if you run
C Scripts/spotless .
NH 1
Crack Methodology - Part 3: Execution and Networking
LP
Each time Crack is invoked, whether networked or not, it generates a
I diefile
with a name of the form
C Runtime/D*
(for network cracks, this file is generated by RCrack, and is of the form
C Runtime/DR*
which points to a
B real
diefile, named
C Runtime/RD*
- see below for details).
LP
These diefiles contain debugging information about the job, and are
generated so that all the jobs on the entire network can be called
quickly by invoking
C Scripts/plaster .
Diefiles delete themselves after they have been run.
LP
As you will read in the sections below, Crack has a
C "-network"
option: This is designed to be a simple method of automatically
spreading the load of password cracking out over several machines on a
network, preferably if they are connected by some form of networked
filestore.
LP
When
C "Crack -network"
is invoked, it filters its input in the ordinary way, and then splits
its load up amongst several machines which are specified in the file
C Scripts/network.conf .
LP
This file contains a series of hostnames, power ratings, flags, etc,
relevant to the running of Crack on each machine. Crack then calls
C Scripts/RCrack
to use the
C rsh
command (or similar) to invoke Crack on the other hosts. See the RCrack
script, and the example network.conf file for details.
NH 1
Installation
LP
Crack is one of those most unusual of beasties, a self-installing
program. Some people have complained about this apparent weirdness, but
it has grown up with Crack ever since the earliest network version, when
I could not be bothered to log into several different machines with
several different architectures, just in order to build the binaries.
Once the necessary configuration options have been set, the executables
are created via
C make
by running the Crack shellscript .
LP
Crack's configuration lies in two files, the
C Crack
shell script, which contains all the installation specific configuration
data, and the file
C Sources/conf.h ,
which contains configuration options specific to various binary platforms.
LP
In the Crack shellscript, you will have to edit the
C CRACK_HOME
variable to the correct value. This variable should be set to an
absolute path name (names relative to
I ~username
are OK, so long as you have some sort of
C csh )
through which the directory containing Crack may be accessed on
B ALL
the machines that Crack will be run on. There is a similar variable
C CRACK_OUT
which specifies where Crack should put its output files - by default,
this is the same as
C "$CRACK_HOME" .
LP
You will also have to edit the file
C Sources/conf.h
and work out which switches to enable. Each
C #define
has a small note explaining its purpose. Where I have been in doubt about
the portability of certain library functions, usually I have re-written
it, so you should be OK. Let me know of your problems, if you have any.
LP
If you will be using
C "Crack -network"
you will then have to generate a
C Scripts/network.conf
file. This contains a list of hostnames to
C rsh
to, what their
I "binary type"
is (useful when running a network Crack on several different
architectures), a guesstimate of their
I "relative power"
(take your slowest machine as unary, and measure all others relative to
it), and a list of per-host
I flags
to
B add
to those specified on the
C Crack
command line, when calling that host. There is an example of such a
file provided in the Scripts directory - take a look at it.
LP
If ever you wish to specify a more precise figure as to the relative
power of your machines, or you are simply at a loss, play with the
command
C "make tests"
in the source code directory. This can provide you with the number of
fcrypt()s that your machine can do per second, which is a number that
you can plug into your
C network.conf
as a measure of your machines' power (after rounding the value to an
integer).
NH 1
Usage
LP
Okay, so, let's assume that you have edited your
C Crack
script, and your
C Sources/conf.h
file, where do you go from here ?
LP
DS B
fi
C Crack
[\c
I options ]
[\c
I bindir ]
C /etc/passwd
[...other passwd files]
sp 1v
C "Crack -network"
[\c
I options ]
C /etc/passwd
[...other passwd files]
DE
LP
Where
B bindir
is the optional name of the directory where you want the binaries
installed. This is useful where you want to be able to run versions of
Crack on several different architectures. If
B bindir
does not exist, a warning will be issued, and the directory created.
QP
Note:
B bindir
defaults to the name
C generic
if not supplied.
QP
LP
B "Notes for Yellow Pages (NIS) Users:"
I have occasional queries about how to get Crack running from a YP
password file. There are several methods, but by far the simplest is to
generate a passwd format file by running:-
DS B
C "ypcat passwd > passwd.yp"
DE
and then running Crack on this file.
NH 1
Options
IP "\fB-f\fP"
Runs Crack in
I foreground
mode, ie: the password cracker is not backgrounded, and messages appear
on stdout and stderr as you would expect. This option is only really
useful for very small password files, or when you want to put a wrapper
script around Crack.
IP
Foreground mode is disabled if you try running
C "Crack -network -f"
on the command line, because of the insensibility of
C rsh ing
to several machines in turn, waiting for each one to finish before
calling the next. However, please read the section about
I "Network Cracking without NFS/RFS" ,
below.
IP "\fB-v\fP"
Sets verbose mode, whereby Crack will print every guess it is trying on
a per-user basis. This is a very quick way of flooding your filestore,
but useful if you think something is going wrong.
IP "\fB-m\fP"
Sends mail to any user whose password you crack by invoking
C Scripts/nastygram
with their username as an argument. The reason for using the script is
so that a degree of flexibility in the format of the mail message is
supplied; ie: you don't have to recompile code in order to change the
message.\**
FS
I'm uncertain about the wisdom of mailing someone like this. If someone
browses your cracked user's mail somehow, it's like a great big neon
sign pointing at the user saying "This Is A Crackable Account - Go For
It!". Not to mention the false sense of security it engenders in the
System Manager that he's "informed" the user to change his password.
What if the user doesn't log on for 3 months? However, so many people
have wired it into their own versions of Crack, I suppose it
B must
be provided... AEM
FE
IP "\fB-nvalue\fP"
Sets the process to be
C nice() ed
to
I value ,
so, for example, the switch
C \&-n19
sets the Crack process to run at the lowest priority.
IP "\fB-network\fP"
Throws Crack into network mode, in which it reads the
C Scripts/network.conf
file, splits its input into chunks which are sized according to the
power of the target machine, and calls
C rsh
to run Crack on that machine. Options for Crack running on the target
machine may be supplied on the command line (eg: verbose or recover
mode), or in the network.conf file if they pertain to specific hosts
(eg:
C nice()
values).
IP "\fB-r<pointfile>\fP"
This is only for use when running in
I recover
mode. When a running Crack starts pass 2, it periodically saves its
state in a
I pointfile ,
with a name of the form
C "Runtime/P.*"
This file can be used to recover where you were should a host crash.
Simply invoke Crack in
B exactly
the same manner as the last time, with the addition of the
C "-r"
switch, (eg:
C "-rRuntime/Pfred12345" )
switch. Crack will startup and read the file, and jump to roughly where
it left off. If you are cracking a very large password file, this can
save oodles of time after a crash.
IP
If you were running a
I network
Crack, then the jobs will again be spawned onto all the machines of the
original Crack. The program will then check that the host it is running
on is the same as is mentioned in the pointfile. If it is not, it will
quietly die. Thus, assuming that you supply the same input data and do
not change your
C network.conf
file, Crack should pick up where it left off. This is a bit inelegant,
but it's better than nothing at the moment.
IP
The method of error recovery outlined above causes headaches for users
who want to do multiprocessing on parallel architectures. Crack is in
no way parallel, and because of the way it's structured (reading stdin
from shellscript frontends) it is a pain to divide the work amongst
several processes via
C fork() ing.
IP
The hack solution to get several copies of Crack running on one machine
with
I n
processors at the moment is to insert
I n
copies of the entry for your parallel machine into the
C Scripts/network.conf
file. If you use the
C \&-r
option in these circumstances however, you will get
I n
copies of the recovered process running, only one of them will have the
correct input data.
IP
The old solution to this problem (see old documentation if you are
interested) has been negated by the introduction of feedback mode, so
the best bet in this particular situation is to wait until the other
jobs are done (and have written out lists of uncrackable passwords), and
then re-start the jobs from scratch. Anyone whose password was not
cracked on the first run will be ignored on the second, if they have not
changed it since. This is inelegant, but it's the best I can do in the
limited time available.
NH
Support Scripts
LP
The
C Scripts
directory contains a small number of support and utility scripts, some
of which are designed to help Crack users check their progress.
Briefly, the most useful ones are:-
IP "\fBScripts/shadmrg\fP"
This is a small (but hopefully readable) script for merging
C /etc/passwd
and
C /etc/shadow
on System V style shadow password systems. It produces the merged data
to stdout, and will need redirecting into a file before Crack can work
on it. The script is meant to be fairly lucid, on the grounds that I
worry that there are many shadowing schemes out there, and perhaps not
all have the same data format.
IP
B "I have not"
wired this facility into the Crack command itself because the world does
B NOT
revolve around System V yet, regardless of what some people would have
me believe, and I believe that the lack of direct support for NIS
outlined above, sets a precedent. There are just too many
incompatibilities in shadow password schemes for me to hardwire
anything.
IP "\fBScripts/plaster\fP"
which is named after a dumb joke, but is a simple frontend to the
C "Runtime/D*"
diefiles that each copy of the password cracker generates. Invoking
C Scripts/plaster
will kill off all copies of the password cracker you are running, over
the network or otherwise.
IP "\fBScripts/status\fP"
This script
C rsh es
to each machine mentioned in the
C Scripts/network.conf
file, and provides some information about processes and uptime on that
machine. This is useful when you want to find out just how well your
password crackers are getting on during a
C "Crack -network" .
IP "\fBScripts/{clean,spotless}\fP"
These are really just frontends to a makefile. Invoking
C Scripts/clean
tidies up the Crack home directory, and removes probably unwanted files,
but leaves the pre-processed dictionary
C bigdict
intact.
C Scripts/spotless
does the same as
C Scripts/clean
but obliterates
C bigdict
and old output files too, and compresses the feedback files into one.
IP "\fBScripts/nastygram\fP"
This is the shellscript that is invoked by the password cracker to send
mail to users who have guessable passwords, if the
C -m
option is used. Edit it at your leisure to suit your system.
IP "\fBScripts/guess2fbk\fP"
This script takes your
C out*
files as arguments and reformats the 'Guessed' lines into a slightly
messy
I feedback
file, suitable for storing with the others.
IP
An occasion where this might be useful is when your cracker has guessed
many peoples passwords, and then died for some reason (a crash?) before
writing out the guesses to a feedback file. Running
DS B
C "Scripts/guess2fbk out* >> Runtime/F.new"
DE
will save the work that has been done.
NH 1
Network Cracking without NFS/RFS
LP
For those users who have some form of
C rsh
command, but do not have a a networked filestore running between hosts,
there is now a solution which will allow you to do networked cracking,
proposed to me by Brian Tompsett at Hull. Personally, I consider the
idea to be potty, but it fills in missing functionality in a wonderfully
tacky manner.
LP
From the documentation above, you will note that Crack will undo the
C "-f"
I "(output in foreground)"
option, if it is invoked with the
C "-network"
switch at the same time (see the
I Options
section above). This is true, but it does not apply if you specify
C "-f"
option in the
C network.conf
file.
LP
The practical upshot of doing this is that remote copies of Crack
can be made to read from
I stdin
and write to
I stdout
over a network link, and thus remote processing is accomplished. I have
tweaked Crack in such a way, therefore, that if the
C "-f"
option is specified amongst the crack-flags of a host in the
network.conf, rather than backgrounding itself on the remote host, the
C rsh
command on the
B server
is backgrounded, and output is written directly to the files on the
server's filestore.
LP
There are restrictions upon this method, mostly involving the number of
processes that a user may run on the server at any one time, and that
you will have to collect feedback output together manually (dropping it
into the
C Runtime
directory on the server). However, it works. Also, if you try to use
C rsh
as another user, you will suffer problems if
C rsh
insists on reading something from your terminal (eg: a password for the
remote account). Also, recovering using checkpointing goes out the
window unless you specify the name of the pointfile as it is named
on the remote machine.
NH 1
UFC Support and notes on fast crypt() implementations
LP
The stdlib version of the
C crypt()
subroutine is incredibly slow. It is a
I massive
bottleneck to the execution of Crack and on typical platforms that you
get at universities, it is rare to find a machine which will achieve
more than 50 standard crypt() s per second. On low-end diskless
workstations, you may expect 2 or 3 per second. It was this slowness of
the crypt() algorithm which originally supplied much of the security
Unix needed.\**
FS
See: "Password Security, A Case History" by Bob Morris & Ken Thomson, in
the Unix Programmer Docs.
FE
LP
There are now
B many
implementations of faster versions of crypt()
to be found on the network. The one supplied with Crack v3.2 and
upwards is called
C fcrypt() .
It was originally written in May 1986 by Robert Baldwin at MIT, and is a
good version of the crypt() subroutine. I received a copy from Icarus
Sparry at Bath University, who had made a couple of portability
enhancements to the code.
LP
I rewrote most of the tables and the KeySchedule generating algorithm in
the original
I fdes-init.c
to knock 40% off the execution overhead of fcrypt() in the form that it
was shipped to me. I inlined a bunch of stuff, put it into a single
file, got some advice from Matt Bishop and Bob Baldwin [both of whom I
am greatly indebted to] about what to do to the
C xform()
routine and to the fcrypt function itself, and tidied up some
algorithms. I have also added more lookup tables and reduced several
formula for faster use. Fcrypt() is now barely recognisable as being
based on its former incarnation, and it is 3x faster.
LP
On a DecStation 5000/200, fcrypt() is about 16 times faster than the
standard crypt (your mileage may vary with other architectures and
compilers). This speed puts fcrypt() into the "moderately fast" league
of crypt implementations.
LP
Amongst other crypt implementations available is
B UFC
by Michael Glad. UFC-crypt is a version of the crypt subroutine which
is optimised for machines with 32-bit long integers and generally
outperforms my fcrypt() by a factor of between 1 and 3, for a tradeoff
of large memory usage, and memory-cache unfriendliness. Hooks for even
more optimised assembler versions of crypt() are also provided for some
platforms (Sun, HP, ...). Getting UFC to work on 16 bit architectures
is nearly impossible.
LP
However, on most architectures, UFC generates a stunning increase in the
power of Crack, and so, from v4.1 onwards, Crack is written to
automatically make use of UFC if it can find it. All that you have to
do is to obtain a suitable copy of UFC (preferably a version which
mentions that it is compatible with
C "Crack v4.1" ,
and unpack it into a directory called
C ufc-crypt
in
C $CRACK_HOME ,
and then delete your old binaries. UFC will then be detected, compiled,
tested and used in preference to fcrypt() by the Crack program, wherever
possible.
NH 1
Conclusions
LP
What can be done about brute force attacks on your password file ?
LP
You must get a drop-in replacement for the
C passwd
and
C yppasswd
commands; one which will stop people from choosing bad passwords in the
first place. There are several programs to do this; Matt Bishop's
C "passwd+"
and Clyde Hoover's
C "npasswd"
program are good examples which are freely available. Consult an
B Archie
database for more details on where you can get them from.
LP
It would be nice if an organisation (such as
B CERT ?)
could be persuaded to supply skeletons of
I sensible
passwd commands for the public good, as well as an archive of security
related utilities\**
on top of the excellent
C COPS .
FS
C COPS
is available for anonymous FTP from
I "cert.sei.cmu.edu"
(128.237.253.5) in
I ~/cops
FE
However, for Unix security to improve on a global scale, we will also
require pressure on the vendors, so that programs are written correctly
from the beginning.
password file, this can
save oodles of time after a crash.
IP
If you were running a
I network
Crack, then the jobs will again be spawned onto all the machines of the
original Crack. Docs/readme.txt 100600 5661 132 74416 5222357212 10151 0 0 1 0
"Crack Version 4.1"
A Sensible Password Checker for Unix
Alec D.E. Muffett
Unix Software Engineer
Aberystwyth, Wales, UK
(
[email protected] or
[email protected])
ABSTRACT
Crack is a freely available program designed
to find standard Unix eight-character DES
encrypted passwords by standard guessing tech-
niques outlined below. It is written to be flexi-
ble, configurable and fast, and to be able to make
use of several networked hosts via the Berkeley
rsh program (or similar), where possible.
1. Statement of Intent
This package is meant as a proving device to aid the con-
struction of secure computer systems. Users of Crack are
advised that they may get severly hassled by authoritarian
type sysadmin dudes if they run Crack without proper author-
isation.
2. Introduction to Version 4.0
Crack is now into it's fourth version, and has been reworked
extensively to provide extra functionality, and the purpose
of this release is to consolidate as much of this new func-
tionality into as small a package as possible. To this end,
Crack may appear to be less configurable: it has been writ-
ten on the assumption that you run a fairly modern Unix, one
with BSD functionality, and then patched in order to run on
other systems.
This, surprisingly enough, has led to neater code, and has
made possible the introduction of greater flexibility which
supercedes many of the options that could be configured in
earlier versions of Crack. In the same vein, some of the
older options are now mandatory. These, such as feedback
mode and CRACK_PRINTOUT are no longer supported as options
and probably never will be again. There is just a lot of
wastage in not running with them, and too many dependencies
in other functions to bother programming around them.
March 3, 1992
- 2 -
The user interface is basically identical to the previous
versions, although some people have asked about providing
X-windows GUI's to Crack, I think it would be a waste of
time to do so. Crack has far less options than your ordinary
version of /bin/ls.
3. Introduction to Version 4.1
Version 4.1 of the Crack program is an attempt to extend the
features introduced in v4.0 and provide hooks for external
libraries such as Michael Glad's wonderful UFC crypt()
implementation, which (on some platforms) can outperform my
fcrypt() by a factor of 3. I have also been burdened with
the task of making Crack's memory handling bombproof (hah!)
in the vague hope that it will survive running out of memory
on small machines.[1]
The extensions that I mention above regard the addition of
extra primitives to the dictionary processing language which
permit the production of more concise dictionaries contain-
ing words, more of which are likely to be passwords. The
idea is to gain efficiency by removing some of the dross
from the generated dictionaries.
Crack should (generally) be more disk-space efficient now
that the program can spot dictionaries which have been
compressed using compress or pack and will uncompress them
on the fly as necessary (using zcat or pcat respec-
tively).[2]
4. Crack Methodology - Part 1: Internals
Crack takes as its input a series of password files and
source dictionaries. It merges the dictionaries, turns the
password files into a sorted list, and generates lists of
possible passwords from the merged dictionary or from infor-
mation gleaned about users from the password file. It does
_________________________
[1] - or even on large ones. Brian Tompsett at Hull
tweaked Crack v3.3 until it could run to completion
after filling the swapspace on each of a network of
SparcStation2's. Due to restructuring work on v4.0, I
have had to write my own sorting algorithm & re-
implement all of his tweaks from scratch, and can only
hope that I have emulated the bombproofness of this
desirable (?) functionality.
[2] Note to people who are short on memory or swap:
do remember that to do this Crack will have to fork()
(via popen()) and might not be able to create the un-
compressing process. Hence, if you intend to swaplock
your machine, don't compress the dictionaries. Switch
this off by editing the Crack shellscript.
March 3, 1992
- 3 -
not attempt to remedy the problem of allowing users to have
guessable passwords, and it should NOT be used in place of
getting a really good, secure passwd program replacement.[3]
The above paragraphs define the purpose of Crack, and embody
a great deal of hard work, screams of Eureka!, drunkeness,
and a fair amount of swearing too. There is a lot of think-
ing, philosophy, and empirical guesswork behind the way that
Crack attacks password files, and although it is not per-
fect, I certainly hope that Crack will out-do most of it's
competitors.
Crack works by making many individual passes over the pass-
word entries that you supply to it. Each pass generates
password guesses based upon a sequence of rules, supplied to
the program by the user. The rules are specified in a
simplistic language in the files gecos.rules and
dicts.rules, to be found in the Scripts directory. The dis-
tinction between these two files will be made clear later.
The rules are written as a simple string of characters, with
one rule to a line. Blank lines, and comment lines begin-
ning with a hash character # are ignored. Trailing whi-
tespace is also ignored. The instructions in the rule are
followed from left to right, and are applied to the diction-
ary words one by one, as the words are loaded. Some simple
pattern matching primitives are provided for selection pur-
poses, so that if the dictionary word does not match the
pattern, it is ignored. This saves on time and memory.
Before carrying on, I suggest that you browse through
Scripts/dicts.rules, take a look at the rules supplied as
defaults, and try to work out what they do.
The rules are stored in two different files for two dif-
ferent purposes. Rules in Scripts/gecos.rules are applied
to data generated by Crack from the pw_gecos and pw_gecos
entries of the user's password entry. The data fed to the
gecos rules for the user aem, who is Alec David Muffett,
Systems would be: aem, Alec, David, Muffett, Systems, and a
series of permutations of those words, either re-ordering
the words and joining them together (eg: AlecMuffett), or
making up new words based on initial letters of one word
taken with the rest of another (eg: AMuffett).[4]
The entire set of rules in gecos.rules is applied to each of
_________________________
[3] See the end of ths document for more information
about passwd replacements.
[4] - and ASystems and DSystems, and MSystems, etc...
because Crack does not differentiate. Hence, care
should be taken to check for redundancy when adding new
rules, so as not to waste time during the gecos pass.
March 3, 1992
- 4 -
these words, which creates many more permutations and combi-
nations, all of which are tested. Hence testing the pass-
word gecos information under Crack v4.0 and upwards takes
somewhat longer than previously, but it is far more
thorough.
After a pass has been made over the data based on gecos
information, Crack makes further passes over the password
data using successive rules from the Scripts/dicts.rules by
loading the whole of Dicts/bigdict file into memory, with
the rule being applied to each word from that file. This
generates a resident dictionary, which is sorted and uniqued
so as to prevent wasting time on repetition. After each pass
is completed, the memory used by the resident dictionary is
freed up, and (hopefully) re-used when the next dictionary
is loaded.
The Dicts/bigdict dictionary is created by Crack by merging,
sorting, and uniq'ing the source dictionaries, which are to
be found in the directory DictSrc and which may also be
named in the Crack shellscript, via the $STDDICT variable.
(The default value of $STDDICT is /usr/dict/words).
The file DictSrc/bad_pws.dat is a dictionary which is meant
to provide many of those common but non-dictionary pass-
words, such as 12345678 or qwerty.
If you wish to provide a dictionary of your own, just copy
it into the DictSrc directory (use compress on it if you
wish to save space; Crack will unpack it whilst generating
the big dictionary) and then delete the contents of the
Dicts directory by running Scripts/spotless. Your new dic-
tionary will be merged in on the next run. For more informa-
tion on dictionary attacks, see the excellent paper called
"Foiling the Cracker: A Survey of, and Improvements to,
Password Security" by Daniel Klein, available from
ftp.sei.cmu.edu in ~/pub/dvk/passwd.*. Also, please read
the APPENDIX file supplied with this distribution.[5]
Having described the method of cracking, perhaps we should
now investigate the algorithm used to overlay the cracking
mechanism.
_________________________
[5] Extra dictionaries (those detailed in Dan Klein's
paper) can be obtained via anonymous FTP from
ftp.uu.net (137.39.1.9) as ~/pub/dictionaries.tar.Z; or
check an Archie database for other possible sources of
dictionaries.
March 3, 1992
- 5 -
5. Crack Methodology - Part 2: Feedback Filters
As is stated above, Crack permutes and loads dictionaries
directly into memory, sorts and uniques them, before
attempting to use each of the words as a guess for each
users' password. If Crack correctly guesses a password, it
marks the user as done and does not waste further time on
trying to break that users password.
Once Crack has finished a dictionary pass, it sweeps the
list of users looking for the passwords it has cracked. It
stores the cracked passwords in both plaintext and encrypted
forms in a feedback file in the directory Runtime. Feedback
files have names of the form Runtime/F*.
The purpose of this is so that, when Crack is next invoked,
it may recognise passwords that it has successfully cracked
before, and filter them from the input to the password
cracker. This provides an instant list of crackable users
who have not changed their passwords since the last time
Crack was run. This list appears in a file with name out* in
the $CRACK_OUT directory, or on stdout, if foreground mode
is invoked (see Options, below).
In a similar vein, when a Crack run terminates normally, it
writes out to the feedback file all encrypted passwords that
it has NOT succeeded in cracking. Crack will then ignore
all of these passwords next time you run it.
Obviously, this is not desirable if you frequently change
your dictionaries or rules, and so there is a script pro-
vided, Scripts/mrgfbk which sorts your feedback files,
merges them into one, and optionally removes all traces of
'uncrackable' passwords, so that your next Crack run can
have a go at passwords it has not succeeded in breaking
before.
Mrgfbk is invoked automatically if you run Scripts/spotless.
6. Crack Methodology - Part 3: Execution and Networking
Each time Crack is invoked, whether networked or not, it
generates a diefile with a name of the form Runtime/D* (for
network cracks, this file is generated by RCrack, and is of
the form Runtime/DR* which points to a real diefile, named
Runtime/RD* - see below for details).
These diefiles contain debugging information about the job,
and are generated so that all the jobs on the entire network
can be called quickly by invoking Scripts/plaster. Diefiles
delete themselves after they have been run.
As you will read in the sections below, Crack has a -network
option: This is designed to be a simple method of
March 3, 1992
- 6 -
automatically spreading the load of password cracking out
over several machines on a network, preferably if they are
connected by some form of networked filestore.
When Crack -network is invoked, it filters its input in the
ordinary way, and then splits its load up amongst several
machines which are specified in the file
Scripts/network.conf.
This file contains a series of hostnames, power ratings,
flags, etc, relevant to the running of Crack on each
machine. Crack then calls Scripts/RCrack to use the rsh
command (or similar) to invoke Crack on the other hosts.
See the RCrack script, and the example network.conf file for
details.
7. Installation
Crack is one of those most unusual of beasties, a self-
installing program. Some people have complained about this
apparent weirdness, but it has grown up with Crack ever
since the earliest network version, when I could not be
bothered to log into several different machines with several
different architectures, just in order to build the
binaries. Once the necessary configuration options have been
set, the executables are created via make by running the
Crack shellscript .
Crack's configuration lies in two files, the Crack shell
script, which contains all the installation specific confi-
guration data, and the file Sources/conf.h, which contains
configuration options specific to various binary platforms.
In the Crack shellscript, you will have to edit the
CRACK_HOME variable to the correct value. This variable
should be set to an absolute path name (names relative to
~username are OK, so long as you have some sort of csh)
through which the directory containing Crack may be accessed
on ALL the machines that Crack will be run on. There is a
similar variable CRACK_OUT which specifies where Crack
should put its output files - by default, this is the same
as $CRACK_HOME.
You will also have to edit the file Sources/conf.h and work
out which switches to enable. Each #define has a small note
explaining its purpose. Where I have been in doubt about
the portability of certain library functions, usually I have
re-written it, so you should be OK. Let me know of your
problems, if you have any.
If you will be using Crack -network you will then have to
generate a Scripts/network.conf file. This contains a list
of hostnames to rsh to, what their binary type is (useful
when running a network Crack on several different
March 3, 1992
- 7 -
architectures), a guesstimate of their relative power (take
your slowest machine as unary, and measure all others rela-
tive to it), and a list of per-host flags to add to those
specified on the Crack command line, when calling that host.
There is an example of such a file provided in the Scripts
directory - take a look at it.
If ever you wish to specify a more precise figure as to the
relative power of your machines, or you are simply at a
loss, play with the command make tests in the source code
directory. This can provide you with the number of
fcrypt()s that your machine can do per second, which is a
number that you can plug into your network.conf as a measure
of your machines' power (after rounding the value to an
integer).
8. Usage
Okay, so, let's assume that you have edited your Crack
script, and your Sources/conf.h file, where do you go from
here ?
Crack [options] [bindir] /etc/passwd [...other passwd files]
Crack -network [options] /etc/passwd [...other passwd files]
Where bindir is the optional name of the directory where you
want the binaries installed. This is useful where you want
to be able to run versions of Crack on several different
architectures. If bindir does not exist, a warning will be
issued, and the directory created.
Note: bindir defaults to the name generic if not
supplied.
Notes for Yellow Pages (NIS) Users: I have occasional
queries about how to get Crack running from a YP password
file. There are several methods, but by far the simplest is
to generate a passwd format file by running:-
ypcat passwd > passwd.yp
and then running Crack on this file.
9. Options
-f Runs Crack in foreground mode, ie: the password cracker
is not backgrounded, and messages appear on stdout and
stderr as you would expect. This option is only really
useful for very small password files, or when you want
to put a wrapper script around Crack.
March 3, 1992
- 8 -
Foreground mode is disabled if you try running Crack
-network -f on the command line, because of the insen-
sibility of rshing to several machines in turn, waiting
for each one to finish before calling the next. How-
ever, please read the section about Network Cracking
without NFS/RFS, below.
-v Sets verbose mode, whereby Crack will print every guess
it is trying on a per-user basis. This is a very quick
way of flooding your filestore, but useful if you think
something is going wrong.
-m Sends mail to any user whose password you crack by
invoking Scripts/nastygram with their username as an
argument. The reason for using the script is so that a
degree of flexibility in the format of the mail message
is supplied; ie: you don't have to recompile code in
order to change the message.[6]
-nvalue
Sets the process to be nice()ed to value, so, for exam-
ple, the switch -n19 sets the Crack process to run at
the lowest priority.
-network
Throws Crack into network mode, in which it reads the
Scripts/network.conf file, splits its input into chunks
which are sized according to the power of the target
machine, and calls rsh to run Crack on that machine.
Options for Crack running on the target machine may be
supplied on the command line (eg: verbose or recover
mode), or in the network.conf file if they pertain to
specific hosts (eg: nice() values).
-r<pointfile>
This is only for use when running in recover mode.
When a running Crack starts pass 2, it periodically
saves its state in a pointfile, with a name of the form
Runtime/P.* This file can be used to recover where you
were should a host crash. Simply invoke Crack in
exactly the same manner as the last time, with the
addition of the -r switch, (eg: -rRuntime/Pfred12345)
_________________________
[6] I'm uncertain about the wisdom of mailing someone
like this. If someone browses your cracked user's mail
somehow, it's like a great big neon sign pointing at
the user saying "This Is A Crackable Account - Go For
It!". Not to mention the false sense of security it
engenders in the System Manager that he's "informed"
the user to change his password. What if the user
doesn't log on for 3 months? However, so many people
have wired it into their own versions of Crack, I sup-
pose it must be provided... AEM
<1b>9
March 3, 1992
- 9 -
switch. Crack will startup and read the file, and jump
to roughly where it left off. If you are cracking a
very large password file, this can save oodles of time
after a crash.
If you were running a network Crack, then the jobs will
again be spawned onto all the machines of the original
Crack. The program will then check that the host it is
running on is the same as is mentioned in the
pointfile. If it is not, it will quietly die. Thus,
assuming that you supply the same input data and do not
change your network.conf file, Crack should pick up
where it left off. This is a bit inelegant, but it's
better than nothing at the moment.
The method of error recovery outlined above causes
headaches for users who want to do multiprocessing on
parallel architectures. Crack is in no way parallel,
and because of the way it's structured (reading stdin
from shellscript frontends) it is a pain to divide the
work amongst several processes via fork()ing.
The hack solution to get several copies of Crack run-
ning on one machine with n processors at the moment is
to insert n copies of the entry for your parallel
machine into the Scripts/network.conf file. If you use
the -r option in these circumstances however, you will
get n copies of the recovered process running, only one
of them will have the correct input data.
The old solution to this problem (see old documentation
if you are interested) has been negated by the intro-
duction of feedback mode, so the best bet in this par-
ticular situation is to wait until the other jobs are
done (and have written out lists of uncrackable pass-
words), and then re-start the jobs from scratch. Any-
one whose password was not cracked on the first run
will be ignored on the second, if they have not changed
it since. This is inelegant, but it's the best I can
do in the limited time available.
10. Support Scripts
The Scripts directory contains a small number of support and
utility scripts, some of which are designed to help Crack
users check their progress. Briefly, the most useful ones
are:-
Scripts/shadmrg
This is a small (but hopefully readable) script for
merging /etc/passwd and /etc/shadow on System V style
shadow password systems. It produces the merged data
to stdout, and will need redirecting into a file before
Crack can work on it. The script is meant to be fairly
March 3, 1992
- 10 -
lucid, on the grounds that I worry that there are many
shadowing schemes out there, and perhaps not all have
the same data format.
I have not wired this facility into the Crack command
itself because the world does NOT revolve around System
V yet, regardless of what some people would have me
believe, and I believe that the lack of direct support
for NIS outlined above, sets a precedent. There are
just too many incompatibilities in shadow password
schemes for me to hardwire anything.
Scripts/plaster
which is named after a dumb joke, but is a simple fron-
tend to the Runtime/D* diefiles that each copy of the
password cracker generates. Invoking Scripts/plaster
will kill off all copies of the password cracker you
are running, over the network or otherwise.
Scripts/status
This script rshes to each machine mentioned in the
Scripts/network.conf file, and provides some informa-
tion about processes and uptime on that machine. This
is useful when you want to find out just how well your
password crackers are getting on during a Crack -net-
work.
Scripts/{clean,spotless}
These are really just frontends to a makefile. Invoking
Scripts/clean tidies up the Crack home directory, and
removes probably unwanted files, but leaves the pre-
processed dictionary bigdict intact. Scripts/spotless
does the same as Scripts/clean but obliterates bigdict
and old output files too, and compresses the feedback
files into one.
Scripts/nastygram
This is the shellscript that is invoked by the password
cracker to send mail to users who have guessable pass-
words, if the -m option is used. Edit it at your lei-
sure to suit your system.
Scripts/guess2fbk
This script takes your out* files as arguments and
reformats the 'Guessed' lines into a slightly messy
feedback file, suitable for storing with the others.
An occasion where this might be useful is when your
cracker has guessed many peoples passwords, and then
died for some reason (a crash?) before writing out the
guesses to a feedback file. Running
Scripts/guess2fbk out* >> Runtime/F.new
March 3, 1992
- 11 -
will save the work that has been done.
11. Network Cracking without NFS/RFS
For those users who have some form of rsh command, but do
not have a a networked filestore running between hosts,
there is now a solution which will allow you to do networked
cracking, proposed to me by Brian Tompsett at Hull. Person-
ally, I consider the idea to be potty, but it fills in miss-
ing functionality in a wonderfully tacky manner.
From the documentation above, you will note that Crack will
undo the -f (output in foreground) option, if it is invoked
with the -network switch at the same time (see the Options
section above). This is true, but it does not apply if you
specify -f option in the network.conf file.
The practical upshot of doing this is that remote copies of
Crack can be made to read from stdin and write to stdout
over a network link, and thus remote processing is accom-
plished. I have tweaked Crack in such a way, therefore,
that if the -f option is specified amongst the crack-flags
of a host in the network.conf, rather than backgrounding
itself on the remote host, the rsh command on the server is
backgrounded, and output is written directly to the files on
the server's filestore.
There are restrictions upon this method, mostly involving
the number of processes that a user may run on the server at
any one time, and that you will have to collect feedback
output together manually (dropping it into the Runtime
directory on the server). However, it works. Also, if you
try to use rsh as another user, you will suffer problems if
rsh insists on reading something from your terminal (eg: a
password for the remote account). Also, recovering using
checkpointing goes out the window unless you specify the
name of the pointfile as it is named on the remote machine.
12. UFC Support and notes on fast crypt() implementations
The stdlib version of the crypt() subroutine is incredibly
slow. It is a massive bottleneck to the execution of Crack
and on typical platforms that you get at universities, it is
rare to find a machine which will achieve more than 50 stan-
dard crypt() s per second. On low-end diskless worksta-
tions, you may expect 2 or 3 per second. It was this slow-
ness of the crypt() algorithm which originally supplied much
of the security Unix needed.[7]
_________________________
[7] See: "Password Security, A Case History" by Bob
Morris & Ken Thomson, in the Unix Programmer Docs.
March 3, 1992
- 12 -
There are now many implementations of faster versions of
crypt() to be found on the network. The one supplied with
Crack v3.2 and upwards is called fcrypt(). It was origi-
nally written in May 1986 by Robert Baldwin at MIT, and is a
good version of the crypt() subroutine. I received a copy
from Icarus Sparry at Bath University, who had made a couple
of portability enhancements to the code.
I rewrote most of the tables and the KeySchedule generating
algorithm in the original fdes-init.c to knock 40% off the
execution overhead of fcrypt() in the form that it was
shipped to me. I inlined a bunch of stuff, put it into a
single file, got some advice from Matt Bishop and Bob
Baldwin [both of whom I am greatly indebted to] about what
to do to the xform() routine and to the fcrypt function
itself, and tidied up some algorithms. I have also added
more lookup tables and reduced several formula for faster
use. Fcrypt() is now barely recognisable as being based on
its former incarnation, and it is 3x faster.
On a DecStation 5000/200, fcrypt() is about 16 times faster
than the standard crypt (your mileage may vary with other
architectures and compilers). This speed puts fcrypt() into
the "moderately fast" league of crypt implementations.
Amongst other crypt implementations available is UFC by
Michael Glad. UFC-crypt is a version of the crypt subrou-
tine which is optimised for machines with 32-bit long
integers and generally outperforms my fcrypt() by a factor
of between 1 and 3, for a tradeoff of large memory usage,
and memory-cache unfriendliness. Hooks for even more optim-
ised assembler versions of crypt() are also provided for
some platforms (Sun, HP, ...). Getting UFC to work on 16
bit architectures is nearly impossible.
However, on most architectures, UFC generates a stunning
increase in the power of Crack, and so, from v4.1 onwards,
Crack is written to automatically make use of UFC if it can
find it. All that you have to do is to obtain a suitable
copy of UFC (preferably a version which mentions that it is
compatible with Crack v4.1, and unpack it into a directory
called ufc-crypt in $CRACK_HOME, and then delete your old
binaries. UFC will then be detected, compiled, tested and
used in preference to fcrypt() by the Crack program, wher-
ever possible.
13. Conclusions
What can be done about brute force attacks on your password
file ?
You must get a drop-in replacement for the passwd and
yppasswd commands; one which will stop people from choosing
bad passwords in the first place. There are several
March 3, 1992
- 13 -
programs to do this; Matt Bishop's passwd+ and Clyde
Hoover's npasswd program are good examples which are freely
available. Consult an Archie database for more details on
where you can get them from.
It would be nice if an organisation (such as CERT?) could be
persuaded to supply skeletons of sensible passwd commands
for the public good, as well as an archive of security
related utilities[8] on top of the excellent COPS. However,
for Unix security to improve on a global scale, we will also
require pressure on the vendors, so that programs are writ-
ten correctly from the beginning.
_________________________
[8] COPS is available for anonymous FTP from
cert.sei.cmu.edu (128.237.253.5) in ~/cops
March 3, 1992
divide the
work amongst several processes via fork()ing.
The hack solution to get several copies of Crack run-
ning on one machine with n processors at the moment is
to insert n copies of the entry for your paraLICENCE 100600 5661 132 11247 5222357133 6243 0 0 1 0 (*
This document is freely plagiarised from the 'Artistic Licence',
distributed as part of the Perl v4.0 kit by Larry Wall, which is
available from most major archive sites
*)
This documents purpose is to state the conditions under which this
Package (See definition below) viz: The "Crack" Password Cracker, which
is copyright Alec David Edward Muffett, may be copied, such that the
Copyright Holder maintains some semblance of artistic control over the
development of the package, while giving the users of the package the
right to use and distribute the Package in a more-or-less customary
fashion, plus the right to make reasonable modifications.
So there.
***************************************************************************
Definitions:
"Package" refers to the collection of files distributed by the Copyright
Holder, and derivatives of that collection of files created through
textual modification, or segments thereof.
"Standard Version" refers to such a Package if it has not been modified,
or has been modified in accordance with the wishes of the Copyright
Holder.
"Copyright Holder" is whoever is named in the copyright or copyrights
for the package.
"You" is you, if you're thinking about copying or distributing this
Package.
"Reasonable copying fee" is whatever you can justify on the basis of
media cost, duplication charges, time of people involved, and so on.
(You will not be required to justify it to the Copyright Holder, but
only to the computing community at large as a market that must bear the
fee.)
"Freely Available" means that no fee is charged for the item itself,
though there may be fees involved in handling the item. It also means
that recipients of the item may redistribute it under the same
conditions they received it.
1. You may make and give away verbatim copies of the source form of the
Standard Version of this Package without restriction, provided that you
duplicate all of the original copyright notices and associated
disclaimers.
2. You may apply bug fixes, portability fixes and other modifications
derived from the Public Domain or from the Copyright Holder. A Package
modified in such a way shall still be considered the Standard Version.
3. You may otherwise modify your copy of this Package in any way,
provided that you insert a prominent notice in each changed file stating
how and when AND WHY you changed that file, and provided that you do at
least ONE of the following:
a) place your modifications in the Public Domain or otherwise make them
Freely Available, such as by posting said modifications to Usenet or an
equivalent medium, or placing the modifications on a major archive site
such as uunet.uu.net, or by allowing the Copyright Holder to include
your modifications in the Standard Version of the Package.
b) use the modified Package only within your corporation or
organization.
c) rename any non-standard executables so the names do not conflict with
standard executables, which must also be provided, and provide separate
documentation for each non-standard executable that clearly documents
how it differs from the Standard Version.
d) make other distribution arrangements with the Copyright Holder.
4. You may distribute the programs of this Package in object code or
executable form, provided that you do at least ONE of the following:
a) distribute a Standard Version of the executables and library files,
together with instructions (in the manual page or equivalent) on where
to get the Standard Version.
b) accompany the distribution with the machine-readable source of the
Package with your modifications.
c) accompany any non-standard executables with their corresponding
Standard Version executables, giving the non-standard executables
non-standard names, and clearly documenting the differences in manual
pages (or equivalent), together with instructions on where to get the
Standard Version.
d) make other distribution arrangements with the Copyright Holder.
5. You may charge a reasonable copying fee for any distribution of this
Package. You may charge any fee you choose for support of this Package.
YOU MAY NOT CHARGE A FEE FOR THIS PACKAGE ITSELF. However, you may
distribute this Package in aggregate with other (possibly commercial)
programs as part of a larger (possibly commercial) software distribution
provided that YOU DO NOT ADVERTISE this package as a product of your
own.
6. The name of the Copyright Holder may not be used to endorse or
promote products derived from this software without specific prior
written permission.
7. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
The End
manually (dropping it into the Runtime
directory on the server). However, it works. Also, if you
try to use rsh as another user, you will suffer problems if
rsh insists on reading something from your terminal (eg: a
password for the remote account). Also, recovering using
checkpointing goes out the window unless you specify MANIFEST 100600 5661 132 4533 5222357023 6365 0 0 1 0 File Name Archive # Description
-----------------------------------------------------------
APPENDIX 2 miscellaneous information
BUGS 1 list of recent bugs and possible fixes
Crack 2 crack driver shellscript
DictSrc 1 directory
DictSrc/bad_pws.dat 2 example extra dictionary
DictSrc/jargon 1 jargon dictionary contributed by ESR
Dicts 1 empty directory
Docs 1 directory
Docs/readme.ms 4 coarse nroff -ms format documentation
Docs/readme.txt 5 ascii format documentation
LICENCE 2 licence document
MANIFEST 1 THIS FILE
README 1 EVERYBODY START HERE
Runtime 1 empty directory
Scripts 1 scripts directory
Scripts/Crack.network 2 network driver script
Scripts/RCrack 1 interface to 'rsh', 'remsh' - whatever
Scripts/clean 1 tidy-up script
Scripts/crack.mf 1
Scripts/dicts.rules 2 rules applied to dictionary words
Scripts/do_install 1
Scripts/do_join 1
Scripts/do_pwc 1
Scripts/do_ufc 1
Scripts/gecos.rules 1 rules applied to gecos-generated words
Scripts/guess2fbk 1 crash recovery script (see docs)
Scripts/install.mf 1
Scripts/mrgfbk 1
Scripts/nastygram 1
Scripts/network.conf 1
Scripts/plaster 1 crack control script
Scripts/saltcount 1
Scripts/shadmrg 1
Scripts/spotless 1 tidy up and delete script
Scripts/status 1
Sources 1 source code directory
Sources/Makefile 1
Sources/bytesex.c 1
Sources/conf.h 1 configuration header file
Sources/crack-fcrypt.c 4
Sources/crack-glob.c 1
Sources/crack-glob.h 1
Sources/crack-lib.c 3
Sources/crack-pwc.c 3 password cracker main file
Sources/crack-sort.c 2
Sources/crack-supp.c 1
Sources/crack.h 1
Sources/speeds.c 1 benchmark program
Sources/tester.c 1 fcrypt compatibility program
Sources/testrule.c 1 dictionary tester program
TODO 1 List of good ideas I _already_ have
on which mentions that it is
compatible with Crack v4.1, and unpack it into a directory
called ufc-crypt in $CRACK_HOME, and then delete your old
binaries. UREADME 100600 5661 132 2333 5222357024 6111 0 0 1 0 This is Crack v4.1, the "Sensible" Unix Password Cracker.
- Documentation is in the directory 'Docs' - go for it...
dicts.rules is now up to 240 entries, mostly thanks to mycroft @
gnu.ai.mit.edu; don't lose heart, its not as bad as all that... 3 weeks
of CPU isn't all that long, really... Seriously, most of the rules
generate really small dictionaries, so it's not all that bad. 8-)
There are several additions to the dictionary rules, notably the
character class commands and the i, o, = and @ commands.
Use of "Crack -R" (as opposed to "Crack -r") is not recommended until I
write v5.0, unless you know exactly what you're doing and why it bombs
out on you...
Also, Crack now fully supports UFC (the latest version of which is to be
posted concurrently with Crack v4.1) - all you should have to do is
unpack the latest version of UFC into the directory
ufc-crypt
which you should create in the Crack installation directory. The
program should do the rest.
Happy cracking !
--
|+ Alec David Edward Muffett, Unix Programmer and Unemployed Coffee Drinker. +|
|>
[email protected] [email protected] aem%
[email protected] mcsun!ukc!aber!aem <|
| "I didn't invent the Unix Password Security problem. I just optimised it." |
0 1 0 Runtime/ 40755 5661 132 0 5222357025 6567 5 0 1 0 Scripts/ 40755 5661 132 0 5222357140 6571 5 0 1 0 Scripts/RCrack 100700 5661 132 6452 5222357027 10573 0 37777777777 1 0 #!/bin/sh
###
# This program is copyright Alec Muffett 1991, and is provided as part of
# the Crack v4.0 Password Cracking package. The author disclaims all
# responsibility or liability with respect to it's usage or its effect
# upon hardware or computer systems, and maintains copyright as set out in
# the "LICENCE" document which accompanies distributions of Crack v4.0 and
# upwards. So there...
###
###
# For those ignorant of 'rsh', what I am trying to build is a line of
# the form
# rsh hostname [-n] [-l remoteuser] command [args ...]
#
###
machine=`(uname) 2>&1` # What architecture are we on ?
###
# Map architecture to rsh-equivalent...
###
case $machine in
"HP*UX") # Hewlett Packard boxen
remote_shell="remsh"
;;
# "XENIX"|"Xenix") # Just a suggestion...
# remote_shell="rcmd"
# ;;
*) # default
remote_shell="rsh"
;;
esac
###
# Are we going to kick rsh into the background, or are we going to
# background the thing on the remote end ?
###
asynch_mode=""
if [ "x$1" = "x-asynch" ]
then
echo "(asynchronous $remote_shell mode)"
asynch_mode="$1"
shift
else
echo "(remotely backgrounded mode)"
fi
###
# Segments of input data to read.
###
startline=$1
shift
stopline=$1
shift
datafile=/tmp/rcrk.$$ # temporary data file
###
# Awk reads from stdin... Create an input file for rsh...
###
awk -F: '
BEGIN {
usercount = 0;
saltcount = 0;
startsalt = '"$startline"';
stopsalt = '"$stopline"';
}
{
if (substr($3, 1, 2) != last)
{
saltcount++;
last = substr($3, 1, 2);
}
if (saltcount >= startsalt && saltcount <= stopsalt)
{
usercount++;
print $0;
}
}' > $datafile
###
# Test that we should actually bother to do anything.
###
numlines=`wc -l < $datafile`
###
# Must not quote $numlines here for comparison to work
###
if [ $numlines = 0 ]
then
echo "RCrack: Nothing left to dispatch to remote host."
rm -f $datafile
exit 0
else
echo Salted Segment comprises $numlines users # Don't quote this...
fi
###
# Now for the important bits. Create a diefile pointing to a remote diefile
# (It's easier to get Crack.network to wire $remotediefile into arglist)
###
remhost=$1 # Name of remote host ($2 == Crack path)
remotediefile=$3 # Name of remote diefile
localdiefile=Runtime/DR$remhost$$ # Local pointer to above
awk -F: '
BEGIN {
rshell = "'"$remote_shell"'";
rhost = "'"$remhost"'";
rdie = "'"$remotediefile"'";
rdie = substr(rdie,3,length(rdie) - 2);
}
$1 == rhost {
if ($4 != "")
{
rshf = "-l " $4 " -n";
} else
{
rshf = "-n";
}
if ($5 != "")
{
nf = split($5, path, "/");
ch = path[1];
for (i = 2; i < nf; i++)
{
ch = ch "/" path[i];
}
} else
{
ch = "'"$CRACK_HOME_UNRES"'";
}
}
END {
print "#!/bin/sh";
print "rm $0 && " rshell, rhost, rshf, "\"cd " ch ";" rdie "\"";
}' < Scripts/network.conf > $localdiefile
chmod 700 $localdiefile
if [ "x$asynch_mode" = "x-asynch" ]
then
if [ "x$CRACK_OUT" != "x" ]
then
outfile=$CRACK_OUT/out.r$$
else
outfile=./out.r$$
fi
# 'rsh' traps SIGHUP and survives OK
echo "Invoking: $remote_shell $@ <$datafile >$outfile 2>&1 && rm -f $datafile $localdiefile &"
$remote_shell "$@" <$datafile >$outfile 2>&1 && rm -f $datafile $localdiefile &
else
# Perfectly ordinary network crack.
echo "Invoking: $remote_shell $@ < $datafile"
$remote_shell "$@" < $datafile
rm -f $datafile
fi
exit 0
user, you will suffer problems if
rsh insists on reading something from your terminal (eg: a
password for the remote account). Also, recovering using
checkpointing goes out the window unless you specify Scripts/clean 100700 5661 132 677 5222357030 10465 0 37777777777 1 0 #!/bin/sh
###
# This program is copyright Alec Muffett 1991, and is provided as part of
# the Crack v4.0 Password Cracking package. The author disclaims all
# responsibility or liability with respect to it's usage or its effect
# upon hardware or computer systems, and maintains copyright as set out in
# the "LICENCE" document which accompanies distributions of Crack v4.0 and
# upwards. So there...
###
make -f Scripts/crack.mf clean
exit 0
1 empty directory
Docs Scripts/crack.mf 100600 5661 132 473 5222357031 11061 0 37777777777 1 0 SRCDIR= Sources
BIGDICT= Dicts/bigdict
UFCDIR= ufc-crypt
all:
@echo CALL TO CRACK.MF WITH NO TARGET
spotless: clean
-rm -f out.* $(BIGDICT)* Dicts/.lock*
-Scripts/mrgfbk
clean:
-rm -f Runtime/D* Runtime/P* Runtime/RD* tmp.* nohup.out
-( cd $(SRCDIR) && make clean )
-( cd $(UFCDIR) && make clean )
ipts/guess2fbk 1 crash recovery script (see docs)
Scripts/install.mf 1
Scripts/mrgfbk 1
Scripts/nastygram 1
Scripts/network.conf 1
Scripts/plastScripts/do_install 100700 5661 132 1367 5222357032 11552 0 37777777777 1 0 #!/bin/sh
###
# This program is copyright Alec Muffett 1991, and is provided as part of
# the Crack v4.0 Password Cracking package. The author disclaims all
# responsibility or liability with respect to it's usage or its effect
# upon hardware or computer systems, and maintains copyright as set out in
# the "LICENCE" document which accompanies distributions of Crack v4.0 and
# upwards. So there...
###
crack_arch=$1
###
# Is there a binaries directory ?
###
if [ ! -d $crack_arch ]
then
mkdir $crack_arch || exit 1
fi
cd $crack_arch || exit 1 # Can we get there from here ?
###
# Install makefiles in our directory if necessary.
###
if [ ! -f Makefile ]
then
cp $CRACK_HOME/Scripts/install.mf Makefile || exit 1
fi
exit 0
0 1 0 Scripts/do_join 100700 5661 132 3566 5222357034 11050 0 37777777777 1 0 #!/bin/sh
###
# This program is copyright Alec Muffett 1991, and is provided as part of
# the Crack v4.0 Password Cracking package. The author disclaims all
# responsibility or liability with respect to it's usage or its effect
# upon hardware or computer systems, and maintains copyright as set out in
# the "LICENCE" document which accompanies distributions of Crack v4.0 and
# upwards. So there...
###
###
# Empty the output file, Error if cannot create
###
warn=$1
shift
cp /dev/null $warn || exit 1
###
# Have we got feedback ?
###
fbkfiles=`sh -c "echo Runtime/F*"`
if [ "$fbkfiles" = "Runtime/F*" ]
then
fbkfiles=""
fi
###
# As Walt Disney would say, we start with a simple bracket:-
###
(
if [ "$fbkfiles" != "" ]
then
cat $fbkfiles
fi
(
for file in $*
do
awk '/^[A-Za-z0-9]/ {print "'"$file"':" $0}' < $file
done
) |
sort -t: +2
) |
awk -F: '
BEGIN {
FS = ":";
numf = 8; # number of fields in a pwent, + 1
warn="'"$warn"'";
date = "'"`date`"'";
date = substr(date, 5, 15);
}
/^!fb!/ {
if ($3 == "N")
{
guessable[$2] = "N";
} else if ($3 == "Y")
{
guessable[$2] = "Y";
decrypt[$2] = $4;
} else
{
print "Strange feedback: ", $0 >> "/dev/tty";
}
next;
}
NF != numf {
printf("join: Rejected '%s': does not have %d fields\n", \
$0, numf) >> warn;
next;
}
$3 == "" {
printf("join: %s Warning! %s (%s in %s) has a NULL password!\n", \
date, $2, $7, $1) >> warn;
next;
}
index($3, "*") != 0 || \
index($3, "!") != 0 || \
index($3, " ") != 0 {
printf("join: %s User %s (in %s) has a locked password:- %s\n", \
date, $2, $1, $3) >> warn;
next;
}
{
if (guessable[$3] == "N")
{
next;
} else if (guessable[$3] == "Y")
{
if ($4 == 0)
{
msg = "ROOT PASSWORD ";
} else
{
msg = "";
}
printf("join: %s Guessed %s%s (%s in %s) [%s] %s\n", \
date, msg, $2, $8, $1, decrypt[$3], $3) >> warn;
} else
{
print $0;
}
}'
exit 0
Scripts/do_pwc 100700 5661 132 1222 5222357035 10666 0 37777777777 1 0 #!/bin/sh
###
# This program is copyright Alec Muffett 1991, and is provided as part of
# the Crack v4.0 Password Cracking package. The author disclaims all
# responsibility or liability with respect to it's usage or its effect
# upon hardware or computer systems, and maintains copyright as set out in
# the "LICENCE" document which accompanies distributions of Crack v4.0 and
# upwards. So there...
###
crack_arch=$1
if [ ! -d $crack_arch ]
then
Scripts/do_install $crack_arch || exit 1
fi
cd $crack_arch || exit 1 # Can we get there from here ?
###
# Make the password cracker
###
make crack-pwc || exit 1
# bye bye
exit 0
t...
###
case $machine in
"HP*UX") # Hewlett Packard boxen
remote_shell="remsh"
;;
# "XENIX"|"Xenix") # Just a suggestion...
# remote_shell="rcmd"
# ;;
*) # default
remote_shell="rsh"
;;
esac
###
# Are we going to kick rsh into the background, or are we going to
# background the thing on the remote end ?
###
asynch_mode=""
if [ "x$1" = "x-asScripts/do_ufc 100700 5661 132 2635 5222357036 10664 0 37777777777 1 0 #!/bin/sh
###
# This program is copyright Alec Muffett 1991, and is provided as part of
# the Crack v4.0 Password Cracking package. The author disclaims all
# responsibility or liability with respect to it's usage or its effect
# upon hardware or computer systems, and maintains copyright as set out in
# the "LICENCE" document which accompanies distributions of Crack v4.0 and
# upwards. So there...
###
###
# This script tries to provide an intelligent hook to the UFC-crypt library
###
if [ "x$CRACK_HOME" = "x" ]
then
CRACK_HOME=".." # for would-be developers in the Sources dir
fi
UFCLIB=libufc.a
SRCDIR=$CRACK_HOME/Sources
UFCDIR=$CRACK_HOME/ufc-crypt
rm -f $SRCDIR/libufc.a # just in case
echo "Looking for UFC-crypt in $UFCDIR"
if [ ! -d $UFCDIR ]
then
echo "Cannot find $UFCDIR - cannot use UFC-crypt on this platform"
exit 1
fi
cd $UFCDIR || exit 1
echo "Crack: Trying to compile UFC-crypt (external product by Michael Glad)"
echo "Crack: Working in $UFCDIR"
if [ -f libufc.a ]
then
echo "Library libufc.a exists. Testing viability..."
rm -f ufc
make ufc
if [ $? = 0 ]
then
echo "Testing ufc"
./ufc 1
if [ $? = 0 ]
then
echo "Crack will use UFC-crypt on this platform"
exit 0
fi
fi
echo "Library is unviable on this architecture. Remaking"
fi
make clean || exit 1
make ufc || exit 1
echo "Testing ufc"
/ufc 1 || exit 1
echo "Crack WILL use $UFCDIR/libufc.a on this platform."
exit 0
else
outfile=./out.r$$
fi
# 'rsh' traps SIGHUP and survives OK
echo "Invoking: $remote_sheScripts/gecos.rules 100600 5661 132 1265 5222357040 11646 0 37777777777 1 0 ###
# Try to avoid redundancy in this file... AEM
###
>2
>2/?ul
>2/?lu
>2ud
>2uf
>2ur
>2cf
>2cr
>2rc
>2ld
>2lf
>2lr
>2<8c$!
>2<8c$.
>2<8c$?
>2^($)
>2<8$!
>2<8$.
>2<8$0
>2<8$1
>2<8$2
>2<8$3
>2<8$4
>2<8$5
>2<8$6
>2<8$7
>2<8$8
>2<8$9
>2<8/?ul$!
>2<8/?ul$.
>2<8/?ul$?
>2<8/?ul$0
>2<8/?ul$1
>2<8/?ul$2
>2<8/?ul$3
>2<8/?ul$4
>2<8/?ul$5
>2<8/?ul$6
>2<8/?ul$7
>2<8/?ul$8
>2<8/?ul$9
>2<8/?lu$!
>2<8/?lu$.
>2<8/?lu$?
>2<8/?lu$0
>2<8/?lu$1
>2<8/?lu$2
>2<8/?lu$3
>2<8/?lu$4
>2<8/?lu$5
>2<8/?lu$6
>2<8/?lu$7
>2<8/?lu$8
>2<8/?lu$9
!?d>2^0
!?d>2^1
!?d>2^2
!?d>2^3
!?d>2^4
!?d>2^5
!?d>2^6
!?d>2^7
!?d>2^8
!?d>2^9
>2/?ul^0
>2/?ul^1
>2/?ul^2
>2/?ul^3
>2/?ul^4
>2/?ul^5
>2/?ul^6
>2/?ul^7
>2/?ul^8
>2/?ul^9
ability with respect to it's usage or its effect
# upon hardware or computer systems, and maintains copyright as set out in
# the "LICENCE" document which accompanies distributions of Crack v4.0 and
# upwards. So there...
###
make -f Scripts/crack.mf clean
exit 0
1 empty directory
Docs Scripts/guess2fbk 100700 5661 132 1533 5222357041 11310 0 37777777777 1 0 #!/bin/sh
###
# This program is copyright Alec Muffett 1991, and is provided as part of
# the Crack v4.0 Password Cracking package. The author disclaims all
# responsibility or liability with respect to it's usage or its effect
# upon hardware or computer systems, and maintains copyright as set out in
# the "LICENCE" document which accompanies distributions of Crack v4.0 and
# upwards. So there...
###
###
# guess2fbk : generates a 'feedback' file on stdout from output format
# data. On occasions when emergency construction is useful.
###
if [ $# = 0 ]
then
echo "Usage: $0 outputfile [...]"
exit 1
fi
###
# Had to modify this awk script now that passwords are turning up with spaces
###
cat $* |
awk '
/Guessed/{
start = index($0, "[");
stop = index($0, "]");
print "!fb!:" $NF ":Y:" substr($0, start+1, stop - start - 1)
}
' |
sort |
uniq
1 0 Scripts/install.mf 100600 5661 132 1326 5222357042 11464 0 37777777777 1 0 ###
# This program is copyright Alec Muffett 1991, and is provided as part of
# the Crack v4.0 Password Cracking package. The author disclaims all
# responsibility or liability with respect to it's usage or its effect
# upon hardware or computer systems, and maintains copyright as set out in
# the "LICENCE" document which accompanies distributions of Crack v4.0 and
# upwards. So there...
###
SD= ../Sources
SRC1= $(SD)/conf.h $(SD)/crack-fcrypt.c $(SD)/crack-glob.c
SRC2= $(SD)/crack-glob.h $(SD)/crack-lib.c $(SD)/crack-pwc.c
SRC3= $(SD)/crack-sort.c $(SD)/crack-supp.c $(SD)/crack.h
SRCS= $(SRC1) $(SRC2) $(SRC3)
crack-pwc: $(SRCS)
( cd $(SD) ; make clean )
( cd $(SD) ; make crack-pwc.which )
cp $(SD)/crack-pwc .
37777777777 1 0 Scripts/mrgfbk 100700 5661 132 2333 5222357043 10666 0 37777777777 1 0 #!/bin/sh
###
# This program is copyright Alec Muffett 1991, and is provided as part of
# the Crack v4.0 Password Cracking package. The author disclaims all
# responsibility or liability with respect to it's usage or its effect
# upon hardware or computer systems, and maintains copyright as set out in
# the "LICENCE" document which accompanies distributions of Crack v4.0 and
# upwards. So there...
###
###
# mrgfbk - a shell script to merge all of your feedback files into one
# before starting a Crack -F on a set of new dictionaries. This program
# is called from "Scripts/spotless"
###
# mrgfbk takes all the feedback files and filters out all the GUESSED
# passwords, and saves them to a new feedback file. The UNGUESSED
# passwords are deleted, so that the new dictionaries can have a go at
# them
###
tf=./mfb$$
echo ""
echo "Saving all CRACKABLE passwords.
Do you also want to save your UNCRACKABLE passwords ?
Answer NO if you have changed some rules or modified source dictionaries
(default: yes) "
read answer
case $answer in
[Nn]*)
cat Runtime/F* |
awk -F: '$3 == "Y"' |
sort |
uniq > $tf
;;
*)
cat Runtime/F* |
sort |
uniq > $tf
;;
esac
rm -f Runtime/F*
cp $tf Runtime/F.merged
rm -f $tf
exit 0
"";
}
printf("join: %s Guessed %s%s (%s in %s) [%s] %s\n", \
date, msg, $2, $8, $1, decrypt[$3], $3) >> warn;
} else
{
print $0;
}
}'
exit 0
Scripts/nastygram 100700 5661 132 2654 5222357045 11433 0 37777777777 1 0 #!/bin/sh
###
# This program is copyright Alec Muffett 1991, and is provided as part of
# the Crack v4.0 Password Cracking package. The author disclaims all
# responsibility or liability with respect to it's usage or its effect
# upon hardware or computer systems, and maintains copyright as set out in
# the "LICENCE" document which accompanies distributions of Crack v4.0 and
# upwards. So there...
###
for username in $*
do
mail $username <<EndOfLetter
`date`
Dear $username,
The login password you use for the account "$username" has been found to
be insecure by the "Crack" password guessing program. You must change
your password as soon as possible.
Passwords which are not easily compromised by programs such as "Crack"
are based upon non-dictionary words, hence any word which might appear
in a dictionary, EVEN IF IT IS SUPPOSEDLY A OBSCURE WORD is unsuitable.
Similarly, any password which is derived from your name, department or
other personal information is unsuitable because it can be easily
guessed.
It is important that password security be maintained at a high level for
the sake of ALL the people who use these computers. We thank you for
your co-operation in this matter.
Yours,
Alec Muffett, Aberystwyth, UK
pp Your System Administrator
EndOfLetter
done
Scripts/network.conf 100600 5661 132 4475 5222357046 12046 0 37777777777 1 0 ###
# Format of this file:-
###
#
# host:binary type:relative power:rsh user:crack path:crack flags:comment
#
# host = hostname to 'rsh' to
# binary type = type of executable to build on this sort of machine
# relative power = power of host relative to weakest machine
# rsh user = username to 'rsh -l' to, if not same as current user.
# crack path = full path name of Crack on host (deft: $CRACK_HOME/Crack)
# crack flags = additional flags to add to crack command line on that host
# comment = anything, really, for your reference
#
# 1) Don't bother specifying "-F" amongst "crack flags" as the
# one which you use on the command line will be passed across.
#
# 2) You CAN specify "-f" here, to throw the remote password cracker
# into foreground mode for non-NFS working, but please read the docs
# thoroughly first.
###
# I have specified relative power here as the number of fcrypts per second
# that each host is (roughly) capable of. This is a perfectly good way to
# define relative power, but if you are at a loss, call your weakest machine
# '1', and measure all others in terms of that.
###
#### Mainframe power boxes
#aberda:mipsel:600:::-n10: Mainframe Dec 5830
#aberdb:mipsel:600:::-n10: Mainframe Dec 5830
##aberdc:mipsel:1200:::: Mainframe DecStation 5000/200
#aberdq:sun4:1000:::: Mainframe Sun 4/330
#### Some of the CS machines over an rsh link - souped up Sun 3/50s
##odin:sun3:50::~aem/Crack/Crack:-n10 -f: Computer Science Server
##thor:sun3:50::~aem/Crack/Crack:-n10 -f: Computer Science Server
#### Colour DECStation 2100's
#decgca:mipsel:700:::-n4: Graphics Room DecStation 2100
#decgcb:mipsel:700:::-n4: Graphics Room DecStation 2100
#decgcc:mipsel:700:::-n4: Graphics Room DecStation 2100
#decgcd:mipsel:700:::-n4: Graphics Room DecStation 2100
##decgce:mipsel:700:::-n4: Nigel's 2100 gets switched off nites
#### Monochrome DECStation 2100's
#decgma:mipsel:700:::-n4: Graphics Room DecStation 2100
##decgmb:mipsel:700:::-n4:DecStation 2100 cannabalised for parts
##decgmc:mipsel:700:::-n4: Graphics Room DecStation 2100
##decgmd:mipsel:700:::-n4: Graphics Room DecStation 2100
##decgme:mipsel:700:::-n4: Graphics Room DecStation 2100
#### Sun 3/50C's which are barely worth bothering about
##sunga:sun3:100:::-n4: Graphics Room Sun 3/50
##sunga:sun3:100:::-n4: Graphics Room Sun 3/50
##sunga:sun3:100:::-n4: Graphics Room Sun 3/50
CE" document which accompanies distributions of Crack v4.0 and
# upwards. So there...
###
make -f Scripts/crack.mf clean
exit 0
1 empty directory
Docs Scripts/plaster 100700 5661 132 1230 5222357047 11067 0 37777777777 1 0 #!/bin/sh
###
# This program is copyright Alec Muffett 1991, and is provided as part of
# the Crack v4.0 Password Cracking package. The author disclaims all
# responsibility or liability with respect to it's usage or its effect
# upon hardware or computer systems, and maintains copyright as set out in
# the "LICENCE" document which accompanies distributions of Crack v4.0 and
# upwards. So there...
###
###
# This program provides a quick network murder if running "Crack -network"
###
# The name is Chris Samuel's fault... "Plaster the Cracks" indeed...
# Mail admiration of this joke to
[email protected]
###
for i in Runtime/D*
do
echo $i
$i
done
exit 0
words are turning up with spaces
###
cat $* |
awk '
/Guessed/{
start = index($0, "[");
stop = index($0, "]");
print "!fb!:" $NF ":Y:" substr($0, start+1, stop - start - 1)
}
' |
sort |
uniq
1 0 Scripts/saltcount 100700 5661 132 1163 5222357051 11431 0 37777777777 1 0 #!/bin/sh
###
# This program is copyright Alec Muffett 1991, and is provided as part of
# the Crack v4.0 Password Cracking package. The author disclaims all
# responsibility or liability with respect to it's usage or its effect
# upon hardware or computer systems, and maintains copyright as set out in
# the "LICENCE" document which accompanies distributions of Crack v4.0 and
# upwards. So there...
###
###
# Count the number of individual salts in do_join format...
###
awk -F: '
BEGIN {
i = 0; # Just in case there is no input
}
substr($3, 1, 2) != last {
i++;
last = substr($3, 1, 2);
}
END {
print i;
}'
exit 0
pwc: $(SRCS)
( cd $(SD) ; make clean )
( cd $(SD) ; make crack-pwc.which )
cp $(SD)/crack-pwc .
37777777777 1 0 Scripts/shadmrg 100700 5661 132 1664 5222357052 11051 0 37777777777 1 0 #!/bin/sh
###
# This program is copyright Alec Muffett 1991, and is provided as part of
# the Crack v4.0 Password Cracking package. The author disclaims all
# responsibility or liability with respect to it's usage or its effect
# upon hardware or computer systems, and maintains copyright as set out in
# the "LICENCE" document which accompanies distributions of Crack v4.0 and
# upwards. So there...
###
shadow=/etc/shadow
passwd=/etc/passwd
###
# Merge /etc/shadow & /etc/passwd for Crack. Assume 7 fields for /etc/passwd,
# and other for /etc/shadow
###
cat $passwd $shadow |
awk -F: '
BEGIN {
OFS = ":";
}
NF == 7 {
pwents[$1] = $0;
}
NF != 7 {
shadow_pw[$1] = $2;
}
END {
for (pw_name in pwents)
{
fields = split(pwents[pw_name], pwd, ":");
if (shadow_pw[pwd[1]] != "LOCKED")
{
print pwd[1], \
shadow_pw[pwd[1]], \
pwd[3], \
pwd[4], \
pwd[5], \
pwd[6], \
pwd[7];
}
}
}'
e changed some rules or modified source dictionaries
(default: yes) "
read Scripts/spotless 100700 5661 132 1052 5222357053 11270 0 37777777777 1 0 #!/bin/sh
###
# This program is copyright Alec Muffett 1991, and is provided as part of
# the Crack v4.0 Password Cracking package. The author disclaims all
# responsibility or liability with respect to it's usage or its effect
# upon hardware or computer systems, and maintains copyright as set out in
# the "LICENCE" document which accompanies distributions of Crack v4.0 and
# upwards. So there...
###
echo "Are you sure that you want to do this ? (no)"
read ans
case $ans in
[Yy]*)
make -f Scripts/crack.mf spotless
;;
*)
;;
esac
exit 0
Alec Muffett 1991, and is provided as part of
# the Crack v4.0 Password Cracking package. The author disclaims all
# responsibility or liability with respect to it's usage or its effect
# upon hardware or computer systems, and maintains copyright as set out in
# the "LICENCE" document which accompanies distributions of Crack v4.0 and
# upwards. So there...
###
for username in $*
do
mail $username <<EndOfLetter
`dateScripts/status 100700 5661 132 1166 5222357054 10746 0 37777777777 1 0 #!/bin/sh
###
# This program is copyright Alec Muffett 1991, and is provided as part of
# the Crack v4.0 Password Cracking package. The author disclaims all
# responsibility or liability with respect to it's usage or its effect
# upon hardware or computer systems, and maintains copyright as set out in
# the "LICENCE" document which accompanies distributions of Crack v4.0 and
# upwards. So there...
###
cat Scripts/network.conf |
awk -F: '
/^[A-Za-z]/{
print "echo ::: Calling", $1, " :-";
if ($4 == "")
{
rshf = "-n";
} else
{
rshf = "-n -l " $4;
}
print "rsh ", $1, rshf, "\"uptime ; ps x\"";
} ' |
sh
exit 0
132 4475 5222357046 12046 0 37777777777 1 0 Scripts/Crack.network 100700 5661 132 7312 5222357135 12135 0 37777777777 1 0 #!/bin/sh
###
# This program is copyright Alec Muffett 1991, and is provided as part of
# the Crack v4.0 Password Cracking package. The author disclaims all
# responsibility or liability with respect to it's usage or its effect
# upon hardware or computer systems, and maintains copyright as set out in
# the "LICENCE" document which accompanies distributions of Crack v4.0 and
# upwards. So there...
###
# This program reads the network.conf and breaks up the sorted password
# file and runs RCrack to kick Crack up on all the machines and feeds
# the file to it.
###
# Okay, if you don't like this bit of code, YOU think of a totally
# portable way to do this - in shell scripts without using PERL - Alec.
###
cf=Scripts/network.conf
tf=/tmp/mcp.$$
###
# Check that the config file is in place
###
if [ ! -f $cf -o ! -s $cf ]
then
echo "Crack.network: empty or missing config file: $cf"
exit 1
fi
###
# Parse arguments
###
args=""
files=""
domail=""
for i in $*
do
if [ -f "$i" ]
then
files="$files $i"
else
case $i in
-f*)
echo "Crack: -f option on COMMAND LINE incompatible with networking - Ignored"
;;
-m*)
domail="$i"
args="$args $i"
;;
*)
args="$args $i"
;;
esac
fi
done
###
# Get on with your proper job
###
echo "Merging input data."
if [ "$CRACK_OUT" != "" ]
then
warn=$CRACK_OUT/out.$$
else
warn=out.$$
fi
Scripts/do_join $warn $files > $tf
if [ "x$domail" != "x" ]
then
MISCREANTS=`awk '/Guessed/{print $6}' < $warn`
echo Sending Warning Mail to $MISCREANTS
Scripts/nastygram $MISCREANTS
fi
###
# Statistics gathering
###
lines=`wc -l < $tf`
saltlines=`Scripts/saltcount < $tf`
# Must not quote $lines/$saltlines here for comparison to work
if [ $lines = 0 -o $saltlines = 0 ]
then
echo "Crack: no uncracked input to distribute."
exit 1
fi
echo "Starting analysis for Network-Crack."
cat $cf |
grep -v '^#' |
grep -v '^$' |
sort -t: +2 -n |
awk -F: '
BEGIN {
hostcount = 0;
totalweight = 0;
linecount = '"$lines"';
saltlinecount = '"$saltlines"';
iargs = "'"$args"'";
file = "'"$tf"'";
}
/^[a-zA-Z0-9]/ {
hostname[hostcount] = $1;
bintype[hostcount] = $2;
relpow[hostcount] = $3;
powtot += $3;
if (index($6, "-f") == 0)
{
asynch[hostcount] = "";
} else
{
asynch[hostcount] = "-asynch";
}
crackf[hostcount] = $6 " " iargs; # useropts go second get priority
if ($4 == "")
{
rshuser[hostcount] = "";
} else
{
rshuser[hostcount] = "-l " $4;
crackf[hostcount] = crackf[hostcount] " -U" $4;
}
if ($5 == "")
{
crackp[hostcount] = "$CRACK_HOME_UNRES/Crack";
} else
{
crackp[hostcount] = $5;
}
crackf[hostcount] = iargs " " $6;
hostcount++;
}
END {
done = 1;
slice = 0.0;
remainder = 0.0;
todo = saltlinecount;
print "echo Users:", linecount;
print "echo Salts:", saltlinecount;
print "echo Remote Hosts:", hostcount;
print "echo Total power:", powtot;
for (i = 0; i < hostcount; i++)
{
if (i < hostcount - 1)
{
# This balancing algorithm by:
[email protected] (George Scott)
# its wonderful - AEM
slice = relpow[i] / powtot; # fraction
slice *= todo; # percentage
slice = int(slice); # round down
todo -= slice; # remainder
powtot -= relpow[i];
} else
{
slice = todo; # fastest machine gets the rest.
todo = 0;
}
if (slice > 0)
{
print "echo Calling", hostname[i], "for", slice, "different salts";
line = sprintf( \
"Scripts/RCrack %s %d %d %s %s \"%s\" %s %s %s < %s", \
asynch[i], \
done, \
done + slice - 1, \
hostname[i], \
rshuser[i], \
crackp[i], \
"-XRuntime/RD'"$$"'." i, \
crackf[i], \
bintype[i], \
file);
# print "echo", line;
print line;
}
done += slice;
}
}' | sh # I'll bet you didn't expect this...
rm $tf
exit 0
37777777777 1 0 Scripts/dicts.rules 100600 5661 132 24271 5222357141 11700 0 37777777777 1 0 ###
# Description file for Crack dictionary processor. ADE Muffett, Mar 1992
###
# Ordinary Commands:
# : = no-op - do nothing to the input word
# <n = reject word UNLESS it is < n characters long, where n = 0-9a-z
# >n = reject word UNLESS it is > n characters long, where n = 0-9a-z
# ^x = prepend character 'x' to word
# $y = append character 'y' to word
# l = force word to be lowercase
# u = force word to be uppercase
# c = force word to be capitalised
# r = reverse word: "Fred" -> "derF"
# d = duplicate word: "Fred" -> "FredFred"
# f = reflect word: "Fred" -> "FredderF"
# p = make best attempt to pluralise a lowercase word
# onx = overstrike character in position 'n' (start at 0) with character 'x'
# nb: little overflow checking is done, so use '<' and '>' carefully
# inx = insert character 'x' in position 'n' (start at 0) and shift the rest
# of the input string right.
# eg: i3* on "wibble" yields "wib*ble"; i0* on "wibble" yields "*wibble"
# nb: if n > strlen(input), character 'x' will be appended
# xnm = extract substring from position n (start at 0) for up to m characters
# eg: using x27 on "autobogotification" yields "tobogot"
# eg: using x3a on "autobogotification" yields "obogotific" (10 chars)
# nb: little overflow checking is done, so use '<' and '>' carefully
###
# Commands which may utilise character classes: (note special use of '?')
# sxy = replace (swap) all 'x' in the word with 'y'
# s?cy = replace all characters of class 'c' in the word with y
# @x = purge all 'x' from the word
# @?c = purge all characters of class 'c' from the word
# !y = reject word if it contains character 'y'
# !?c = reject word if it contains a character in class 'c'
# /x = reject word unless it contains character 'x'
# /?c = reject word unless it contains a character in class 'c'
# =nx = reject word unless char at position 'n' is equal to x
# =n?c = reject word unless char at position 'n' is in class 'c'
# nb: the word always starts at position 0
###
# Character classes for use in above:
# ?? matches "?"
# ?v matches vowels aeiou
# ?c matches consonants bcdfghjklmnpqrstvwxyz
# ?w matches whitespace (space, tab)
# ?p matches punctuation .,:;'"?!`
# ?s matches symbols $%^&*()-_+=|\[]{}#@/~
# ?l matches lowercase letters
# ?u matches uppercase letters
# ?d matches any digit
# ?a matches any letter of the alphabet
# ?x matches any letter of the alphabet, or any digit (ie: is alphanumeric)
# The complement of a class may be matched by the uppercase of it's letter
# ie: where ?d == DIGITS, ?D == NON-DIGITS, and so on.
###
# Many people haven't realised that the above is a complete language; ie:
# if you want to create a dictionary of short words with "123" appended,
# use "<6l$1$2$3".
###
# A FINAL NOTE: remember that very few users are aware that passwords
# stop at 8 chars long; so, while it IS worthwhile to check for words
# being 8 or more chars long before appending a character, it is NOT
# worthwhile to do the same when prepending characters. Hence:-
#
# "williamsburgh" -> "williams" }\
# "williamsburgh1" -> "williams" }/~~~Will be uniqued.
# "1williamsburgh" -> "1william"
#
###
# So, here we go; try to order these in the order most likely to be a
# password. First we try to make selections from the pure alphabetic
# words in the dicts, then we get onto the weird stuff.
######################################################################
# Force every pure alphabetic word lowercase and try it
# NOT-CONTAIN ANY NON-ALPHA, LOWERCASE
!?Al
# Pluralise every significant one of the above
# MORE-THAN 2, NOT-CONTAIN ANY NON-ALPHA, LOWERCASE, PLURALISE
>2!?Alp
# Try variations of anything that is not pure alnum
# CONTAIN ANY NON-ALNUM
/?X
# CONTAIN ANY NON-ALNUM, CONTAIN ANY UPPER, LOWERCASE
/?X/?ul
# Any alphaword >2 & <8 chars long, append a digit or simple punctuation
# since few ppl add non alpha chars to a already non-alpha word
# MORE-THAN 2, LESS-THAN 8, NOT ANY NON-ALPHA, LOWERCASE, APPEND <whatever>
>2<8!?Al$0
>2<8!?Al$1
>2<8!?Al$2
>2<8!?Al$3
>2<8!?Al$4
>2<8!?Al$5
>2<8!?Al$6
>2<8!?Al$7
>2<8!?Al$8
>2<8!?Al$9
>2<8!?Al$!
>2<8!?Al$.
>2<8!?Al$?
>2<8!?Al$ :
# trailing colon (no-op) on last line delimits space character.
# Lowercase every pure alphabetic word and reverse it
# MORE-THAN 2, NOT-CONTAIN ANY NON-ALPHA, LOWERCASE, REVERSE
>2!?Alr
# Capitalise every pure alnum word (ie: not anything which is not alnum)
# MORE-THAN 2, NOT-CONTAIN ANY NON-ALNUM, CAPITALISE
>2!?Xc
# Anything uppercase
# MORE-THAN 2, NOT-CONTAIN ANY NON-ALNUM, UPPERCASE
>2!?Xu
# Pure alphabetic words with vowels removed which are still fairly long
# NOT-CONTAIN ANY NON-ALPHA, CONTAIN ANY VOWEL, PURGE ANY VOWEL, MORE-THAN 3
!?A/?v@?v>3
# Look, I'm getting really bored of this monotone uppercase typing, so
# if it's OK with you, I'll drop the commentaries on each rule. You
# should have got the idea by now...
# Longish pure words lowercased and reflected
>2!?Alf
# Words containing whitespace, which is then squeezed out
/?w@?w>3
# In a similar vein, words with punctuation, squeezed out
/?p@?p>3
# Reasonably short words, duplicated. eg: "fredfred"
>1<7!?Ald
###
# >From:
[email protected]
# >In addition to the standard dicts.rules, I use the following set. You
# >can guess what it does.
# I've tidied this up a bit (I hope) - alec
###
>2/asa2l
>2/asa4l
>2/ese3l
>2/hsh4l
>2/isi1l
>2/lsl1l
>2/oso0l
>2/sss$l
>2/asa2/hsh4l
>2/asa2/sss$l
>2/asa4/hsh4l
>2/ese3/asa2l
>2/ese3/asa4l
>2/ese3/hsh4l
>2/ese3/sss$l
>2/isi1/asa2l
>2/isi1/asa4l
>2/isi1/ese3l
>2/isi1/hsh4l
>2/isi1/sss$l
>2/lsl1/asa2l
>2/lsl1/asa4l
>2/lsl1/ese3l
>2/lsl1/hsh4l
>2/lsl1/isi1l
>2/lsl1/oso0l
>2/lsl1/sss$l
>2/oso0/asa2l
>2/oso0/asa4l
>2/oso0/ese3l
>2/oso0/hsh4l
>2/oso0/isi1l
>2/oso0/sss$l
>2/sss$/asa4l
>2/sss$/hsh4l
>2/asa2/sss$/hsh4l
>2/ese3/asa2/hsh4l
>2/ese3/asa2/sss$l
>2/ese3/asa4/hsh4l
>2/ese3/sss$/asa4l
>2/ese3/sss$/hsh4l
>2/isi1/asa2/hsh4l
>2/isi1/asa2/sss$l
>2/isi1/asa4/hsh4l
>2/isi1/ese3/asa2l
>2/isi1/ese3/asa4l
>2/isi1/ese3/hsh4l
>2/isi1/ese3/sss$l
>2/isi1/sss$/asa4l
>2/isi1/sss$/hsh4l
>2/lsl1/asa2/hsh4l
>2/lsl1/asa2/sss$l
>2/lsl1/asa4/hsh4l
>2/lsl1/ese3/asa2l
>2/lsl1/ese3/asa4l
>2/lsl1/ese3/hsh4l
>2/lsl1/ese3/sss$l
>2/lsl1/isi1/asa2l
>2/lsl1/isi1/asa4l
>2/lsl1/isi1/ese3l
>2/lsl1/isi1/hsh4l
>2/lsl1/isi1/sss$l
>2/lsl1/oso0/asa2l
>2/lsl1/oso0/asa4l
>2/lsl1/oso0/ese3l
>2/lsl1/oso0/hsh4l
>2/lsl1/oso0/isi1l
>2/lsl1/oso0/sss$l
>2/lsl1/sss$/asa4l
>2/lsl1/sss$/hsh4l
>2/oso0/asa2/hsh4l
>2/oso0/asa2/sss$l
>2/oso0/asa4/hsh4l
>2/oso0/ese3/asa2l
>2/oso0/ese3/asa4l
>2/oso0/ese3/hsh4l
>2/oso0/ese3/sss$l
>2/oso0/isi1/asa2l
>2/oso0/isi1/asa4l
>2/oso0/isi1/ese3l
>2/oso0/isi1/hsh4l
>2/oso0/isi1/sss$l
>2/oso0/sss$/asa4l
>2/oso0/sss$/hsh4l
>2/sss$/asa4/hsh4l
>2/ese3/asa2/sss$/hsh4l
>2/ese3/sss$/asa4/hsh4l
>2/isi1/asa2/sss$/hsh4l
>2/isi1/ese3/asa2/hsh4l
>2/isi1/ese3/asa2/sss$l
>2/isi1/ese3/asa4/hsh4l
>2/isi1/ese3/sss$/asa4l
>2/isi1/ese3/sss$/hsh4l
>2/isi1/sss$/asa4/hsh4l
>2/lsl1/asa2/sss$/hsh4l
>2/lsl1/ese3/asa2/hsh4l
>2/lsl1/ese3/asa2/sss$l
>2/lsl1/ese3/asa4/hsh4l
>2/lsl1/ese3/sss$/asa4l
>2/lsl1/ese3/sss$/hsh4l
>2/lsl1/isi1/asa2/hsh4l
>2/lsl1/isi1/asa2/sss$l
>2/lsl1/isi1/asa4/hsh4l
>2/lsl1/isi1/ese3/asa2l
>2/lsl1/isi1/ese3/asa4l
>2/lsl1/isi1/ese3/hsh4l
>2/lsl1/isi1/ese3/sss$l
>2/lsl1/isi1/sss$/asa4l
>2/lsl1/isi1/sss$/hsh4l
>2/lsl1/oso0/asa2/hsh4l
>2/lsl1/oso0/asa2/sss$l
>2/lsl1/oso0/asa4/hsh4l
>2/lsl1/oso0/ese3/asa2l
>2/lsl1/oso0/ese3/asa4l
>2/lsl1/oso0/ese3/hsh4l
>2/lsl1/oso0/ese3/sss$l
>2/lsl1/oso0/isi1/asa2l
>2/lsl1/oso0/isi1/asa4l
>2/lsl1/oso0/isi1/ese3l
>2/lsl1/oso0/isi1/hsh4l
>2/lsl1/oso0/isi1/sss$l
>2/lsl1/oso0/sss$/asa4l
>2/lsl1/oso0/sss$/hsh4l
>2/lsl1/sss$/asa4/hsh4l
>2/oso0/asa2/sss$/hsh4l
>2/oso0/ese3/asa2/hsh4l
>2/oso0/ese3/asa2/sss$l
>2/oso0/ese3/asa4/hsh4l
>2/oso0/ese3/sss$/asa4l
>2/oso0/ese3/sss$/hsh4l
>2/oso0/isi1/asa2/hsh4l
>2/oso0/isi1/asa2/sss$l
>2/oso0/isi1/asa4/hsh4l
>2/oso0/isi1/ese3/asa2l
>2/oso0/isi1/ese3/asa4l
>2/oso0/isi1/ese3/hsh4l
>2/oso0/isi1/ese3/sss$l
>2/oso0/isi1/sss$/asa4l
>2/oso0/isi1/sss$/hsh4l
>2/oso0/sss$/asa4/hsh4l
>2/isi1/ese3/asa2/sss$/hsh4l
>2/isi1/ese3/sss$/asa4/hsh4l
>2/lsl1/ese3/asa2/sss$/hsh4l
>2/lsl1/ese3/sss$/asa4/hsh4l
>2/lsl1/isi1/asa2/sss$/hsh4l
>2/lsl1/isi1/ese3/asa2/hsh4l
>2/lsl1/isi1/ese3/asa2/sss$l
>2/lsl1/isi1/ese3/asa4/hsh4l
>2/lsl1/isi1/ese3/sss$/asa4l
>2/lsl1/isi1/ese3/sss$/hsh4l
>2/lsl1/isi1/sss$/asa4/hsh4l
>2/lsl1/oso0/asa2/sss$/hsh4l
>2/lsl1/oso0/ese3/asa2/hsh4l
>2/lsl1/oso0/ese3/asa2/sss$l
>2/lsl1/oso0/ese3/asa4/hsh4l
>2/lsl1/oso0/ese3/sss$/asa4l
>2/lsl1/oso0/ese3/sss$/hsh4l
>2/lsl1/oso0/isi1/asa2/hsh4l
>2/lsl1/oso0/isi1/asa2/sss$l
>2/lsl1/oso0/isi1/asa4/hsh4l
>2/lsl1/oso0/isi1/ese3/asa2l
>2/lsl1/oso0/isi1/ese3/asa4l
>2/lsl1/oso0/isi1/ese3/hsh4l
>2/lsl1/oso0/isi1/ese3/sss$l
>2/lsl1/oso0/isi1/sss$/asa4l
>2/lsl1/oso0/isi1/sss$/hsh4l
>2/lsl1/oso0/sss$/asa4/hsh4l
>2/oso0/ese3/asa2/sss$/hsh4l
>2/oso0/ese3/sss$/asa4/hsh4l
>2/oso0/isi1/asa2/sss$/hsh4l
>2/oso0/isi1/ese3/asa2/hsh4l
>2/oso0/isi1/ese3/asa2/sss$l
>2/oso0/isi1/ese3/asa4/hsh4l
>2/oso0/isi1/ese3/sss$/asa4l
>2/oso0/isi1/ese3/sss$/hsh4l
>2/oso0/isi1/sss$/asa4/hsh4l
>2/lsl1/isi1/ese3/asa2/sss$/hsh4l
>2/lsl1/isi1/ese3/sss$/asa4/hsh4l
>2/lsl1/oso0/ese3/asa2/sss$/hsh4l
>2/lsl1/oso0/ese3/sss$/asa4/hsh4l
>2/lsl1/oso0/isi1/asa2/sss$/hsh4l
>2/lsl1/oso0/isi1/ese3/asa2/hsh4l
>2/lsl1/oso0/isi1/ese3/asa2/sss$l
>2/lsl1/oso0/isi1/ese3/asa4/hsh4l
>2/lsl1/oso0/isi1/ese3/sss$/asa4l
>2/lsl1/oso0/isi1/ese3/sss$/hsh4l
>2/lsl1/oso0/isi1/sss$/asa4/hsh4l
>2/oso0/isi1/ese3/asa2/sss$/hsh4l
>2/oso0/isi1/ese3/sss$/asa4/hsh4l
>2/lsl1/oso0/isi1/ese3/asa2/sss$/hsh4l
>2/lsl1/oso0/isi1/ese3/sss$/asa4/hsh4l
# Bleagh! pant, pant - alec
# Oddly enough, people prefixing passwords with numbers is quite a lot
# rarer than suffixing numbers. Hence, we are further down the file
# before trying this. Oh well, let's nail the buggers anyway...
>2<8l^ :
>2l^0
>2l^1
>2l^2
>2l^3
>2l^4
>2l^5
>2l^6
>2l^7
>2l^8
>2l^9
# Capitalise and then reverse every word (eg: "derF")
>2!?Xcr
# Reverse and then capitalise every alphabetic word (eg: "Derf")
>2rc
# Pure words capitalised with various ejaculatory punctuation added
# eg: "Cats!" for Andrew Floyd-Drebber fans...
>2<8!?Ac$!
>2<8!?Ac$.
>2<8!?Ac$?
# Uppercase words with various things appended or swapped out
>2<8u$!
>2<8u$.
>2<8u$?
>2/OsO0u
# Really weird uppercase variations
>2ud
>2uf
>2ur
# Yes, I know all this looks like line noise, but I haven't put regexp in yet.
acters long, where n = 0-9a-z
# >n = reject word UNLESS it is > n characters long, where n = 0-9a-z
# ^x = prepend character 'x' to word
# $y = append character 'y' to word
# l = force word to be lowercase
# u = force word to be uppercase
# c = force word to be capitalised
# r = reverse word: "Fred" -> "derF"
# d = duplicate Sources/ 40755 5661 132 0 5222357177 6577 5 0 1 0 Sources/Makefile 100600 5661 132 3561 5222357056 11136 0 37777777777 1 0 ###
# Revised Makefile for Crack v4.1 - AEM, Feb 14 1992
###
LIBS=
CFLAGS= -O
PWC= crack-pwc
FCRYPT= crack-fcrypt.o
OBJS= crack-lib.o crack-glob.o crack-supp.o crack-sort.o
UFCLIB= ../ufc-crypt/libufc.a
TRUNS= 1000
###
# The reason for the direct reference to libufc.a is to get round
# obnoxious problems with ranlibbing a file after copying it on some
# architectures.
###
$(PWC).which:
@echo Choosing between Crack.fcrypt and Crack.ufc
-((../Scripts/do_ufc && make $(PWC).ufc) || make $(PWC).fcrypt)
$(PWC).fcrypt: $(OBJS) $(FCRYPT) $(PWC).o
$(CC) $(CFLAGS) -o $(PWC) $(PWC).o $(OBJS) $(FCRYPT) $(LIBS)
$(PWC).ufc: $(OBJS) $(PWC).o
$(CC) $(CFLAGS) -o $(PWC) $(PWC).o $(OBJS) $(UFCLIB) $(LIBS)
testrule: testrule.o crack-lib.o
$(CC) $(CFLAGS) -o $@ testrule.o crack-lib.o
tester: tester.o $(OBJS) $(FCRYPT)
$(CC) $(CFLAGS) -o $@ tester.o $(OBJS) $(FCRYPT)
speedufc: speeds.c $(OBJS) $(UFC)
../Scripts/do_ufc
$(CC) $(CFLAGS) -DT1 -o $@ speeds.c $(OBJS) $(UFCLIB)
speedfcrypt: speeds.c $(OBJS) $(FCRYPT)
$(CC) $(CFLAGS) -DT1 -o $@ speeds.c $(OBJS) $(FCRYPT)
speedxform: speeds.c $(OBJS) $(FCRYPT)
$(CC) $(CFLAGS) -DT2 -o $@ speeds.c $(OBJS) $(FCRYPT)
speedcrypt: speeds.c $(OBJS) $(FCRYPT)
$(CC) $(CFLAGS) -o $@ speeds.c $(OBJS) $(FCRYPT)
tests: tester speedcrypt speedfcrypt speedxform speedufc
-tester $(TRUNS)
-speedcrypt
-speedfcrypt
-speedxform
-speedufc
bytesex: bytesex.o
$(CC) $(CFLAGS) -o $@ bytesex.o
$(FCRYPT): crack-fcrypt.c crack.h bytesex
$(CC) $(CFLAGS) `./bytesex` -c crack-fcrypt.c
$(PWC).o: crack.h conf.h
crack-glob.o: crack.h
crack-lib.o: crack.h conf.h
crack-sort.o: crack.h
crack-supp.o: crack.h conf.h
testrule.o: crack.h
crack.h: crack-glob.h
touch crack.h
conf.h:
clean:
-rm -f *.o *.u *.a *.pixie *.Addrs *.Counts
-rm -f $(PWC) tester bytesex testrule
-rm -f speedcrypt speedfcrypt speedxform speedufc
ic word lowercase and try it
# NOT-CONTAIN ANY NON-ALPHA, LOWERCASE
!?Al
# Pluralise every significant one of the above
# MORE-THAN 2, NOT-CONSources/bytesex.c 100600 5661 132 1064 5222357057 11322 0 37777777777 1 0 #include <stdio.h>
main ()
{
char *p;
long int l;
l = 'a' << 24 | 'b' << 16 | 'c' << 8 | 'd';
p = (char *) &l;
if (sizeof (long int) == 4)
{
#ifndef GCC /* gcc tends to make a botch of it */
puts ("-DFDES_4BYTE");
#endif
} else if (sizeof (long int) == 8)
{
puts ("-DFDES_8BYTE");
l <<= 32;
} else
{
printf ("-DFDES_%dBYTE%c", sizeof (long int), 10);
}
if (!strncmp (p, "abcd", 4))
{
puts ("-DBIG_ENDIAN");
} else if (!strncmp (p, "dcba", 4))
{
puts ("-DLITTLE_ENDIAN");
}
exit (0);
}
Y VOWEL, PURGE ANY VOWEL, MORE-THAN 3
!?A/?v@?v>3
# Look, I'm getting really bored of this monotone uppercase typing, so
# if it's OK with you, I'll drop the commentaries on each rule. You
# should have got the idea by now...
# Longish pure words lowercased and reflected
>2!?Alf
# Words containing whitespace, which is then squeezed out
/?w@?w>3
# In a similar vein, words with punctuation, squeezed out
/?p@?p>3
# Reasonably short words, duplicated. eg:Sources/conf.h 100600 5661 132 4232 5222357061 10564 0 37777777777 1 0 /*
* 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.
*/
#undef DEVELOPMENT_VERSION
/*
* define this symbol if you are on a system where you don't have the
* strchr() function in your standard library (usually this means you are on
* a BSD based system with no System 5isms) but you DO have the equivalent
* index() function.
*/
#undef INDEX_NOT_STRCHR
/*
* define this if you have a smart toupper() and tolower() (a-la ANSI), which
* do not generate barf when something which is not a lowercase letter is
* uppercased, or vice-versa (a-la K&R). Check your manpage or leave it
* undefined
*/
#undef FAST_TOCASE
/*
* define this if you are on a Sys V type system with a uname() system call
* AND YOU HAVE NO gethostname() - it fakes up a BSD gethostname() so you can
* use CRACK_NETWORK; see crack-port.c
*/
#undef CRACK_UNAME
/*
* define CRACK_DOTFILES if you want to search the first 1Kb segment of users
* .plan/.project/.signature files for potential passwords.
*
* define CRACK_DOTSANE to likewise do (possibly non-portable) sanity testing
* on the dotfiles before opening them (check that they are not named pipes,
* etc...)
*/
#undef CRACK_DOTFILES
#undef CRACK_DOTSANE
/*
* define "COMPRESSION" if you have enabled compression in the Crack
* Shellscript
*
* this is enabled by default if you have /usr/ucb/compress; change the pathname
* of the $compress variable in the Crack script if you use another pathname
* to get to "compress" and then put the path name of the "pipe to stdout"
* version of the compression prog here.
*/
#define COMPRESSION
#define ZCAT "/usr/ucb/zcat" /* as in "zcat Dicts/bigdict.Z" */
#define PCAT "/usr/bin/pcat"
/*
* define this if you are using fcrypt() - you might not want to if fcrypt()
* doesn't work properly
*/
#define FCRYPT
/oso0/isi1/asa2/sss$l
>2/oso0/isi1/asa4/hsh4l
>2/oso0/isi1/ese3/asa2l
>2/oso0/isi1/ese3/asa4l
>2/oso0/isi1/ese3/hsh4l
>2/oso0/isi1/ese3/sss$l
>2/oso0/isi1/sss$/asa4l
>2/oso0/isi1/sss$/hsh4l
>2/oso0/sss$/asa4/hsh4l
>2/isi1/ese3/asa2/sss$/hsh4l
>2/isi1/ese3/sss$/asa4/hsh4l
>2/lsl1/ese3/asa2/sss$/hsh4l
>2/lsl1/ese3/sss$/asa4/hsh4l
>2/lsl1/isi1/asa2/sss$/hsh4lSources/crack-glob.c 100600 5661 132 2554 5222357062 11644 0 37777777777 1 0 #include "crack.h"
char version[] = "4.1f"; /* version of prog */
char runtime[] = "Runtime";
char feedback_string[] = "!fb!";
char rulefile[] = "Scripts/dicts.rules";
char gecosfile[] = "Scripts/gecos.rules";
char nastygram[] = "Scripts/nastygram";
char zcat[] = ZCAT;
char pcat[] = PCAT;
/* runtime variable declarations */
int pid; /* current process ID */
int pwlength = 8; /* significant length of a password */
struct USER *userroot; /* root of linked list of users */
struct RULE *ruleroot; /* root of linked list of rules */
struct RULE *gecosroot; /* root of linked list of (gecos) rules */
struct DICT *dictroot; /* root of linked list of words */
/* datafile variables */
char diefile[STRINGSIZE]; /* where die output goes... */
char feedbackfile[STRINGSIZE]; /* where feedback ouytput goes */
char opfile[STRINGSIZE]; /* where Log() output goes */
char pointfile[STRINGSIZE]; /* checkpointing */
char this_hostname[STRINGSIZE]; /* gethostname() hack */
/* recover variables */
char old_hostname[STRINGSIZE]; /* next 4 vars used in recovery */
char old_dictname[STRINGSIZE];
char old_rule[STRINGSIZE];
int old_usernum;
char old_username[STRINGSIZE];
/* switches */
char input_file[STRINGSIZE];
int foreground_bool;
int remote_bool;
int nice_value;
int recover_bool;
char recover_file[STRINGSIZE];
int verbose_bool;
char supplied_name[STRINGSIZE];
int mail_bool;
latory punctuation added
# eg: "Cats!" for Andrew Floyd-Drebber fans...
>2<8!?Ac$!
>2<8!?Ac$.
>2<8!?Ac$?
# Uppercase words with various things appeSources/crack-glob.h 100600 5661 132 1676 5222357064 11657 0 37777777777 1 0 extern char version[];
extern char runtime[];
extern char feedback_string[];
extern char rulefile[];
extern char gecosfile[];
extern char nastygram[];
extern char zcat[];
extern char pcat[];
extern int pid;
extern int pwlength;
extern struct USER *userroot;
extern struct RULE *ruleroot;
extern struct RULE *gecosroot;
extern struct DICT *dictroot;
extern char diefile[STRINGSIZE];
extern char feedbackfile[STRINGSIZE];
extern char opfile[STRINGSIZE];
extern char pointfile[STRINGSIZE];
extern char this_hostname[STRINGSIZE];
extern char old_hostname[STRINGSIZE];
extern char old_dictname[STRINGSIZE];
extern char old_rule[STRINGSIZE];
extern int old_usernum;
extern char old_username[STRINGSIZE];
extern char input_file[STRINGSIZE];
extern int foreground_bool;
extern int remote_bool;
extern int nice_value;
extern int recover_bool;
extern char recover_file[STRINGSIZE];
extern int verbose_bool;
extern char supplied_name[STRINGSIZE];
extern int mail_bool;
Sources/crack-supp.c 100600 5661 132 6521 5222357066 11712 0 37777777777 1 0 /*
* 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"
#ifdef CRACK_UNAME
#ifndef AMIGA
#include <sys/utsname.h>
int
gethostname (name, namelen)
char *name;
int namelen;
{
struct utsname uts;
if (uname (&uts))
{
return (-1);
}
strncpy (name, uts.nodename, namelen - 1);
return (0);
}
#else
int
gethostname (name, namelen)
char *name;
int namelen;
{
strncpy (name, "dougal", namelen);
return (0);
}
#endif /* AMIGA */
#endif /* CRACK_UNAME */
/* log anything to datafile. */
void
Log (fmt, a, b, c, d, e, f, g, h, i, j)
char *fmt;
long int a, b, c, d, e, f, g, h, i, j;
{
long t;
time (&t);
printf ("pwc: %-15.15s ", ctime (&t) + 4);
printf (fmt, a, b, c, d, e, f, g, h, i, j);
fflush (stdout);
}
/* print a guess, giving a single place to mod where necessary */
void
PrintGuess (eptr, guess)
register struct USER *eptr;
char *guess;
{
eptr -> done = 1;
eptr -> passwd_txt = Clone (guess); /* ESSENTIAL to FeedBack() */
if (!eptr -> passwd_txt)
{
eptr -> passwd_txt = "<Ran out of memory logging this password>";
}
Log ("Guessed %s%s (%s in %s) [%s] %s\n",
(eptr -> passwd.pw_uid ? "" : "ROOT PASSWORD "),
eptr -> passwd.pw_name,
eptr -> passwd.pw_shell,
eptr -> filename,
guess,
eptr -> passwd.pw_passwd);
if (mail_bool)
{
char dobuff[STRINGSIZE];
sprintf (dobuff, "%s %s", nastygram, eptr -> passwd.pw_name);
system (dobuff);
}
}
/* write a pointfile out */
int
SetPoint (dict, rule, usernum, username)
char *dict;
char *rule;
int usernum;
char *username;
{
FILE *fp;
long t;
if (!(fp = fopen (pointfile, "w")))
{
perror (pointfile);
return (-1);
}
time (&t);
fprintf (fp, "host=%s pid=%d pointtime=%s", this_hostname, pid, ctime (&t));
fprintf (fp, "%s\n", this_hostname);
fprintf (fp, "%s\n", dict);
fprintf (fp, "%s\n", rule);
fprintf (fp, "%d\n", usernum);
fprintf (fp, "%s\n", username);
fclose (fp);
return (0);
}
/* read a pointfile in... */
int
GetPoint (pf)
char *pf;
{
FILE *fp;
char buffer[STRINGSIZE];
if (!(fp = fopen (pf, "r")))
{
perror (pf);
return (-1);
}
/* junk */
if (!fgets (buffer, STRINGSIZE, fp))
{
return (-2);
}
/* hostname */
if (!fgets (old_hostname, STRINGSIZE, fp))
{
return (-3);
}
/* dictname */
if (!fgets (old_dictname, STRINGSIZE, fp))
{
return (-4);
}
/* rule */
if (!fgets (old_rule, STRINGSIZE, fp))
{
return (-5);
}
/* usernum */
if (!fgets (buffer, STRINGSIZE, fp))
{
return (-6);
}
/* username */
if (!fgets (old_username, STRINGSIZE, fp))
{
return (-7);
}
Trim (old_hostname);
if (strcmp (old_hostname, this_hostname))
{
return (-8);
}
Trim (old_dictname);
Trim (old_rule);
old_usernum = atoi (buffer);
Trim (old_username);
fclose (fp);
return (0);
}
1 0 Sources/crack.h 100600 5661 132 3415 5222357067 10732 0 37777777777 1 0 /*
* 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 <stdio.h>
#include <ctype.h>
#include <pwd.h>
#include <signal.h>
#include "conf.h"
#define STRINGSIZE 256
#ifdef DEVELOPMENT_VERSION
#define BUILTIN_CLEAR
#undef BRAINDEAD6
#define CRACK_UNAME
#endif
extern void Trim ();
extern char *Reverse ();
extern char *Uppercase ();
extern char *Lowercase ();
extern char *Clone ();
extern char *Mangle ();
extern int gethostname ();
#ifdef FAST_TOCASE
#define CRACK_TOUPPER(x) (toupper(x))
#define CRACK_TOLOWER(x) (tolower(x))
#else
#define CRACK_TOUPPER(x) (islower(x) ? toupper(x) : (x))
#define CRACK_TOLOWER(x) (isupper(x) ? tolower(x) : (x))
#endif
#ifdef FCRYPT
#define crypt(a,b) fcrypt(a,b)
#endif
#ifdef INDEX_NOT_STRCHR
#define strchr(a,b) index(a,b)
#endif
struct USER
{
struct USER *next; /* next users with different salt */
struct USER *across; /* line of users with same salt */
char *filename; /* where we got it from */
char *passwd_txt; /* plaintext of password */
struct passwd passwd; /* ...guess... */
int done; /* bool flag */
};
struct DICT
{
struct DICT *next; /* simple linked list */
char word[1]; /* ...<snigger>... */
};
/* include lyrics of "perfect circle" by R.E.M. at this point */
struct RULE
{
struct RULE *next;
char *rule;
};
#define STRCMP(x,y) ( *(x) == *(y) ? strcmp((x),(y)) : -1 )
#include "crack-glob.h"
4l
>2/oso0/isi1/ese3/sss$l
>2/oso0/isi1/sss$/asa4l
>2/oso0/isi1/sss$/hsh4l
>2/oso0/sss$/asa4/hsh4l
>2/isi1/ese3/asa2/sss$/hsh4l
>2/isi1/ese3/sss$/asa4/hsh4l
>2/lsl1/ese3/asa2/sss$/hsh4l
>2/lsl1/ese3/sss$/asa4/hsh4l
>2/lsl1/isi1/asa2/sss$/hsh4lSources/speeds.c 100600 5661 132 3536 5222357071 11124 0 37777777777 1 0 /*
* 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.
*/
/* Cray portions Copyright (c) 1992 Tom Hutton. */
#ifdef cray
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <ctype.h>
#else
#include <sys/time.h>
#include <signal.h>
#endif
#include <stdio.h>
#ifdef cray
/*
* Clocks to seconds and seconds to clocks
*/
#define CTOS(X) ((long) ((unsigned) (X) / (long) hz))
#define STOC(X) ((long) ((X) * hz))
static long hz;
#endif
static int cnt;
#define ITIME 10 /* Number of seconds to run test. */
void
Stop ()
{
printf ("Did %f %s()s per second.\n",
((float) cnt) / ((float) ITIME),
#ifdef T1
"fcrypt"
#else
#ifdef T2
"XForm"
#else
"crypt"
#endif
#endif
);
exit (0);
}
main ()
{
#ifdef cray
static long vtime;
#else
struct itimerval itv;
#endif
static int quarters[4];
#ifdef cray
hz = sysconf(_SC_CLK_TCK); /* get # ticks per second */
vtime = STOC(ITIME);
#else
bzero (&itv, sizeof (itv));
#endif
printf ("Running for %d seconds of virtual time ...\n", ITIME);
#if defined(T1) || defined(T2)
init_des ();
#endif
#ifdef cray
for (cnt = 0;cpused() <= vtime; cnt++)
#else
signal (SIGVTALRM, Stop);
itv.it_value.tv_sec = ITIME;
itv.it_value.tv_usec = 0;
setitimer (ITIMER_VIRTUAL, &itv, NULL);
for (cnt = 0;; cnt++)
#endif
{
#ifdef T1
fcrypt ("fredfred", "eek");
#else
#ifdef T2
XForm (quarters, 0);
#else
crypt ("fredfred", "eek");
#endif
#endif
}
Stop();
}
0 Sources/tester.c 100600 5661 132 1200 5222357072 11132 0 37777777777 1 0 #include <stdio.h>
#include <time.h>
main (argc, argv)
int argc;
char *argv[];
{
register int i;
long int t;
if (argc < 2)
{
exit (1);
}
init_des ();
printf ("%s\n", fcrypt ("fredfred", "fredfred"));
if (strcmp (fcrypt ("fredfred", "fredfred"), "frxWbx4IRuBBA"))
{
printf ("Version of fcrypt() is not compatible with standard.\n");
exit (0);
}
i = atoi (argv[1]);
printf ("Doing %d fcrypts()\n", i);
time (&t);
printf ("%s", ctime (&t));
while (i--)
{
fcrypt ("fredfred", "fredfred");
}
time (&t);
printf ("%s", ctime (&t));
return (0);
}
6521 5222357066 11712 0 37777777777 1 0 Sources/testrule.c 100600 5661 132 1005 5222357073 11477 0 37777777777 1 0 #include "crack.h"
void
Log (a, b, c, d, e, f, g)
char *a, b, c, d, e, f, g;
{
printf (a, b, c, d, e, f, g);
}
int
main (argc, argv)
int argc;
char *argv[];
{
int i;
char *ptr;
char buffer[STRINGSIZE];
while (!feof (stdin))
{
fgets (buffer, STRINGSIZE - 1, stdin);
Trim (buffer);
for (i = 1; i < argc; i++)
{
ptr = Mangle (buffer, argv[i]);
printf ("'%s'('%s') = '%s'\n",
argv[i],
buffer,
ptr ? ptr : "(rejected)");
}
}
return (0);
}
g, h, i, j;
{
long t;
time (&t);
printf ("pwc: %-15.15s ", ctime (&t) + 4);
printf (fmt, a, b, c, d, e, f, g, h, i, j);
fflush (stdout);
}
/* print a guess, giving a single place to mod where necessary */
void
PrintGuess (eptr, guess)
register struct USER *eptr;
char *guess;
{
eptr -> done = 1;
eptr -> passwd_txt = Clone (guess); /* ESSENTIAL to FeedBack() */
if (!eptr -> passwd_txt)
{
eptr -> passwd_txt = "<Ran out of memory logging this password>";
Sources/crack-sort.c 100600 5661 132 12407 5222357143 11726 0 37777777777 1 0 #include "crack.h"
#define Compare(a,b) (strcmp(a,b))
/*
* Sort a list of struct DICT by using an iterative bottom-up merge sort.
* This particular piece of code took me ages to do (well, 2 days + 3 weeks
* research) and provides a FAST way of sorting a linked list without the
* overhead of increasing memory usage via malloc() or brk(). Why ? Because I
* have to assume that there is no more memory, thats why. It's all Brian
* Thompsett's fault! Really! Filling the swapspace on a SparcStation2 and
* expecting Crack to survive! Argh! 8-)
*/
/* Since this code is so nice, I'll comment it fairly thoroughly */
struct DICT *
SortDict (chain3, listlength)
register struct DICT *chain3;
long int listlength;
{
/* misc counters */
register int i;
long int discarded;
/* 2^n for n = 0..x */
long int n;
/* head of the first extracted subchain */
register struct DICT *chain1;
/* head of second subchain */
register struct DICT *chain2;
/* useful temp pointer */
register struct DICT *scratch;
/* PTR TO ELEMENT containing TAIL of unsorted list pre-merging */
struct DICT *lead_in;
/* PTR TO HEAD of unsorted list after extracting chains */
struct DICT *lead_out;
/* dummy structures used as fenceposts */
struct DICT dummy1;
struct DICT dummy2;
/* Put the incoming list into 'dummy1' posthole */
dummy1.next = chain3;
/* For values of n = 2^(0..30) limited by listlength */
for (n = 1L; n < listlength; n *= 2)
{
/* Store place to get/put head of list in 'lead_in' */
lead_in = &dummy1;
/* Set chain1 to the head of unsorted list */
for (chain1 = lead_in -> next; chain1; chain1 = lead_in -> next)
{
/* Break connection head and chain1 */
lead_in -> next = (struct DICT *) 0;
/* Extract up to length 'n', park on last element before chain2 */
for (i = n - 1, scratch = chain1;
i && scratch -> next;
scratch = scratch -> next)
{
i--;
};
/* If chain1 is undersized/exact, there is no chain2 */
if (i || !scratch -> next)
{
/* put chain1 back where you got it and break */
lead_in -> next = chain1;
break;
}
/* Get pointer to head of chain2 */
chain2 = scratch -> next;
/* Break connection between chain1 & chain2 */
scratch -> next = (struct DICT *) 0;
/* Extract up to length 'n', park on last element of chain2 */
for (i = n - 1, scratch = chain2;
i && scratch -> next;
scratch = scratch -> next)
{
i--;
};
/* Even if it's NULL, store rest of list in 'lead_out' */
lead_out = scratch -> next;
/* Break connection between chain2 & tail of unsorted list */
scratch -> next = (struct DICT *) 0;
/* Now, mergesort chain1 & chain2 to chain3 */
/* Set up dummy list fencepost */
chain3 = &dummy2;
chain3 -> next = (struct DICT *) 0;
/* While there is something in each list */
while (chain1 && chain2)
{
/* Compare them */
i = Compare (chain1 -> word, chain2 -> word);
if (i < 0)
{
/* a < b */
chain3 -> next = chain1;
chain3 = chain1;
chain1 = chain1 -> next;
} else if (i > 0)
{
/* a > b */
chain3 -> next = chain2;
chain3 = chain2;
chain2 = chain2 -> next;
} else
{
/*
* a == b. Link them both in. Don't try to get rid of the
* multiple copies here, because if you free up any
* elements at this point the listsize changes and the
* algorithm runs amok.
*/
chain3 -> next = chain1;
chain3 = chain1;
chain1 = chain1 -> next;
chain3 -> next = chain2;
chain3 = chain2;
chain2 = chain2 -> next;
}
}
/*
* Whatever is left is sorted and therefore linkable straight
* onto the end of the current list.
*/
if (chain1)
{
chain3 -> next = chain1;
} else
{
chain3 -> next = chain2;
}
/* Skip to the end of the sorted list */
while (chain3 -> next)
{
chain3 = chain3 -> next;
}
/* Append this lot to where you got chain1 from ('lead_in') */
lead_in -> next = dummy2.next;
/* Append rest of unsorted list to chain3 */
chain3 -> next = lead_out;
/* Set 'lead_in' for next time to last element of 'chain3' */
lead_in = chain3;
}
}
/* Now, Uniq the list */
discarded = 0;
/* Chain1 to the head of the list, Chain2 to the next */
chain1 = dummy1.next;
chain2 = chain1 -> next;
/* While not at end of list */
while (chain2)
{
/* Whilst (chain1) == (chain2) */
while (!Compare (chain1 -> word, chain2 -> word))
{
/* Bump the discard count */
discarded++;
/* Store the next element */
scratch = chain2 -> next;
/* Get some memory back */
free (chain2); /* ...<snigger>... */
/* Assign the skip, break if you run off the end of list */
if (!(chain2 = scratch))
{
break;
}
}
/* Set comparison ptr to new element or terminate */
chain1 -> next = chain2;
/* If not terminated */
if (chain2)
{
/* set the compared pointer to its successor */
chain1 = chain2;
chain2 = chain2 -> next;
}
}
Log ("Sort discarded %ld words; FINAL DICTIONARY SIZE: %ld\n",
discarded,
listlength - discarded);
return (dummy1.next);
}
z))
#define STOC(X) ((long) ((X) * hz))
static long hz;
#endif
static int cnt;
#define ITIME 10 /* Number of seconds to run test. */
void
Stop ()
{
printf ("Did %f %s()s per second.\n",
((float) cnt) / ((float) ITIME),
#ifdef T1
"Sources/crack-lib.c 100600 5661 132 33430 5222357151 11503 0 37777777777 1 0 /*
* 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 RULE_NOOP ':'
#define RULE_PREPEND '^'
#define RULE_APPEND '$'
#define RULE_REVERSE 'r'
#define RULE_UPPERCASE 'u'
#define RULE_LOWERCASE 'l'
#define RULE_PLURALISE 'p'
#define RULE_CAPITALISE 'c'
#define RULE_DUPLICATE 'd'
#define RULE_REFLECT 'f'
#define RULE_SUBSTITUTE 's'
#define RULE_MATCH '/'
#define RULE_NOT '!'
#define RULE_LT '<'
#define RULE_GT '>'
#define RULE_EXTRACT 'x'
#define RULE_OVERSTRIKE 'o'
#define RULE_INSERT 'i'
#define RULE_EQUALS '='
#define RULE_PURGE '@'
#define RULE_CLASS '?' /* class rule? socialist ethic in cracker? */
void
Trim (string) /* remove trailing whitespace from a string */
register char *string;
{
register char *ptr;
for (ptr = string; *ptr; ptr++);
while ((--ptr >= string) && isspace (*ptr));
*(++ptr) = '\0';
}
char *
Clone (string)
char *string;
{
register char *retval;
retval = (char *) malloc (strlen (string) + 1);
if (retval)
{
strcpy (retval, string);
}
return (retval);
}
int
Suffix (word, suffix)
char *word;
char *suffix;
{
register int i;
register int j;
i = strlen (word);
j = strlen (suffix);
if (i > j)
{
return (STRCMP ((word + i - j), suffix));
} else
{
return (-1);
}
}
char *
Reverse (str) /* return a pointer to a reversal */
register char *str;
{
register int i;
register int j;
static char area[STRINGSIZE];
j = i = strlen (str);
while (*str)
{
area[--i] = *str++;
}
area[j] = '\0';
return (area);
}
char *
Uppercase (str) /* return a pointer to an uppercase */
register char *str;
{
register char *ptr;
static char area[STRINGSIZE];
ptr = area;
while (*str)
{
*(ptr++) = CRACK_TOUPPER (*str);
str++;
}
*ptr = '\0';
return (area);
}
char *
Lowercase (str) /* return a pointer to an lowercase */
register char *str;
{
register char *ptr;
static char area[STRINGSIZE];
ptr = area;
while (*str)
{
*(ptr++) = CRACK_TOLOWER (*str);
str++;
}
*ptr = '\0';
return (area);
}
char *
Capitalise (str) /* return a pointer to an capitalised */
register char *str;
{
register char *ptr;
static char area[STRINGSIZE];
ptr = area;
while (*str)
{
*(ptr++) = CRACK_TOLOWER (*str);
str++;
}
*ptr = '\0';
area[0] = CRACK_TOUPPER (area[0]);
return (area);
}
char *
Pluralise (string) /* returns a pointer to a plural */
register char *string;
{
register int length;
static char area[STRINGSIZE];
length = strlen (string);
strcpy (area, string);
if (!Suffix (string, "ch") ||
!Suffix (string, "ex") ||
!Suffix (string, "ix") ||
!Suffix (string, "sh") ||
!Suffix (string, "ss"))
{
/* bench -> benches */
strcat (area, "es");
} else if (length > 2 && string[length - 1] == 'y')
{
if (strchr ("aeiou", string[length - 2]))
{
/* alloy -> alloys */
strcat (area, "s");
} else
{
/* gully -> gullies */
strcpy (area + length - 1, "ies");
}
} else if (string[length - 1] == 's')
{
/* bias -> biases */
strcat (area, "es");
} else
{
/* catchall */
strcat (area, "s");
}
return (area);
}
char *
Substitute (string, old, new) /* returns pointer to a swapped about copy */
register char *string;
register char old;
register char new;
{
register char *ptr;
static char area[STRINGSIZE];
ptr = area;
while (*string)
{
*(ptr++) = (*string == old ? new : *string);
string++;
}
*ptr = '\0';
return (area);
}
char *
Purge (string, target) /* returns pointer to a purged copy */
register char *string;
register char target;
{
register char *ptr;
static char area[STRINGSIZE];
ptr = area;
while (*string)
{
if (*string != target)
{
*(ptr++) = *string;
}
string++;
}
*ptr = '\0';
return (area);
}
/* -------- CHARACTER CLASSES START HERE -------- */
/*
* this function takes two inputs, a class identifier and a character, and
* returns non-null if the given character is a member of the class, based
* upon restrictions set out below
*/
int
MatchClass (class, input)
register char class;
register char input;
{
register char c;
register int retval;
retval = 0;
switch (class)
{
/* ESCAPE */
case '?': /* ?? -> ? */
if (input == '?')
{
retval = 1;
}
break;
/* ILLOGICAL GROUPINGS (ie: not in ctype.h) */
case 'V':
case 'v': /* vowels */
c = CRACK_TOLOWER (input);
if (strchr ("aeiou", c))
{
retval = 1;
}
break;
case 'C':
case 'c': /* consonants */
c = CRACK_TOLOWER (input);
if (strchr ("bcdfghjklmnpqrstvwxyz", c))
{
retval = 1;
}
break;
case 'W':
case 'w': /* whitespace */
if (strchr ("\t ", input))
{
retval = 1;
}
break;
case 'P':
case 'p': /* punctuation */
if (strchr (".`,:;'!?\"", input))
{
retval = 1;
}
break;
case 'S':
case 's': /* symbols */
if (strchr ("$%%^&*()-_+=|\\[]{}#@/~", input))
{
retval = 1;
}
break;
/* LOGICAL GROUPINGS */
case 'L':
case 'l': /* lowercase */
if (islower (input))
{
retval = 1;
}
break;
case 'U':
case 'u': /* uppercase */
if (isupper (input))
{
retval = 1;
}
break;
case 'A':
case 'a': /* alphabetic */
if (isalpha (input))
{
retval = 1;
}
break;
case 'X':
case 'x': /* alphanumeric */
if (isalnum (input))
{
retval = 1;
}
break;
case 'D':
case 'd': /* digits */
if (isdigit (input))
{
retval = 1;
}
break;
default:
Log ("MatchClass: unknown class %c\n", class);
return (0);
break;
}
if (isupper (class))
{
return (!retval);
}
return (retval);
}
char *
PolyStrchr (string, class)
register char *string;
register char class;
{
while (*string)
{
if (MatchClass (class, *string))
{
return (string);
}
string++;
}
return ((char *) 0);
}
char *
PolySubst (string, class, new) /* returns pointer to a swapped about copy */
register char *string;
register char class;
register char new;
{
register char *ptr;
static char area[STRINGSIZE];
ptr = area;
while (*string)
{
*(ptr++) = (MatchClass (class, *string) ? new : *string);
string++;
}
*ptr = '\0';
return (area);
}
char *
PolyPurge (string, class) /* returns pointer to a purged copy */
register char *string;
register char class;
{
register char *ptr;
static char area[STRINGSIZE];
ptr = area;
while (*string)
{
if (!MatchClass (class, *string))
{
*(ptr++) = *string;
}
string++;
}
*ptr = '\0';
return (area);
}
/* -------- BACK TO NORMALITY -------- */
int
Char2Int (character)
char character;
{
if (isdigit (character))
{
return (character - '0');
} else if (islower (character))
{
return (character - 'a' + 10);
} else if (isupper (character))
{
return (character - 'A' + 10);
}
return (-1);
}
char *
Mangle (input, control) /* returns a pointer to a controlled Mangle */
char *input;
char *control;
{
int limit;
register char *ptr;
static char area[STRINGSIZE];
char area2[STRINGSIZE];
area[0] = '\0';
strcpy (area, input);
for (ptr = control; *ptr; ptr++)
{
switch (*ptr)
{
case RULE_NOOP:
break;
case RULE_REVERSE:
strcpy (area, Reverse (area));
break;
case RULE_UPPERCASE:
strcpy (area, Uppercase (area));
break;
case RULE_LOWERCASE:
strcpy (area, Lowercase (area));
break;
case RULE_CAPITALISE:
strcpy (area, Capitalise (area));
break;
case RULE_PLURALISE:
strcpy (area, Pluralise (area));
break;
case RULE_REFLECT:
strcat (area, Reverse (area));
break;
case RULE_DUPLICATE:
strcpy (area2, area);
strcat (area, area2);
break;
case RULE_GT:
if (!ptr[1])
{
Log ("Mangle: '>' missing argument in '%s'\n", control);
return ((char *) 0);
} else
{
limit = Char2Int (*(++ptr));
if (limit < 0)
{
Log ("Mangle: '>' weird argument in '%s'\n", control);
return ((char *) 0);
}
if (strlen (area) <= limit)
{
return ((char *) 0);
}
}
break;
case RULE_LT:
if (!ptr[1])
{
Log ("Mangle: '<' missing argument in '%s'\n", control);
return ((char *) 0);
} else
{
limit = Char2Int (*(++ptr));
if (limit < 0)
{
Log ("Mangle: '<' weird argument in '%s'\n", control);
return ((char *) 0);
}
if (strlen (area) >= limit)
{
return ((char *) 0);
}
}
break;
case RULE_PREPEND:
if (!ptr[1])
{
Log ("Mangle: prepend missing argument in '%s'\n", control);
return ((char *) 0);
} else
{
area2[0] = *(++ptr);
strcpy (area2 + 1, area);
strcpy (area, area2);
}
break;
case RULE_APPEND:
if (!ptr[1])
{
Log ("Mangle: append missing argument in '%s'\n", control);
return ((char *) 0);
} else
{
register char *string;
string = area;
while (*(string++));
string[-1] = *(++ptr);
*string = '\0';
}
break;
case RULE_EXTRACT:
if (!ptr[1] || !ptr[2])
{
Log ("Mangle: extract missing argument in '%s'\n", control);
return ((char *) 0);
} else
{
register int i;
int start;
int length;
start = Char2Int (*(++ptr));
length = Char2Int (*(++ptr));
if (start < 0 || length < 0)
{
Log ("Mangle: extract: weird argument in '%s'\n", control);
return ((char *) 0);
}
strcpy (area2, area);
for (i = 0; length-- && area2[start + i]; i++)
{
area[i] = area2[start + i];
}
/* cant use strncpy() - no trailing NUL */
area[i] = '\0';
}
break;
case RULE_OVERSTRIKE:
if (!ptr[1] || !ptr[2])
{
Log ("Mangle: overstrike missing argument in '%s'\n", control);
return ((char *) 0);
} else
{
register int i;
i = Char2Int (*(++ptr));
if (i < 0)
{
Log ("Mangle: overstrike weird argument in '%s'\n",
control);
return ((char *) 0);
} else
{
++ptr;
if (area[i])
{
area[i] = *ptr;
}
}
}
break;
case RULE_INSERT:
if (!ptr[1] || !ptr[2])
{
Log ("Mangle: insert missing argument in '%s'\n", control);
return ((char *) 0);
} else
{
register int i;
register char *p1;
register char *p2;
i = Char2Int (*(++ptr));
if (i < 0)
{
Log ("Mangle: insert weird argument in '%s'\n",
control);
return ((char *) 0);
}
p1 = area;
p2 = area2;
while (i && *p1)
{
i--;
*(p2++) = *(p1++);
}
*(p2++) = *(++ptr);
strcpy (p2, p1);
strcpy (area, area2);
}
break;
/* THE FOLLOWING RULES REQUIRE CLASS MATCHING */
case RULE_PURGE: /* @x or @?c */
if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
{
Log ("Mangle: delete missing arguments in '%s'\n", control);
return ((char *) 0);
} else if (ptr[1] != RULE_CLASS)
{
strcpy (area, Purge (area, *(++ptr)));
} else
{
strcpy (area, PolyPurge (area, ptr[2]));
ptr += 2;
}
break;
case RULE_SUBSTITUTE: /* sxy || s?cy */
if (!ptr[1] || !ptr[2] || (ptr[1] == RULE_CLASS && !ptr[3]))
{
Log ("Mangle: subst missing argument in '%s'\n", control);
return ((char *) 0);
} else if (ptr[1] != RULE_CLASS)
{
strcpy (area, Substitute (area, ptr[1], ptr[2]));
ptr += 2;
} else
{
strcpy (area, PolySubst (area, ptr[2], ptr[3]));
ptr += 3;
}
break;
case RULE_MATCH: /* /x || /?c */
if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
{
Log ("Mangle: '/' missing argument in '%s'\n", control);
return ((char *) 0);
} else if (ptr[1] != RULE_CLASS)
{
if (!strchr (area, *(++ptr)))
{
return ((char *) 0);
}
} else
{
if (!PolyStrchr (area, ptr[2]))
{
return ((char *) 0);
}
ptr += 2;
}
break;
case RULE_NOT: /* !x || !?c */
if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2]))
{
Log ("Mangle: '!' missing argument in '%s'\n", control);
return ((char *) 0);
} else if (ptr[1] != RULE_CLASS)
{
if (strchr (area, *(++ptr)))
{
return ((char *) 0);
}
} else
{
if (PolyStrchr (area, ptr[2]))
{
return ((char *) 0);
}
ptr += 2;
}
break;
/*
* alternative use for a boomerang, number 1: a standard throwing
* boomerang is an ideal thing to use to tuck the sheets under
* the mattress when making your bed. The streamlined shape of
* the boomerang allows it to slip easily 'twixt mattress and
* bedframe, and it's curve makes it very easy to hook sheets
* into the gap.
*/
case RULE_EQUALS: /* =nx || =n?c */
if (!ptr[1] || !ptr[2] || (ptr[2] == RULE_CLASS && !ptr[3]))
{
Log ("Mangle: '=' missing argument in '%s'\n", control);
return ((char *) 0);
} else
{
register int i;
if ((i = Char2Int (ptr[1])) < 0)
{
Log ("Mangle: '=' weird argument in '%s'\n", control);
return ((char *) 0);
}
if (ptr[2] != RULE_CLASS)
{
ptr += 2;
if (area[i] != *ptr)
{
return ((char *) 0);
}
} else
{
ptr += 3;
if (!MatchClass (*ptr, area[i]))
{
return ((char *) 0);
}
}
}
break;
default:
Log ("Mangle: unknown command %c in %s\n", *ptr, control);
return ((char *) 0);
break;
}
}
if (!area[0]) /* have we deweted de poor widdle fing away? */
{
return ((char *) 0);
}
return (area);
}
;
static char area[STRINGSIZE];
ptr = area;
while (*string)
{
*(ptr++) = (*string == old ? new : *string);
string++;
}
*ptr = '\0';
return (area);
}
char *
Purge (string, target) /* returns pointer tSources/crack-pwc.c 100600 5661 132 53410 5222357160 11526 0 37777777777 1 0 /*
* 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);
}
{
return (0);
}
for (ruleptr = gecosroot; ruleptr; ruleptr = ruleptr -> next)
{
if (mangle = Mangle (guess, ruleptr -> rule))
{
if (TryOneUser (entry_ptr, mangle))
{
return (1);
}
}
}
return (0);
}
/* SpecSources/crack-fcrypt.c 100600 5661 132 57742 5222357201 12254 0 37777777777 1 0 /*
* 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.
*/
/*
* Misc defs for the fast password transform optimisations.
*/
#include "crack.h"
#define reg register
#define uns unsigned
#define unsb uns char
#define unsl uns long
/*
* Types for the different ways to represent DES bit patterns. Bits are
* always right justified within fields. Bits which have lower indices in
* the NBS spec are stored in the vax bits with less significance (e.g., Bit
* 1 of NBS spec is stored in the bit with weight 2 ** 0 to the Vax.
*/
#define obpb1 unsb /* One bit per byte. */
#define sbpb6 unsb /* Six bits per byte, 6 held. */
#define sbpb6R unsb /* Six bits per byte Reversed order, 6 held. */
#define sbpb24 unsl /* Six bits per byte, 24 held. */
#define ebpb24 unsl /* Eight bits per bit, 24 held. */
#define fbpb4 unsb /* Four bits per byte, 4 held. */
#define fbpb4R unsb /* Four bits per byte Reversed order, 4 held. */
/*
* The operation (6 * x) is often better optimised as this (for really
* braindead compilers) - AEM
*/
#ifdef BRAINDEAD6
#define SIX_TIMES(exprn) (((exprn) << 2) + ((exprn) << 1))
#else
#define SIX_TIMES(exprn) (6 * (exprn))
#endif /* BRAINDEAD6 */
/* DES transformation type... */
union SDATA
{
sbpb24 b[2];
sbpb6 c[8];
};
#ifndef FDES_4BYTE /* Thanks to Matt Bishop for this idea -AEM. */
#define SIZEFIX 0
#define INDIRECT(a,b) (a)[b]
#else
#define SIZEFIX 2 /* "n" where 2^n == sizeof(sbpb24) */
#define INDIRECT(a,b) (*((sbpb24 *)(((unsigned char *) a) + (b))))
#endif
/*
* These used to be rather slow and frequently used functions - AEM
*/
#define TF_TO_SIXBIT(tf) \
(sbpb24)((tf & 077L) | \
((tf & 07700L) << 2) | \
((tf & 0770000L) << 4) | \
((tf & 077000000L) << 6))
#define SIXBIT_TO_TF(sb) \
(ebpb24)((sb & 0x3fL) | \
((sb & 0x3f00L) >> 2) | \
((sb & 0x3f0000L) >> 4) | \
((sb & 0x3f000000L) >> 6))
/*
* Data segment gathered into one place, try to keep this stuff long aligned
* - AEM
*/
static char iobuf[16];
static obpb1 crypt_block[72]; /* 72 is next multiple of 8 bytes after 66 */
static sbpb24 KS[32];
static sbpb24 S0H[64], S1H[64], S2H[64], S3H[64];
static sbpb24 S4H[64], S5H[64], S6H[64], S7H[64];
static sbpb24 S0L[64], S1L[64], S2L[64], S3L[64];
static sbpb24 S4L[64], S5L[64], S6L[64], S7L[64];
static sbpb24 out96[4];
/*
* Start of the real thing
*/
void
fsetkey ()
{
/*
* This used to be utterly horrendous. It still is, but it's much, much,
* smaller... (and quite a bit faster...) - AEM
*/
static unsb KeyToKS[] =
{
9, 50, 33, 59, 48, 16, 32, 56, 1, 8, 18, 41, 2, 34, 25, 24,
43, 57, 58, 0, 35, 26, 17, 40, 21, 27, 38, 53, 36, 3, 46, 29,
4, 52, 22, 28, 60, 20, 37, 62, 14, 19, 44, 13, 12, 61, 54, 30,
1, 42, 25, 51, 40, 8, 24, 48, 58, 0, 10, 33, 59, 26, 17, 16,
35, 49, 50, 57, 56, 18, 9, 32, 13, 19, 30, 45, 28, 62, 38, 21,
27, 44, 14, 20, 52, 12, 29, 54, 6, 11, 36, 5, 4, 53, 46, 22,
50, 26, 9, 35, 24, 57, 8, 32, 42, 49, 59, 17, 43, 10, 1, 0,
48, 33, 34, 41, 40, 2, 58, 16, 60, 3, 14, 29, 12, 46, 22, 5,
11, 28, 61, 4, 36, 27, 13, 38, 53, 62, 20, 52, 19, 37, 30, 6,
34, 10, 58, 48, 8, 41, 57, 16, 26, 33, 43, 1, 56, 59, 50, 49,
32, 17, 18, 25, 24, 51, 42, 0, 44, 54, 61, 13, 27, 30, 6, 52,
62, 12, 45, 19, 20, 11, 60, 22, 37, 46, 4, 36, 3, 21, 14, 53,
18, 59, 42, 32, 57, 25, 41, 0, 10, 17, 56, 50, 40, 43, 34, 33,
16, 1, 2, 9, 8, 35, 26, 49, 28, 38, 45, 60, 11, 14, 53, 36,
46, 27, 29, 3, 4, 62, 44, 6, 21, 30, 19, 20, 54, 5, 61, 37,
2, 43, 26, 16, 41, 9, 25, 49, 59, 1, 40, 34, 24, 56, 18, 17,
0, 50, 51, 58, 57, 48, 10, 33, 12, 22, 29, 44, 62, 61, 37, 20,
30, 11, 13, 54, 19, 46, 28, 53, 5, 14, 3, 4, 38, 52, 45, 21,
51, 56, 10, 0, 25, 58, 9, 33, 43, 50, 24, 18, 8, 40, 2, 1,
49, 34, 35, 42, 41, 32, 59, 17, 27, 6, 13, 28, 46, 45, 21, 4,
14, 62, 60, 38, 3, 30, 12, 37, 52, 61, 54, 19, 22, 36, 29, 5,
35, 40, 59, 49, 9, 42, 58, 17, 56, 34, 8, 2, 57, 24, 51, 50,
33, 18, 48, 26, 25, 16, 43, 1, 11, 53, 60, 12, 30, 29, 5, 19,
61, 46, 44, 22, 54, 14, 27, 21, 36, 45, 38, 3, 6, 20, 13, 52,
56, 32, 51, 41, 1, 34, 50, 9, 48, 26, 0, 59, 49, 16, 43, 42,
25, 10, 40, 18, 17, 8, 35, 58, 3, 45, 52, 4, 22, 21, 60, 11,
53, 38, 36, 14, 46, 6, 19, 13, 28, 37, 30, 62, 61, 12, 5, 44,
40, 16, 35, 25, 50, 18, 34, 58, 32, 10, 49, 43, 33, 0, 56, 26,
9, 59, 24, 2, 1, 57, 48, 42, 54, 29, 36, 19, 6, 5, 44, 62,
37, 22, 20, 61, 30, 53, 3, 60, 12, 21, 14, 46, 45, 27, 52, 28,
24, 0, 48, 9, 34, 2, 18, 42, 16, 59, 33, 56, 17, 49, 40, 10,
58, 43, 8, 51, 50, 41, 32, 26, 38, 13, 20, 3, 53, 52, 28, 46,
21, 6, 4, 45, 14, 37, 54, 44, 27, 5, 61, 30, 29, 11, 36, 12,
8, 49, 32, 58, 18, 51, 2, 26, 0, 43, 17, 40, 1, 33, 24, 59,
42, 56, 57, 35, 34, 25, 16, 10, 22, 60, 4, 54, 37, 36, 12, 30,
5, 53, 19, 29, 61, 21, 38, 28, 11, 52, 45, 14, 13, 62, 20, 27,
57, 33, 16, 42, 2, 35, 51, 10, 49, 56, 1, 24, 50, 17, 8, 43,
26, 40, 41, 48, 18, 9, 0, 59, 6, 44, 19, 38, 21, 20, 27, 14,
52, 37, 3, 13, 45, 5, 22, 12, 62, 36, 29, 61, 60, 46, 4, 11,
41, 17, 0, 26, 51, 48, 35, 59, 33, 40, 50, 8, 34, 1, 57, 56,
10, 24, 25, 32, 2, 58, 49, 43, 53, 28, 3, 22, 5, 4, 11, 61,
36, 21, 54, 60, 29, 52, 6, 27, 46, 20, 13, 45, 44, 30, 19, 62,
25, 1, 49, 10, 35, 32, 48, 43, 17, 24, 34, 57, 18, 50, 41, 40,
59, 8, 9, 16, 51, 42, 33, 56, 37, 12, 54, 6, 52, 19, 62, 45,
20, 5, 38, 44, 13, 36, 53, 11, 30, 4, 60, 29, 28, 14, 3, 46,
17, 58, 41, 2, 56, 24, 40, 35, 9, 16, 26, 49, 10, 42, 33, 32,
51, 0, 1, 8, 43, 34, 25, 48, 29, 4, 46, 61, 44, 11, 54, 37,
12, 60, 30, 36, 5, 28, 45, 3, 22, 27, 52, 21, 20, 6, 62, 38
};
reg int i;
reg unsigned long r;
reg unsb *k;
k = KeyToKS;
for (i = 0; i < 32; i++)
{
/* 16-bit tweaks suggested by
[email protected] */
/* inlining speedup tweak suggested by
[email protected] */
/* (strange addition compensates missing TF_TO_SIXBIT) */
r = (unsigned long) crypt_block[*(k++)];
r |= (unsigned long) crypt_block[*(k++)] << 1;
r |= (unsigned long) crypt_block[*(k++)] << 2;
r |= (unsigned long) crypt_block[*(k++)] << 3;
r |= (unsigned long) crypt_block[*(k++)] << 4;
r |= (unsigned long) crypt_block[*(k++)] << 5;
r |= (unsigned long) crypt_block[*(k++)] << (2 + 6);
r |= (unsigned long) crypt_block[*(k++)] << (2 + 7);
r |= (unsigned long) crypt_block[*(k++)] << (2 + 8);
r |= (unsigned long) crypt_block[*(k++)] << (2 + 9);
r |= (unsigned long) crypt_block[*(k++)] << (2 + 10);
r |= (unsigned long) crypt_block[*(k++)] << (2 + 11);
r |= (unsigned long) crypt_block[*(k++)] << (4 + 12);
r |= (unsigned long) crypt_block[*(k++)] << (4 + 13);
r |= (unsigned long) crypt_block[*(k++)] << (4 + 14);
r |= (unsigned long) crypt_block[*(k++)] << (4 + 15);
r |= (unsigned long) crypt_block[*(k++)] << (4 + 16);
r |= (unsigned long) crypt_block[*(k++)] << (4 + 17);
r |= (unsigned long) crypt_block[*(k++)] << (6 + 18);
r |= (unsigned long) crypt_block[*(k++)] << (6 + 19);
r |= (unsigned long) crypt_block[*(k++)] << (6 + 20);
r |= (unsigned long) crypt_block[*(k++)] << (6 + 21);
r |= (unsigned long) crypt_block[*(k++)] << (6 + 22);
r |= (unsigned long) crypt_block[*(k++)] << (6 + 23);
KS[i] = r;
}
}
void
XForm (saltvalue)
sbpb24 saltvalue;
{
#ifdef BIG_ENDIAN /* Icarus Sparry, Bath - mod AEM */
#define STEP --
#define START &sdata.c[7]
#define Dl sdata.b[1]
#define Dh sdata.b[0]
#else
#ifdef LITTLE_ENDIAN
#define STEP ++
#define START &sdata.c[0]
#define Dl sdata.b[0]
#define Dh sdata.b[1]
#endif
/* else error */
#endif
union SDATA sdata;
reg sbpb24 Rl;
reg sbpb24 Rh;
reg sbpb24 Ll;
reg sbpb24 Lh;
reg sbpb6 *dp;
int loop;
int kloop;
sbpb24 *kp;
reg sbpb24 k;
#ifdef FDES_8BYTE
reg sbpb24 tmpi;
#endif /* FDES_8BYTE */
Ll = Lh = Rl = Rh = 0;
for (loop = 25; loop--; /* nothing */ )
{
kp = KS;
for (kloop = 8; kloop--; /* nothing */ )
{
k = (Rl ^ Rh) & saltvalue;
#ifndef FDES_8BYTE
Dl = (k ^ Rl ^ *kp++) << SIZEFIX;
Dh = (k ^ Rh ^ *kp++) << SIZEFIX;
#else
/* hack to make things work better - matthew kaufman */
/* I haven't tried any of this - I don't have a cray... AEM */
tmpi = (k ^ Rl ^ *kp++);
sdata.c[3] = (tmpi >> 24) & 0x00ff;
sdata.c[2] = (tmpi >> 16) & 0x00ff;
sdata.c[1] = (tmpi >> 8) & 0x00ff;
sdata.c[0] = (tmpi) & 0x00ff;
tmpi = (k ^ Rh ^ *kp++);
sdata.c[7] = (tmpi >> 24) & 0x00ff;
sdata.c[6] = (tmpi >> 16) & 0x00ff;
sdata.c[5] = (tmpi >> 8) & 0x00ff;
sdata.c[4] = (tmpi) & 0x00ff;
#endif /* FDES_8BYTE */
dp = START;
Lh ^= INDIRECT (S0H, *dp);
Ll ^= INDIRECT (S0L, *dp STEP);
Lh ^= INDIRECT (S1H, *dp);
Ll ^= INDIRECT (S1L, *dp STEP);
Lh ^= INDIRECT (S2H, *dp);
Ll ^= INDIRECT (S2L, *dp STEP);
Lh ^= INDIRECT (S3H, *dp);
Ll ^= INDIRECT (S3L, *dp STEP);
Lh ^= INDIRECT (S4H, *dp);
Ll ^= INDIRECT (S4L, *dp STEP);
Lh ^= INDIRECT (S5H, *dp);
Ll ^= INDIRECT (S5L, *dp STEP);
Lh ^= INDIRECT (S6H, *dp);
Ll ^= INDIRECT (S6L, *dp STEP);
Lh ^= INDIRECT (S7H, *dp);
Ll ^= INDIRECT (S7L, *dp STEP);
k = (Ll ^ Lh) & saltvalue;
#ifndef FDES_8BYTE
Dl = (k ^ Ll ^ *kp++) << SIZEFIX;
Dh = (k ^ Lh ^ *kp++) << SIZEFIX;
#else
tmpi = (k ^ Ll ^ *kp++);
sdata.c[3] = (tmpi >> 24) & 0x00ff;
sdata.c[2] = (tmpi >> 16) & 0x00ff;
sdata.c[1] = (tmpi >> 8) & 0x00ff;
sdata.c[0] = (tmpi) & 0x00ff;
tmpi = (k ^ Lh ^ *kp++);
sdata.c[7] = (tmpi >> 24) & 0x00ff;
sdata.c[6] = (tmpi >> 16) & 0x00ff;
sdata.c[5] = (tmpi >> 8) & 0x00ff;
sdata.c[4] = (tmpi) & 0x00ff;
#endif /* FDES_8BYTE */
dp = START;
Rh ^= INDIRECT (S0H, *dp);
Rl ^= INDIRECT (S0L, *dp STEP);
Rh ^= INDIRECT (S1H, *dp);
Rl ^= INDIRECT (S1L, *dp STEP);
Rh ^= INDIRECT (S2H, *dp);
Rl ^= INDIRECT (S2L, *dp STEP);
Rh ^= INDIRECT (S3H, *dp);
Rl ^= INDIRECT (S3L, *dp STEP);
Rh ^= INDIRECT (S4H, *dp);
Rl ^= INDIRECT (S4L, *dp STEP);
Rh ^= INDIRECT (S5H, *dp);
Rl ^= INDIRECT (S5L, *dp STEP);
Rh ^= INDIRECT (S6H, *dp);
Rl ^= INDIRECT (S6L, *dp STEP);
Rh ^= INDIRECT (S7H, *dp);
Rl ^= INDIRECT (S7L, *dp STEP);
}
Ll ^= Rl;
Lh ^= Rh;
Rl ^= Ll;
Rh ^= Lh;
Ll ^= Rl;
Lh ^= Rh;
}
/*
* for reasons that I cannot explain, if I insert the contents of the
* UnXForm function right HERE, making the tweaks as necessary to avoid
* using out96[] to pass data, I LOSE 30% of my speed. I don't know why.
* Hence, I continue to use out96[]...
*/
{
reg sbpb24 *qp;
qp = out96;
*qp++ = Ll;
*qp++ = Lh;
*qp++ = Rl;
*qp++ = Rh;
}
}
void
UnXForm ()
{
reg sbpb24 Rl;
reg sbpb24 Rh;
reg sbpb24 Ll;
reg sbpb24 Lh;
reg obpb1 *ptr;
reg long int mask;
register long int *lip;
Ll = SIXBIT_TO_TF (out96[0]);
Lh = SIXBIT_TO_TF (out96[1]);
Rl = SIXBIT_TO_TF (out96[2]);
Rh = SIXBIT_TO_TF (out96[3]);
#ifdef BUILTIN_CLEAR
lip = (long int *) crypt_block;
for (mask = (sizeof (crypt_block) / sizeof (long int)); mask--; /* - */ )
{
*(lip++) = 0L;
}
#else /* BUILTIN_CLEAR */
bzero (crypt_block, 66);
#endif /* BUILTIN_CLEAR */
ptr = crypt_block;
mask = 0x000400L;
if (Rl & mask)
*ptr = 0x01;
ptr++;
if (Ll & mask)
*ptr = 0x01;
ptr++;
mask = 0x400000L;
if (Rl & mask)
*ptr = 0x01;
ptr++;
if (Ll & mask)
*ptr = 0x01;
ptr++;
mask = 0x000400L;
if (Rh & mask)
*ptr = 0x01;
ptr++;
if (Lh & mask)
*ptr = 0x01;
ptr++;
mask = 0x400000L;
if (Rh & mask)
*ptr = 0x01;
ptr++;
if (Lh & mask)
*ptr = 0x01;
ptr++;
mask = 0x000200L;
if (Rl & mask)
*ptr = 0x01;
ptr++;
if (Ll & mask)
*ptr = 0x01;
ptr++;
mask = 0x200000L;
if (Rl & mask)
*ptr = 0x01;
ptr++;
if (Ll & mask)
*ptr = 0x01;
ptr++;
mask = 0x000200L;
if (Rh & mask)
*ptr = 0x01;
ptr++;
if (Lh & mask)
*ptr = 0x01;
ptr++;
mask = 0x200000L;
if (Rh & mask)
*ptr = 0x01;
ptr++;
if (Lh & mask)
*ptr = 0x01;
ptr++;
mask = 0x000100L;
if (Rl & mask)
*ptr = 0x01;
ptr++;
if (Ll & mask)
*ptr = 0x01;
ptr++;
mask = 0x100000L;
if (Rl & mask)
*ptr = 0x01;
ptr++;
if (Ll & mask)
*ptr = 0x01;
ptr++;
mask = 0x000100L;
if (Rh & mask)
*ptr = 0x01;
ptr++;
if (Lh & mask)
*ptr = 0x01;
ptr++;
mask = 0x100000L;
if (Rh & mask)
*ptr = 0x01;
ptr++;
if (Lh & mask)
*ptr = 0x01;
ptr++;
mask = 0x000080L;
if (Rl & mask)
*ptr = 0x01;
ptr++;
if (Ll & mask)
*ptr = 0x01;
ptr++;
mask = 0x080000L;
if (Rl & mask)
*ptr = 0x01;
ptr++;
if (Ll & mask)
*ptr = 0x01;
ptr++;
mask = 0x000080L;
if (Rh & mask)
*ptr = 0x01;
ptr++;
if (Lh & mask)
*ptr = 0x01;
ptr++;
mask = 0x080000L;
if (Rh & mask)
*ptr = 0x01;
ptr++;
if (Lh & mask)
*ptr = 0x01;
ptr++;
mask = 0x000010L;
if (Rl & mask)
*ptr = 0x01;
ptr++;
if (Ll & mask)
*ptr = 0x01;
ptr++;
mask = 0x010000L;
if (Rl & mask)
*ptr = 0x01;
ptr++;
if (Ll & mask)
*ptr = 0x01;
ptr++;
mask = 0x000010L;
if (Rh & mask)
*ptr = 0x01;
ptr++;
if (Lh & mask)
*ptr = 0x01;
ptr++;
mask = 0x010000L;
if (Rh & mask)
*ptr = 0x01;
ptr++;
if (Lh & mask)
*ptr = 0x01;
ptr++;
mask = 0x000008L;
if (Rl & mask)
*ptr = 0x01;
ptr++;
if (Ll & mask)
*ptr = 0x01;
ptr++;
mask = 0x008000L;
if (Rl & mask)
*ptr = 0x01;
ptr++;
if (Ll & mask)
*ptr = 0x01;
ptr++;
mask = 0x000008L;
if (Rh & mask)
*ptr = 0x01;
ptr++;
if (Lh & mask)
*ptr = 0x01;
ptr++;
mask = 0x008000L;
if (Rh & mask)
*ptr = 0x01;
ptr++;
if (Lh & mask)
*ptr = 0x01;
ptr++;
mask = 0x000004L;
if (Rl & mask)
*ptr = 0x01;
ptr++;
if (Ll & mask)
*ptr = 0x01;
ptr++;
mask = 0x004000L;
if (Rl & mask)
*ptr = 0x01;
ptr++;
if (Ll & mask)
*ptr = 0x01;
ptr++;
mask = 0x000004L;
if (Rh & mask)
*ptr = 0x01;
ptr++;
if (Lh & mask)
*ptr = 0x01;
ptr++;
mask = 0x004000L;
if (Rh & mask)
*ptr = 0x01;
ptr++;
if (Lh & mask)
*ptr = 0x01;
ptr++;
mask = 0x000002L;
if (Rl & mask)
*ptr = 0x01;
ptr++;
if (Ll & mask)
*ptr = 0x01;
ptr++;
mask = 0x002000L;
if (Rl & mask)
*ptr = 0x01;
ptr++;
if (Ll & mask)
*ptr = 0x01;
ptr++;
mask = 0x000002L;
if (Rh & mask)
*ptr = 0x01;
ptr++;
if (Lh & mask)
*ptr = 0x01;
ptr++;
mask = 0x002000L;
if (Rh & mask)
*ptr = 0x01;
ptr++;
if (Lh & mask)
*ptr = 0x01;
ptr++;
}
char *
fcrypt (pw, salt)
char *pw;
char *salt;
{
/* Table lookups for salts reduce fcrypt() overhead dramatically */
static sbpb24 salt0[] =
{
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
58, 59, 60, 61, 62, 63, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
0, 1, 2, 3, 4
};
static sbpb24 salt1[] =
{
1152, 1216, 1280, 1344, 1408, 1472, 1536, 1600, 1664,
1728, 1792, 1856, 1920, 1984, 2048, 2112, 2176, 2240, 2304,
2368, 2432, 2496, 2560, 2624, 2688, 2752, 2816, 2880, 2944,
3008, 3072, 3136, 3200, 3264, 3328, 3392, 3456, 3520, 3584,
3648, 3712, 3776, 3840, 3904, 3968, 4032, 0, 64, 128, 192, 256,
320, 384, 448, 512, 576, 640, 704, 320, 384, 448, 512, 576, 640,
704, 768, 832, 896, 960, 1024, 1088,
1152, 1216, 1280, 1344, 1408, 1472, 1536, 1600, 1664,
1728, 1792, 1856, 1920, 1984, 2048, 2112, 2176, 2240, 2304,
2368, 2048, 2112, 2176, 2240, 2304, 2368, 2432, 2496, 2560,
2624, 2688, 2752, 2816, 2880, 2944, 3008, 3072, 3136, 3200,
3264, 3328, 3392, 3456, 3520, 3584, 3648, 3712, 3776, 3840,
3904, 3968, 4032, 0, 64, 128, 192, 256, 320, 384, 448, 512, 576,
640, 704, 768, 832, 896, 960, 1024, 1088,
1152, 1216, 1280, 1344, 1408, 1472, 1536, 1600, 1664,
1728, 1792, 1856, 1920, 1984, 2048, 2112, 2176, 2240, 2304,
2368, 2432, 2496, 2560, 2624, 2688, 2752, 2816, 2880, 2944,
3008, 3072, 3136, 3200, 3264, 3328, 3392, 3456, 3520, 3584,
3648, 3712, 3776, 3840, 3904, 3968, 4032, 0, 64, 128, 192, 256,
320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960, 1024,
1088,
1152, 1216, 1280, 1344, 1408, 1472, 1536, 1600, 1664,
1728, 1792, 1856, 1920, 1984, 2048, 2112, 2176, 2240, 2304,
2368, 2432, 2496, 2560, 2624, 2688, 2752, 2816, 2880, 2944,
3008, 3072, 3136, 3200, 3264, 3328, 3392, 3456, 3520, 3584,
3648, 3712, 3776, 3840, 3904, 3968, 4032, 0, 64, 128, 192, 256
};
/* final perutation desalting */
static obpb1 final[] =
{
46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66,
67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103,
104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,
143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155,
156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168,
169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181,
182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220,
221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233,
234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246,
247, 248, 249, 250, 251, 252, 253, 254, 255,
/* Truncate overflow bits at 256 */
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58
};
reg int i, j, k;
reg long int *lip;
sbpb24 saltvalue;
#ifdef BUILTIN_CLEAR
lip = (long int *) crypt_block;
for (i = (sizeof (crypt_block) / sizeof (long int)); i--; /* - */ )
{
*(lip++) = 0L;
}
#else /* BUILTIN_CLEAR */
bzero (crypt_block, 66);
#endif /* BUILTIN_CLEAR */
for (i = 0; (k = *pw) && i < 64; pw++)
{
crypt_block[i++] = (k >> 6) & 01;
crypt_block[i++] = (k >> 5) & 01;
crypt_block[i++] = (k >> 4) & 01;
crypt_block[i++] = (k >> 3) & 01;
crypt_block[i++] = (k >> 2) & 01;
crypt_block[i++] = (k >> 1) & 01;
crypt_block[i++] = (k >> 0) & 01;
i++; /* have to skip one here (parity bit) */
}
fsetkey ( /* crypt_block */ );
#ifdef BUILTIN_CLEAR
lip = (long int *) crypt_block;
for (i = (sizeof (crypt_block) / sizeof (long int)); i--; /* - */ )
{
*(lip++) = 0L;
}
#else /* BUILTIN_CLEAR */
bzero (crypt_block, 66);
#endif /* BUILTIN_CLEAR */
iobuf[0] = salt[0];
iobuf[1] = salt[1];
saltvalue = salt0[iobuf[0]] | salt1[iobuf[1]];
saltvalue = TF_TO_SIXBIT (saltvalue);
XForm (saltvalue);
UnXForm ();
for (i = 0; i < 11; i++)
{
k = 0;
for (j = 0; j < 6; j++)
{
k = (k << 1) | crypt_block[SIX_TIMES (i) + j];
}
iobuf[i + 2] = final[k];
}
iobuf[i + 2] = 0;
if (iobuf[1] == 0)
{
iobuf[1] = iobuf[0];
}
return (iobuf);
}
/********* INITIALISATION ROUTINES *********/
fbpb4
lookupS (tableno, t6bits)
unsl tableno;
sbpb6R t6bits;
{
static fbpb4R S[8][64] =
{
14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13,
15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9,
10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12,
7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14,
2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3,
12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13,
4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12,
13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11,
};
sbpb6 fixed6bits;
fbpb4R r;
fbpb4 fixedr;
fixed6bits = (((t6bits >> 0) & 01) << 5) +
(((t6bits >> 1) & 01) << 3) +
(((t6bits >> 2) & 01) << 2) +
(((t6bits >> 3) & 01) << 1) +
(((t6bits >> 4) & 01) << 0) +
(((t6bits >> 5) & 01) << 4);
r = S[tableno][fixed6bits];
fixedr = (((r >> 3) & 01) << 0) +
(((r >> 2) & 01) << 1) +
(((r >> 1) & 01) << 2) +
(((r >> 0) & 01) << 3);
return (fixedr);
}
void
init (tableno, lowptr, highptr)
unsl tableno;
sbpb24 *lowptr, *highptr;
{
static unsb P[] =
{
15, 6, 19, 20,
28, 11, 27, 16,
0, 14, 22, 25,
4, 17, 30, 9,
1, 7, 23, 13,
31, 26, 2, 8,
18, 12, 29, 5,
21, 10, 3, 24,
};
static unsb E[] =
{
31, 0, 1, 2, 3, 4,
3, 4, 5, 6, 7, 8,
7, 8, 9, 10, 11, 12,
11, 12, 13, 14, 15, 16,
15, 16, 17, 18, 19, 20,
19, 20, 21, 22, 23, 24,
23, 24, 25, 26, 27, 28,
27, 28, 29, 30, 31, 0,
};
static obpb1 tmp32[32];
static obpb1 tmpP32[32];
static obpb1 tmpE[48];
int j, k, i;
int tablenoX4;
reg sbpb24 spare24;
tablenoX4 = tableno * 4;
for (j = 0; j < 64; j++)
{
k = lookupS (tableno, j);
for (i = 0; i < 32; i++)
{
tmp32[i] = 0;
}
for (i = 0; i < 4; i++)
{
tmp32[tablenoX4 + i] = (k >> i) & 01;
}
for (i = 0; i < 32; i++)
{
tmpP32[i] = tmp32[P[i]];
}
for (i = 0; i < 48; i++)
{
tmpE[i] = tmpP32[E[i]];
}
lowptr[j] = 0L;
highptr[j] = 0L;
for (i = 0; i < 24; i++)
{
lowptr[j] |= (unsigned long) tmpE[i] << i;
}
for (k = 0, i = 24; i < 48; i++, k++)
{
highptr[j] |= (unsigned long) tmpE[i] << k;
}
spare24 = lowptr[j]; /* to allow for macro expansion */
lowptr[j] = TF_TO_SIXBIT (spare24);
spare24 = highptr[j]; /* to allow for macro expansion */
highptr[j] = TF_TO_SIXBIT (spare24);
}
}
int
init_des ()
{
init (0L, S0L, S0H);
init (1L, S1L, S1H);
init (2L, S2L, S2H);
init (3L, S3L, S3H);
init (4L, S4L, S4H);
init (5L, S5L, S5H);
init (6L, S6L, S6H);
init (7L, S7L, S7H);
return (0);
}
0004L;
if (Rl & mask)
*ptTODO 100600 5661 132 535 5222357074 5710 0 0 1 0 * replace recover/checkpoint code in entirety
* make work over rsh link entirely
* dictionaries shipped from central machine
* code shipped from central machine (!)
* regexp rules (is this really necessary ? what syntax the commands ?)
* bottles of glenmorangie always welcome
* multiprocessing ability
- most of these will be in v5.0
- alec
)
char *pw;
char *salt;
{
/* Table lookups for salts reduce fcrypt() overhead dramatically */
static sbpb24 salt0[] =
{
18, 19, 20, 21, 22, 23 40, 2304,
2368, 2048, 2112, 2176, 2240, 2304, 2368, 2432, 2496, 2560,
2624, 2688, 2752, 2816, 2880, 2944, 3008, 3072, 3136, 3200,
3264, 3328, 3392, 3456, 3520, 3584, 3648, 3712, 3776, 3840,
3904, 3968, 4032, 0, 64, 128, 192, 256, 320, 384, 448, 512, 576,
640, 704, 768, 832, 896, 960, 1024, 1088,
1152, 1216, 1280, 1344, 1408, 1472, 1536, 1600, 1664,
1728, 1792, 1856, 1920, 1984, 2048, 2112, 2176, 2240, 2304,
2368, 2432, 2496, 2560, 2624, 2688, 2752, 2816, 2880, 2944,
3008, 3072, 3136, 3200, 3264, 3
Downloaded From P-80 International Information Systems 304-744-2253