# # This file is part of John the Ripper password cracker, # Copyright (c) 1996-2006,2008 by Solar Designer # [Options] # Wordlist file name, to be used in batch mode Wordlist = /usr/share/john/password.lst # Default Markov mode settings Statsfile = /usr/share/john/stats MkvLvl = 200 MkvMaxLen = 12 # Use idle cycles only Idle = N # Crash recovery file saving delay in seconds Save = 600 # Beep when a password is found (who needs this anyway?) Beep = N # "Single crack" mode rules [List.Rules:Single] # Simple rules come first... : -s x** -c (?acQ -c lQ -s-c x**MlQ # These were not included in crackers I've seen, but are pretty efficient, # so I include them near the beginning >6'6 >7l'7 >6/?ul'6 >5'5 # Weird order, eh? Can't do anything about it, the order is based on the # number of successful cracks... <*d rc <*dMcQ >5/?ul'5 uQ r(?al <*!?A[lc]p <*cQd >7/?u'7 >4l'4 <+(?lcr <+r(?lcr >3'3 >4/?u'4 >3/?ul'3 uQr <*lQf # About 50% of single-mode-crackable passwords get cracked by now... >2x12 >3x13 >4x14 >5x15 >6x16 >7x17 >8x18 >3x22 >4x23 >5x24 >6x25 >7x26 >8x27 >9x28 >4x32 >5x33 >6x34 >7x35 >8x36 >9x37 >2/?ulx12 >3/?ulx13 >4/?ulx14 >5/?ulx15 >6/?ulx16 >7/?ulx17 >8/?ulx18 >3/?ulx22 >4/?ulx23 >5/?ulx24 >6/?ulx25 >7/?ulx26 >8/?ulx27 >9/?ulx28 >4/?ulx32 >5/?ulx33 >6/?ulx34 >7/?ulx35 >8/?ulx36 >9/?ulx37 # Now to the suffix stuff... <*l$[1-9!0a-z"-/:-@\[-`{-~] <*(?ac$[1-9!0a-z"-/:-@\[-`{-~] <*lr$[1-9!] <*/?au$[1-9!] <-l$!$! <-(?ac$!$! l$!<-$!$! (?ac$!<-$!$! # Removing vowels... /?v@?v>2l /?v@?v>2(?ac /?v@?v>2<*d # crack -> cracked, crack -> cracking <*l[PI] <*l[PI](?ac # mary -> marie <*(?a[lc])yro0ir$e # marie -> mary <*(?a[lc])er=1iD0o0yr # The following 3l33t rules are based on original Crack's dicts.rules l/asa4[:c] l/ese3[:c] l/lsl1[:c] l/oso0[:c] l/sss$[:c] l/asa4/ese3[:c] l/asa4/lsl1[:c] l/asa4/oso0[:c] l/asa4/sss$[:c] l/ese3/lsl1[:c] l/ese3/oso0[:c] l/ese3/sss$[:c] l/lsl1/oso0[:c] l/lsl1/sss$[:c] l/oso0/sss$[:c] l/asa4/ese3/lsl1[:c] l/asa4/ese3/oso0[:c] l/asa4/ese3/sss$[:c] l/asa4/lsl1/oso0[:c] l/asa4/lsl1/sss$[:c] l/asa4/oso0/sss$[:c] l/ese3/lsl1/oso0[:c] l/ese3/lsl1/sss$[:c] l/ese3/oso0/sss$[:c] l/lsl1/oso0/sss$[:c] l/asa4/ese3/lsl1/oso0[:c] l/asa4/ese3/lsl1/sss$[:c] l/asa4/ese3/oso0/sss$[:c] l/asa4/lsl1/oso0/sss$[:c] l/ese3/lsl1/oso0/sss$[:c] l/asa4/ese3/lsl1/oso0/sss$[:c] # Now to the prefix stuff... l^[1a-z2-90] lQ^[A-Z] ^[A-Z] l^["-/:-@\[-`{-~] <9(?a[lc]^e^h^[tT] <9(?a[lc]^y^m^[aA] <9(?a[lc]^r^[mdMD] <9(?a[lc]^.^r^[mdMD] <9(?a[lc]^_^_ <-!?Alp^[240-9] # Some word pair rules... # johnsmith -> JohnSmith, johnSmith (?a2(?ac1[cl] # JohnSmith -> john smith, john_smith, john-smith 1<-$[ _\-]+l # JohnSmith -> John smith, John_smith, John-smith 1<-(?ac$[ _\-]2l # JohnSmith -> john Smith, john_Smith, john-Smith 1<-l$[ _\-]2(?ac # johnsmith -> John Smith, John_Smith, John-Smith 1<-(?ac$[ _\-]2(?ac # Applying different simple rules to each of the two words 1[ur]2l 2(?ac1[ur] 1l2[ur] 1(?ac2[ur] # jsmith -> smithj, etc... (?a[lc][{}] (?a[lc]}} (?a[lc]{{ # Toggle case... T[1-7]Q lMT[1-7]Q >2[lu]MT0T2T4T6T8Q # Deleting chars... D[1-7]Q D[1-7]Q/?ul D[1-7]Q(?ac # Inserting a dot... >3(?a[lc]i[12]. # More suffix stuff... <-l$[190]$[0-9] <-(?ac$[190]$[0-9] <-l$[782]$[0-9] <-(?ac$[782]$[0-9] <*(?a[lc]$[A-Z] # cracking -> CRACKiNG u/IsIi # Crack96 -> cRACK96 CQ # Crack96 -> cRACK(^ SQ # Crack96 -> CRaCK96 /?vVQ # Really weird charset conversions, like "england" -> "rmh;smf" :[RL]Q lQ[RL] (?acQ[RL] RRQ LLQ # Both prefixing and suffixing... <-l^1$1 <-l^!$! <-l^@$@ <-l^#$# <-l^$$$ <-l^%$% <-l^^$^ <-l^&$& <-l^*$* <-l^($) <-l^-$- <-l^=$= <-l^_$_ <-l^+$+ <-l^.$. <-l^?$? <-l^{$} <-l^\[$] <-l^<$> <-l^|$| <-l^:$: <-l^'$' <-l^"$" # The rest of two-digit suffix stuff, less common numbers... <-l$[63-5]$[0-9] <-(?ac$[63-5]$[0-9] # Some three-digit numbers... (?a[lc]$0<-$0$7 (?a[lc]$1<-$1$1 (?a[lc]$1<-$2$3 (?a[lc]$2<-$2$2 (?a[lc]$3<-$3$3 (?a[lc]$4<-$4$4 (?a[lc]$5<-$5$5 (?a[lc]$6<-$6$6 (?a[lc]$7<-$7$7 (?a[lc]$8<-$8$8 (?a[lc]$9<-$9$9 # Some [birth] years... l$1<-$9$[7-96-0]>- l$2<-$0$0>- l$1$9<-$[7-9]$[0-9] l$2$0<-$0$[0-9] l$1$9<-$[6-0]$[9-0] # Uncomment the following lines if you're really crazy ;# Insert/overstrike some characters... ;!?Ali[1-6][a-z] ;!?Alo[0-7][a-z] ;# Toggle case everywhere... ;lMT[*0]T[*1]T[*2]T[*3]T[*4]T[*5]T[*6]T[*7]Q ;# Very slow stuff... ;l$[1-90]<-$[0-9]$[0-9] ;(?ac$[1-90]<-$[0-9]$[0-9] ;<-l$[a-z]$[a-z] ;<9l^[a-z]^[a-z] ;<-l^[a-z]$[a-z] # Wordlist mode rules [List.Rules:Wordlist] # Try words as they are : # Lowercase every pure alphanumeric word -c >3!?XlQ # Capitalize every pure alphanumeric word -c >2(?a!?XcQ # Lowercase and pluralize pure alphabetic words <*>2!?Alp # Lowercase pure alphabetic words and append '1' <*>2!?Al$1 # Capitalize pure alphabetic words and append '1' -c <*>2!?Ac$1 # Duplicate reasonably short pure alphabetic words (fred -> fredfred) <7>1!?Ald # Lowercase and reverse pure alphabetic words >3!?AlMrQ # Prefix pure alphabetic words with '1' >2!?Al^1 # Uppercase pure alphanumeric words -c >2!?XuQ # Lowercase pure alphabetic words and append a digit or simple punctuation <*>2!?Al$[2!37954860.?] # Words containing punctuation, which is then squeezed out, lowercase /?p@?p>3l # Words with vowels removed, lowercase /?v@?v>3l # Words containing whitespace, which is then squeezed out, lowercase /?w@?w>3l # Capitalize and duplicate short pure alphabetic words (fred -> FredFred) -c <7>1!?Acd # Capitalize and reverse pure alphabetic words (fred -> derF) -c <+>2!?Acr # Reverse and capitalize pure alphabetic words (fred -> Derf) -c >2!?AMrQc # Lowercase and reflect pure alphabetic words (fred -> fredderf) <7>1!?AlMrQrf # Uppercase the last letter of pure alphabetic words (fred -> freD) -c <+>2!?AMrQcr # Prefix pure alphabetic words with '2' or '4' >2!?Al^[24] # Capitalize pure alphabetic words and append a digit or simple punctuation -c <*>2!?Ac$[2!3957468.?0] # Prefix pure alphabetic words with digits >2!?Al^[379568] # Capitalize and pluralize pure alphabetic words of reasonable length -c <*>2!?Acp # Lowercase/capitalize pure alphabetic words of reasonable length and convert: # crack -> cracked, crack -> cracking <*>2!?Al[PI] -c <*>2!?Ac[PI] # Try the second half of split passwords -s x** -s-c x**MlQ # Case toggler for cracking MD4-based NTLM hashes (with the contributed # patch), given already cracked DES-based LM hashes. # Rename this section to [List.Rules:Wordlist] to activate it. [List.Rules:NT] l lMT[*0]T[*1]T[*2]T[*3]T[*4]T[*5]T[*6]T[*7]T[*8]T[*9]T[*A]T[*B]T[*C]T[*D]Q # Incremental modes [Incremental:All] File = /usr/share/john/all.chr MinLen = 0 MaxLen = 8 CharCount = 95 [Incremental:Alpha] File = /usr/share/john/alpha.chr MinLen = 1 MaxLen = 8 CharCount = 26 [Incremental:Digits] File = /usr/share/john/digits.chr MinLen = 1 MaxLen = 8 CharCount = 10 [Incremental:Alnum] File = /usr/share/john/alnum.chr MinLen = 1 MaxLen = 8 CharCount = 36 [Incremental:LanMan] File = /usr/share/john/lanman.chr MinLen = 0 MaxLen = 7 CharCount = 69 # Some pre-defined word filters [List.External:Filter_Alpha] void filter() { int i, c; i = 0; while (c = word[i++]) if (c < 'a' || c > 'z') { word = 0; return; } } [List.External:Filter_Digits] void filter() { int i, c; i = 0; while (c = word[i++]) if (c < '0' || c > '9') { word = 0; return; } } [List.External:Filter_Alnum] void filter() { int i, c; i = 0; while (c = word[i++]) if ((c < 'a' || c > 'z') && (c < '0' || c > '9')) { word = 0; return; } } [List.External:Filter_LanMan] void filter() { int i, c; word[7] = 0; // Truncate at 7 characters i = 0; // Convert to uppercase while (c = word[i]) { if (c >= 'a' && c <= 'z') word[i] &= 0xDF; i++; } } # A simple cracker for LM hashes [List.External:LanMan] int length; // Current length void init() { word[0] = 'A' - 1; // Start with "A" word[length = 1] = 0; } void generate() { int i; i = length - 1; // Start from the last character while (++word[i] > 'Z') // Try to increase it if (i) // Overflow here, any more positions? word[i--] = 'A'; // Yes, move to the left, and repeat else // No if (length < 7) { word[i = ++length] = 0; // Switch to the next length while (i--) word[i] = 'A'; return; } else { word = 0; return; // We're done } } void restore() { length = 0; // Calculate the length while (word[length]) length++; } # Simple and well-commented, yet useful external mode example [List.External:Double] /* * This cracking mode tries all the possible duplicated lowercase alphabetic * "words" of up to 8 characters long. Since word halves are the same, it * only has to try about 500,000 words. */ /* Global variables: current length and word */ int length, current[9]; /* Called at startup to initialize the global variables */ void init() { int i; i = length = 2; // Start with 4 character long words while (i--) current[i] = 'a'; // Set our half-word to "aa" } /* Generates a new word */ void generate() { int i; /* Export last generated word, duplicating it at the same time; here "word" * is a pre-defined external variable. */ word[(i = length) << 1] = 0; while (i--) word[length + i] = word[i] = current[i]; /* Generate a new word */ i = length - 1; // Start from the last character while (++current[i] > 'z') // Try to increase it if (i) // Overflow here, any more positions? current[i--] = 'a'; // Yes, move to the left, and repeat else { // No current = 0; // Request a length switch break; // Break out of the loop } /* Switch to the next length, unless we were generating 8 character long * words already. */ if (!current && length < 4) { i = ++length; while (i--) current[i] = 'a'; } } /* Called when restoring an interrupted session */ void restore() { int i; /* Import the word back */ i = 0; while (current[i] = word[i]) i++; /* ...and calculate the half-word length */ length = i >> 1; } # Trivial parallel processing example [List.External:Parallel] /* * This word filter makes John process some of the words only, for running * multiple instances on different CPUs. It can be used with any cracking * mode except for "single crack". Note: this is not a good solution, but * is just an example of what can be done with word filters. */ int node, total; // This node's number, and node count int number; // Current word number void init() { node = 1; total = 2; // Node 1 of 2, change as appropriate number = node - 1; // Speedup the filter a bit } void filter() { if (number++ % total) // Word for a different node? word = 0; // Yes, skip it } # Strip 0.5 ("Secure Tool for Recalling Important Passwords") cracker, # based on analysis done by Thomas Roessler and Ian Goldberg. This will # crack passwords you may have generated with Strip; other uses of Strip # are unaffected. [List.External:Strip] int minlength, maxlength, mintype, maxtype; int crack_seed, length, type; int count, charset[128]; void init() { int c; /* Password lengths to try; Strip can generate passwords of 4 to 16 * characters, but traditional crypt(3) hashes are limited to 8. */ minlength = 4; // 4 maxlength = 8; // 16 /* Password types to try (Numeric, Alpha-Num, Alpha-Num w/ Meta). */ mintype = 0; // 0 maxtype = 2; // 2 crack_seed = 0x10000; length = minlength - 1; type = mintype; count = 0; c = '0'; while (c <= '9') charset[count++] = c++; } void generate() { int seed, random; int i, c; if (crack_seed > 0xffff) { crack_seed = 0; if (++length > maxlength) { length = minlength; if (++type > maxtype) { word[0] = 0; return; } } count = 10; if (type >= 1) { c = 'a'; while (c <= 'f') charset[count++] = c++; c = 'h'; while (c <= 'z') charset[count++] = c++; c = 'A'; while (c <= 'Z') charset[count++] = c++; } if (type == 2) { charset[count++] = '!'; c = '#'; while (c <= '&') charset[count++] = c++; c = '('; while (c <= '/') charset[count++] = c++; c = '<'; while (c <= '>') charset[count++] = c++; charset[count++] = '?'; charset[count++] = '@'; charset[count++] = '['; charset[count++] = ']'; charset[count++] = '^'; charset[count++] = '_'; c = '{'; while (c <= '~') charset[count++] = c++; } } seed = (crack_seed++ << 16 >> 16) * 22695477 + 1; i = 0; while (i < length) { random = ((seed = seed * 22695477 + 1) >> 16) & 0x7fff; word[i++] = charset[random % count]; } word[i] = 0; } # Try sequences of adjacent keys on a keyboard as candidate passwords [List.External:Keyboard] int maxlength, length; // Maximum password length to try, current length int fuzz; // The desired "fuzz factor", either 0 or 1 int id[15]; // Current character indices for each position int m[0x400], mc[0x80]; // The keys matrix, counts of adjacent keys int f[0x40], fc; // Characters for the first position, their count void init() { int minlength; int i, j, c, p; int k[0x40]; minlength = 1; // Initial password length to try maxlength = 15; // Maximum password length to try, up to 15 fuzz = 1; // "Fuzz factor", set to 0 for much quicker runs /* * This defines the keyboard layout, by default for a QWERTY keyboard. * Please note that the sizes of m[] and mc[] arrays assume 7-bit * characters and will need to be doubled for 8-bit characters such as * umlauts. */ i = 0; while (i < 0x40) k[i++] = 0; k[0] = '`'; i = 0; while (++i <= 9) k[i] = '0' + i; k[10] = '0'; k[11] = '-'; k[12] = '='; k[0x11] = 'q'; k[0x12] = 'w'; k[0x13] = 'e'; k[0x14] = 'r'; k[0x15] = 't'; k[0x16] = 'y'; k[0x17] = 'u'; k[0x18] = 'i'; k[0x19] = 'o'; k[0x1a] = 'p'; k[0x1b] = '['; k[0x1c] = ']'; k[0x1d] = '\\'; k[0x21] = 'a'; k[0x22] = 's'; k[0x23] = 'd'; k[0x24] = 'f'; k[0x25] = 'g'; k[0x26] = 'h'; k[0x27] = 'j'; k[0x28] = 'k'; k[0x29] = 'l'; k[0x2a] = ';'; k[0x2b] = '\''; k[0x31] = 'z'; k[0x32] = 'x'; k[0x33] = 'c'; k[0x34] = 'v'; k[0x35] = 'b'; k[0x36] = 'n'; k[0x37] = 'm'; k[0x38] = ','; k[0x39] = '.'; k[0x3a] = '/'; i = 0; while (i < 0x80) mc[i++] = 0; fc = 0; /* rows */ c = 0; i = 0; while (i < 0x40) { p = c; c = k[i++]; if (!c) continue; f[fc++] = c; if (!p) continue; m[(c << 3) + mc[c]++] = p; m[(p << 3) + mc[p]++] = c; } f[fc] = 0; /* columns */ i = 0; while (i < 0x30) { p = k[i++]; if (!p) continue; j = 1 - fuzz; while (j <= 1 + fuzz) { c = k[i + 0x10 - j++]; if (!c) continue; m[(c << 3) + mc[c]++] = p; m[(p << 3) + mc[p]++] = c; } } id[0] = 0; length = minlength; } void generate() { int i, p, maxcount; word[i = 0] = p = f[id[0]]; while (++i < length) word[i] = p = m[(p << 3) + id[i]]; word[i--] = 0; if (i) maxcount = mc[word[i - 1]]; else maxcount = fc; while (++id[i] >= maxcount) { if (!i) { if (length < maxlength) { id[0] = 0; id[length++] = 0; } return; } id[i--] = 0; if (i) maxcount = mc[word[i - 1]]; else maxcount = fc; } } void restore() { int i; /* Calculate the length */ length = 0; while (word[length]) length++; /* Infer the first character index */ i = -1; while (++i < fc) { if (f[i] == word[0]) { id[0] = i; break; } } /* This sample can be enhanced to infer the rest of the indices here */ } # Generic implementation of "dumb" exhaustive search, given a range of lengths # and an arbitrary charset. This is pre-configured to try 8-bit characters # against LM hashes, which is only reasonable to do for very short password # half lengths. [List.External:DumbForce] int maxlength; // Maximum password length to try int last; // Last character position, zero-based int lastid; // Character index in the last position int id[0x7f]; // Current character indices for other positions int charset[0x100], c0; // Character set void init() { int minlength; int i, c; minlength = 1; // Initial password length to try, must be at least 1 maxlength = 7; // Must be at least same as minlength /* * This defines the character set. * * Let's say, we want to try TAB, all non-control ASCII characters, and all * 8-bit characters, including the 8-bit terminal controls range (as these are * used as regular national characters with some 8-bit encodings), but except * for known terminal controls (risky for the terminal we may be running on). * * Also, let's say our hashes are case-insensitive, so skip lowercase letters * (this is right for LM hashes). */ i = 0; charset[i++] = 9; // Add horizontal TAB (ASCII 9), then c = ' '; // start with space (ASCII 32) and while (c < 'a') // proceed till lowercase 'a' charset[i++] = c++; c = 'z' + 1; // Skip lowercase letters and while (c <= 0x7e) // proceed for all printable ASCII charset[i++] = c++; c++; // Skip DEL (ASCII 127) and while (c < 0x84) // proceed over 8-bit codes till IND charset[i++] = c++; charset[i++] = 0x86; // Skip IND (84 hex) and NEL (85 hex) charset[i++] = 0x87; c = 0x89; // Skip HTS (88 hex) while (c < 0x8d) // Proceed till RI (8D hex) charset[i++] = c++; c = 0x91; // Skip RI, SS2, SS3, DCS while (c < 0x96) // Proceed till SPA (96 hex) charset[i++] = c++; charset[i++] = 0x99; // Skip SPA, EPA, SOS c = 0xa0; // Skip DECID, CSI, ST, OSC, PM, APC while (c <= 0xff) // Proceed with the rest of 8-bit codes charset[i++] = c++; /* Zero-terminate it, and cache the first character */ charset[i] = 0; c0 = charset[0]; last = minlength - 1; i = 0; while (i <= last) { id[i] = 0; word[i++] = c0; } lastid = -1; word[i] = 0; } void generate() { int i; /* Handle the typical case specially */ if (word[last] = charset[++lastid]) return; lastid = 0; word[i = last] = c0; while (i--) { // Have a preceding position? if (word[i] = charset[++id[i]]) return; id[i] = 0; word[i] = c0; } if (++last < maxlength) { // Next length? id[last] = lastid = 0; word[last] = c0; word[last + 1] = 0; } else // We're done word = 0; } void restore() { int i, c; /* Calculate the current length and infer the character indices */ last = 0; while (c = word[last]) { i = 0; while (charset[i] != c && charset[i]) i++; if (!charset[i]) i = 0; // Not found id[last++] = i; } lastid = id[--last]; } # Generic implementation of exhaustive search for a partially-known password. # This is pre-configured for length 8, lowercase and uppercase letters in the # first 4 positions (52 different characters), and digits in the remaining 4 # positions - however, the corresponding part of init() may be modified to use # arbitrary character sets or even fixed characters for each position. [List.External:KnownForce] int last; // Last character position, zero-based int lastofs; // Last character position offset into charset[] int lastid; // Current character index in the last position int id[0x7f]; // Current character indices for other positions int charset[0x7f00]; // Character sets, 0x100 elements for each position void init() { int length; int pos, ofs, i, c; length = 8; // Password length to try /* This defines the character sets for different character positions */ pos = 0; while (pos < 4) { ofs = pos++ << 8; i = 0; c = 'a'; while (c <= 'z') charset[ofs + i++] = c++; c = 'A'; while (c <= 'Z') charset[ofs + i++] = c++; charset[ofs + i] = 0; } while (pos < length) { ofs = pos++ << 8; i = 0; c = '0'; while (c <= '9') charset[ofs + i++] = c++; charset[ofs + i] = 0; } last = length - 1; pos = -1; while (++pos <= last) word[pos] = charset[id[pos] = pos << 8]; lastid = (lastofs = last << 8) - 1; word[pos] = 0; } void generate() { int pos; /* Handle the typical case specially */ if (word[last] = charset[++lastid]) return; word[pos = last] = charset[lastid = lastofs]; while (pos--) { // Have a preceding position? if (word[pos] = charset[++id[pos]]) return; word[pos] = charset[id[pos] = pos << 8]; } word = 0; // We're done } void restore() { int i, c; /* Calculate the current length and infer the character indices */ last = 0; while (c = word[last]) { i = lastofs = last << 8; while (charset[i] != c && charset[i]) i++; if (!charset[i]) i = lastofs; // Not found id[last++] = i; } lastid = id[--last]; }