1
mirror of https://github.com/rapid7/metasploit-framework synced 2024-11-05 14:57:30 +01:00
metasploit-framework/data/john.conf

2022 lines
62 KiB
Plaintext
Executable File

#
# This file is part of John the Ripper password cracker,
# Copyright (c) 1996-2006,2008-2011 by Solar Designer
#
# ...with changes in the jumbo patch, by various authors
#
#
# This file uses rules from the KoreLogic set published
# online at: http://contest.korelogic.com/rules.html
#
[Options]
# Wordlist file name, to be used in batch mode
Wordlist = $JOHN/password.lst
# Default Markov mode settings
Statsfile = $JOHN/stats
MkvLvl = 200
MkvMaxLen = 12
# Use idle cycles only
Idle = Y
# Crash recovery file saving delay in seconds
Save = 600
# Beep when a password is found (who needs this anyway?)
Beep = N
# Automagically disable OMP if MPI is used (set to N if
# you want to run one MPI process per multi-core host)
MPIOMPmutex = Y
# Print a notice if disabling OMP (when MPIOMPmutex = Y)
# or when running OMP and MPI at the same time
MPIOMPverbose = Y
# Time formatting string used in status ETA.
# %c means 'local' specific canonical form, such as:
# 05/06/11 18:10:34
#
# Other examples
# %d/%m/%y %H:%M (day/mon/year hour:min)
# %m/%d/%y %H:%M (mon/day/year hour:min)
# %Y-%m-%d %H:%M (ISO 8601 style, 2011-05-06 18:10)
TimeFormat = %c
# Threshold for showing ETA, in percent. ETA will not be
# shown if progress is less than this. If too low, early
# reported figures will be less accurate (default 0.05%)
ETAthreshold = 0.05%
# "Single crack" mode rules
[List.Rules:Single]
# Simple rules come first...
:
-s x**
-c (?a c Q
-c l Q
-s-c x** /?u l
# These were not included in crackers I've seen, but are pretty efficient,
# so I include them near the beginning
>6 '6
>7 '7 l
-c >6 '6 /?u l
>5 '5
# Weird order, eh? Can't do anything about it, the order is based on the
# number of successful cracks...
<* d
r c
-c <* (?a d c
-c >5 '5 /?u l
-c u Q
-c )?a r l
-[:c] <* !?A \p1[lc] p
-c <* c Q d
-c >7 '7 /?u
>4 '4 l
-c <+ (?l c r
-c <+ )?l l Tm
>3 '3
-c >4 '4 /?u
-c >3 '3 /?u l
-c u Q r
<* d M 'l f Q
-c <* l Q d M 'l f Q
# About 50% of single-mode-crackable passwords get cracked by now...
# >2 x12 ... >8 x18
>[2-8] x1\1
>9 \[
# >3 x22 ... >9 x28
>[3-9] x2\p[2-8]
# >4 x32 ... >9 x37
>[4-9] x3\p[2-7]
# >2 x12 /?u l ... >8 x18 /?u l
-c >[2-8] x1\1 /?u l
-c >9 \[ /?u l
# >3 x22 /?u l ... >9 x28 /?u l
-c >[3-9] x2\p[2-8] /?u l
# >4 x32 /?u l ... >9 x37 /?u l
-c >[4-9] x3\p[2-7] /?u l
# Now to the suffix stuff...
<* l $[1-9!0a-rt-z"-/:-@\[-`{-~]
-c <* (?a c $[1-9!0a-rt-z"-/:-@\[-`{-~]
-[:c] <* !?A (?\p1[za] \p1[lc] $s M 'l p Q X0z0 'l $s
-[:c] <* /?A (?\p1[za] \p1[lc] $s
<* l r $[1-9!]
-c <* /?a u $[1-9!]
-[:c] <- (?\p1[za] \p1[lc] Az"'s"
-[:c] <- (?\p1[za] \p1[lc] Az"!!"
-[:c] (?\p1[za] \p1[lc] $! <- Az"!!"
# Removing vowels...
-[:c] /?v @?v >2 (?\p1[za] \p1[lc]
/?v @?v >2 <* d
# crack -> cracked, crack -> cracking
<* l [PI]
-c <* l [PI] (?a c
# mary -> marie
-[:c] <* (?\p1[za] \p1[lc] )y omi $e
# marie -> mary
-[:c] <* (?\p1[za] \p1[lc] )e \] )i val1 oay
# The following are some 3l33t rules
-[:c] l /[aelos] s\0\p[4310$] (?\p1[za] \p1[:c]
-[:c] l /a /[elos] sa4 s\0\p[310$] (?\p1[za] \p1[:c]
-[:c] l /e /[los] se3 s\0\p[10$] (?\p1[za] \p1[:c]
-[:c] l /l /[os] sl1 s\0\p[0$] (?\p1[za] \p1[:c]
-[:c] l /o /s so0 ss$ (?\p1[za] \p1[:c]
-[:c] l /a /e /[los] sa4 se3 s\0\p[10$] (?\p1[za] \p1[:c]
-[:c] l /a /l /[os] sa4 sl1 s\0\p[0$] (?\p1[za] \p1[:c]
-[:c] l /a /o /s sa4 so0 ss$ (?\p1[za] \p1[:c]
-[:c] l /e /l /[os] se3 sl1 s\0\p[0$] (?\p1[za] \p1[:c]
-[:c] l /[el] /o /s s\0\p[31] so0 ss$ (?\p1[za] \p1[:c]
-[:c] l /a /e /l /[os] sa4 se3 sl1 s\0\p[0$] (?\p1[za] \p1[:c]
-[:c] l /a /[el] /o /s sa4 s\0\p[31] so0 ss$ (?\p1[za] \p1[:c]
-[:c] l /e /l /o /s se3 sl1 so0 ss$ (?\p1[za] \p1[:c]
-[:c] l /a /e /l /o /s sa4 se3 sl1 so0 ss$ (?\p1[za] \p1[:c]
# Now to the prefix stuff...
l ^[1a-z2-90]
-c l Q ^[A-Z]
^[A-Z]
l ^["-/:-@\[-`{-~]
-[:c] <9 (?a \p1[lc] A0"[tT]he"
-[:c] <9 (?a \p1[lc] A0"[aA]my"
-[:c] <9 (?a \p1[lc] A0"[mdMD]r"
-[:c] <9 (?a \p1[lc] A0"[mdMD]r."
-[:c] <9 (?a \p1[lc] A0"__"
<- !?A l p ^[240-9]
# Some word pair rules...
# johnsmith -> JohnSmith, johnSmith
-p-c (?a 2 (?a c 1 [cl]
# JohnSmith -> john smith, john_smith, john-smith
-p 1 <- $[ _\-] + l
# JohnSmith -> John smith, John_smith, John-smith
-p-c 1 <- (?a c $[ _\-] 2 l
# JohnSmith -> john Smith, john_Smith, john-Smith
-p-c 1 <- l $[ _\-] 2 (?a c
# johnsmith -> John Smith, John_Smith, John-Smith
-p-c 1 <- (?a c $[ _\-] 2 (?a c
# Applying different simple rules to each of the two words
-p-[c:] 1 \p1[ur] 2 l
-p-c 2 (?a c 1 [ur]
-p-[c:] 1 l 2 \p1[ur]
-p-c 1 (?a c 2 [ur]
# jsmith -> smithj, etc...
-[:c] (?a \p1[lc] [{}]
-[:c] (?a \p1[lc] [{}] \0
# Toggle case...
-c <+ )?u l Tm
-c T0 Q M c Q l Q u Q C Q X0z0 'l
-c T[1-9A-E] Q M l Tm Q C Q u Q l Q c Q X0z0 'l
-c l Q T[1-9A-E] Q M T\0 Q l Tm Q C Q u Q X0z0 'l
-c >2 <G %2?a [lu] T0 M T2 T4 T6 T8 TA TC TE Q M l Tm Q X0z0 'l
-c >2 /?l /?u t Q M c Q C Q l Tm Q X0z0 'l
# Deleting chars...
>[2-8] D\p[1-7]
>[8-9A-E] D\1
-c /?u >[2-8] D\p[1-7] l
-c /?u >[8-9A-E] D\1 l
=1?a \[ M c Q
-c (?a >[1-9A-E] D\1 c
# Inserting a dot...
-[:c] >3 (?a \p1[lc] i[12].
# More suffix stuff...
<- l Az"[190][0-9]"
-c <- (?a c Az"[190][0-9]"
<- l Az"[782][0-9]"
-c <- (?a c Az"[782][0-9]"
<* l $[A-Z]
-c <* (?a c $[A-Z]
# cracking -> CRACKiNG
-c u /I sIi
# Crack96 -> cRACK96
%2?a C Q
# Crack96 -> cRACK(^
/?A S Q
# Crack96 -> CRaCK96
-c /?v V Q
# Really weird charset conversions, like "england" -> "rmh;smf"
:[RL] Q
l Q [RL]
-c (?a c Q [RL]
:[RL] \0 Q
# Both prefixing and suffixing...
<- l ^[1!@#$%^&*\-=_+.?|:'"] $\1
<- l ^[({[<] $\p[)}\]>]
# The rest of two-digit suffix stuff, less common numbers...
<- l Az"[63-5][0-9]"
-c <- (?a c Az"[63-5][0-9]"
# Some three-digit numbers...
-[:c] (?a \p1[lc] Az"007" <+
-[:c] (?a \p1[lc] Az"123" <+
-[:c] (?a \p1[lc] Az"[1-9]\0\0" <+
# Some [birth] years...
l Az"19[7-96-0]" <+ >-
l Az"20[01]" <+ >-
l Az"19[7-9][0-9]" <+
l Az"20[01][0-9]" <+
l Az"19[6-0][9-0]" <+
# Uncomment the following lines if you're really crazy
;# Insert/overstrike some characters...
;!?A >[1-6] l i\0[a-z]
;!?A l o0[a-z]
;!?A >[1-7] l o\0[a-z]
;# Toggle case everywhere (up to length 8), assuming that certain case
;# combinations were already tried.
;-c T1 Q M T0 Q
;-c T2 Q M T[z0] T[z1] Q
;-c T3 Q M T[z0] T[z1] T[z2] Q
;-c T4 Q M T[z0] T[z1] T[z2] T[z3] Q
;-c T5 Q M T[z0] T[z1] T[z2] T[z3] T[z4] Q
;-c T6 Q M T[z0] T[z1] T[z2] T[z3] T[z4] T[z5] Q
;-c T7 Q M T[z0] T[z1] T[z2] T[z3] T[z4] T[z5] T[z6] Q
;# Very slow stuff...
;l Az"[1-90][0-9][0-9]" <+
;-c (?a c Az"[1-90][0-9][0-9]" <+
;<[\-9] l A\p[z0]"[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 !?X l Q
# Capitalize every pure alphanumeric word
-c (?a >2 !?X c Q
# Lowercase and pluralize pure alphabetic words
<* >2 !?A l p
# Lowercase pure alphabetic words and append '1'
<* >2 !?A l $1
# Capitalize pure alphabetic words and append '1'
-c <* >2 !?A c $1
# Duplicate reasonably short pure alphabetic words (fred -> fredfred)
<7 >1 !?A l d
# Lowercase and reverse pure alphabetic words
>3 !?A l M r Q
# Prefix pure alphabetic words with '1'
>2 !?A l ^1
# Uppercase pure alphanumeric words
-c >2 !?X u Q M c Q u
# Lowercase pure alphabetic words and append a digit or simple punctuation
<* >2 !?A l $[2!37954860.?]
# Words containing punctuation, which is then squeezed out, lowercase
/?p @?p >3 l
# Words with vowels removed, lowercase
/?v @?v >3 l
# Words containing whitespace, which is then squeezed out, lowercase
/?w @?w >3 l
# Capitalize and duplicate short pure alphabetic words (fred -> FredFred)
-c <7 >1 !?A c d
# Capitalize and reverse pure alphabetic words (fred -> derF)
-c <+ >2 !?A c r
# Reverse and capitalize pure alphabetic words (fred -> Derf)
-c >2 !?A l M r Q c
# Lowercase and reflect pure alphabetic words (fred -> fredderf)
<7 >1 !?A l d M 'l f Q
# Uppercase the last letter of pure alphabetic words (fred -> freD)
-c <+ >2 !?A l M r Q c r
# Prefix pure alphabetic words with '2' or '4'
>2 !?A l ^[24]
# Capitalize pure alphabetic words and append a digit or simple punctuation
-c <* >2 !?A c $[2!3957468.?0]
# Prefix pure alphabetic words with digits
>2 !?A l ^[379568]
# Capitalize and pluralize pure alphabetic words of reasonable length
-c <* >2 !?A c p
# Lowercase/capitalize pure alphabetic words of reasonable length and convert:
# crack -> cracked, crack -> cracking
-[:c] <* >2 !?A \p1[lc] M [PI] Q
# Try the second half of split passwords
-s x**
-s-c x** M l Q
# Prepend "pass"
A0"[pP][aA][sS][sS]"
# 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]
:
-c T0Q
-c T1QT[z0]
-c T2QT[z0]T[z1]
-c T3QT[z0]T[z1]T[z2]
-c T4QT[z0]T[z1]T[z2]T[z3]
-c T5QT[z0]T[z1]T[z2]T[z3]T[z4]
-c T6QT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]
-c T7QT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]
-c T8QT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7]
-c T9QT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7]T[z8]
-c TAQT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7]T[z8]T[z9]
-c TBQT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7]T[z8]T[z9]T[zA]
-c TCQT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7]T[z8]T[z9]T[zA]T[zB]
-c TDQT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7]T[z8]T[z9]T[zA]T[zB]T[zC]
# Incremental modes
[Incremental:All]
File = $JOHN/all.chr
MinLen = 0
MaxLen = 8
CharCount = 95
[Incremental:All4]
File = $JOHN/all.chr
MinLen = 0
MaxLen = 4
CharCount = 95
[Incremental:Alpha]
File = $JOHN/alpha.chr
MinLen = 1
MaxLen = 8
CharCount = 26
[Incremental:Digits]
File = $JOHN/digits.chr
MinLen = 1
MaxLen = 8
CharCount = 10
[Incremental:Digits5]
File = $JOHN/digits.chr
MinLen = 1
MaxLen = 5
CharCount = 10
[Incremental:Alnum]
File = $JOHN/alnum.chr
MinLen = 1
MaxLen = 8
CharCount = 36
[Incremental:LanMan]
File = $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_No_Cap_or_Symbols]
void filter()
{
int i, c;
i = 0;
while (c = word[i++])
if ((c < 'a' || c > 'z') && (c < '0' || c > '9')) {
return;
}
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];
}
# A variation of KnownForce configured to try likely date and time strings.
[List.External:DateTime]
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; // Must be one of: 4, 5, 7, 8
/* This defines the character sets for different character positions */
pos = 0;
while (pos < length - 6) {
ofs = pos++ << 8;
i = 0;
c = '0';
while (c <= '9')
charset[ofs + i++] = c++;
charset[ofs + i] = 0;
}
if (pos) {
ofs = pos++ << 8;
charset[ofs] = '/';
charset[ofs + 1] = '.';
charset[ofs + 2] = ':';
charset[ofs + 3] = 0;
}
while (pos < length - 3) {
ofs = pos++ << 8;
i = 0;
c = '0';
while (c <= '9')
charset[ofs + i++] = c++;
charset[ofs + i] = 0;
}
ofs = pos++ << 8;
charset[ofs] = '/';
charset[ofs + 1] = '.';
charset[ofs + 2] = ':';
charset[ofs + 3] = 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];
}
# Try strings of repeated characters.
[List.External:Repeats]
int minlength, maxlength, minc, maxc, length, c;
void init()
{
minlength = 1;
maxlength = 72;
minc = 0x20;
maxc = 0xff;
length = minlength; c = minc;
}
void generate()
{
int i;
i = 0;
while (i < length)
word[i++] = c;
word[i] = 0;
if (c++ < maxc)
return;
c = minc;
if (++length > maxlength)
c = 0; // Will NUL out the next "word" and thus terminate
}
# Generate candidate passwords from many small subsets of characters from a
# much larger full character set. This will test for passwords containing too
# few different characters. As currently implemented, this code will produce
# some duplicates, although their number is relatively small when the maximum
# number of different characters (the maxdiff setting) is significantly lower
# than the maximum length (the maxlength setting). Nevertheless, you may want
# to pass the resulting candidate passwords through "unique" if you intend to
# test them against hashes that are salted and/or of a slow to compute type.
[List.External:Subsets]
int minlength; // Minimum password length to try
int maxlength; // Maximum password length to try
int startdiff; // Initial number of characters in a subset to try
int maxdiff; // Maximum number of characters in a subset 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 subset[0x100], c0; // Current subset
int subcount; // Number of characters in the current subset
int subid[0x100]; // Indices into charset[] of characters in subset[]
int charset[0x100]; // Full character set
int charcount; // Number of characters in the full charset
void init()
{
int i, c;
minlength = 1; // Minimum password length to try, must be at least 1
maxlength = 8; // Must be at least same as minlength
startdiff = 1; // Initial number of different characters to try
maxdiff = 3; // Maximum number of different characters to try
/* This defines the character set */
i = 0;
c = 0x20;
while (c <= 0x7e)
charset[i++] = c++;
if (maxdiff > (charcount = i))
maxdiff = i;
if (maxdiff > maxlength)
maxdiff = maxlength;
/*
* Initialize the variables such that generate() gets to its "next subset"
* code, which will initialize everything for real.
*/
subcount = (i = startdiff) - 1;
while (i--)
subid[i] = charcount;
subset[0] = c0 = 0;
last = maxlength - 1;
lastid = -1;
}
void generate()
{
int i;
/* Handle the typical case specially */
if (word[last] = subset[++lastid]) return;
lastid = 0;
word[i = last] = c0;
while (i--) { // Have a preceding position?
if (word[i] = subset[++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;
return;
}
/* Next subset */
if (subcount) {
int j;
i = subcount - 1;
j = charcount;
while (++subid[i] >= j) {
if (i--) {
j--;
continue;
}
subid[i = 0] = 0;
subset[++subcount] = 0;
break;
}
} else {
subid[i = 0] = 0;
subset[++subcount] = 0;
}
subset[i] = charset[subid[i]];
while (++i < subcount)
subset[i] = charset[subid[i] = subid[i - 1] + 1];
if (subcount > maxdiff) {
word = 0; // Done
return;
}
/*
* We won't be able to fully use the subset if the length is smaller than the
* character count. We assume that we've tried all smaller subsets before, so
* we don't bother with such short lengths.
*/
if (minlength < subcount)
last = subcount - 1;
else
last = minlength - 1;
c0 = subset[0];
i = 0;
while (i <= last) {
id[i] = 0;
word[i++] = c0;
}
lastid = 0;
word[i] = 0;
}
# Simple password policy matching: require at least one digit.
[List.External:AtLeast1-Simple]
void filter()
{
int i, c;
i = 0;
while (c = word[i++])
if (c >= '0' && c <= '9')
return; // Found at least one suitable character, good
word = 0; // No suitable characters found, skip this "word"
}
# The same password policy implemented in a more efficient and more generic
# fashion (easy to expand to include other "sufficient" characters as well).
[List.External:AtLeast1-Generic]
int mask[0x100];
void init()
{
int c;
mask[0] = 0; // Terminate the loop in filter() on NUL
c = 1;
while (c < 0x100)
mask[c++] = 1; // Continue looping in filter() on most chars
c = '0';
while (c <= '9')
mask[c++] = 0; // Terminate the loop in filter() on digits
}
void filter()
{
int i;
i = -1;
while (mask[word[++i]])
continue;
if (word[i])
return; // Found at least one suitable character, good
word = 0; // No suitable characters found, skip this "word"
}
# An efficient and fairly generic password policy matcher. The policy to match
# is specified in the check at the end of filter() and in mask[]. For example,
# lowercase and uppercase letters may be treated the same by initializing the
# corresponding mask[] elements to the same value, then adjusting the value to
# check "seen" for accordingly.
[List.External:Policy]
int mask[0x100];
void init()
{
int c;
mask[0] = 0x100;
c = 1;
while (c < 0x100)
mask[c++] = 0x200;
c = 'a';
while (c <= 'z')
mask[c++] = 1;
c = 'A';
while (c <= 'Z')
mask[c++] = 2;
c = '0';
while (c <= '9')
mask[c++] = 4;
}
void filter()
{
int i, seen;
/*
* This loop ends when we see NUL (sets 0x100) or a disallowed character
* (sets 0x200).
*/
i = -1; seen = 0;
while ((seen |= mask[word[++i]]) < 0x100)
continue;
/*
* We should have seen at least one character of each type (which "add up"
* to 7) and then a NUL (adds 0x100), but not any other characters (would
* add 0x200). The length must be 8.
*/
if (seen != 0x107 || i != 8)
word = 0; // Does not conform to policy
}
# Append the Luhn algorithm digit to arbitrary all-digit strings. Optimized
# for speed, not for size nor simplicity. The primary optimization trick is to
# compute the length and four sums in parallel (in two SIMD'ish variables).
# Then whether the length is even or odd determines which two of the four sums
# are actually used. Checks for non-digits and for NUL are packed into the
# SIMD'ish bitmasks as well.
[List.External:AppendLuhn]
int map1[0x100], map2[0x1fff];
void init()
{
int i;
map1[0] = ~0x7fffffff;
i = 1;
while (i < 0x100)
map1[i++] = ~0x7effffff;
i = -1;
while (++i < 10)
map1['0' + i] = i + ((i * 2 % 10 + i / 5) << 12);
i = -1;
while (++i < 0x1fff) {
if (i % 10)
map2[i] = '9' + 1 - i % 10;
else
map2[i] = '0';
}
}
void filter()
{
int i, o, e;
i = o = e = 0;
while ((o += map1[word[i++]]) >= 0) {
if ((e += map1[word[i++]]) >= 0)
continue;
if (e & 0x01000000)
return; // Not all-digit, leave unmodified
word[i--] = 0;
word[i] = map2[(e & 0xfff) + (o >> 12)];
return;
}
if (o & 0x01000000)
return; // Not all-digit, leave unmodified
word[i--] = 0;
word[i] = map2[(o & 0xfff) + (e >> 12)];
}
# Here are some examples of GENERIC-MD5.
# Please refer to doc/MD5_GENERIC for documentation on how to set these up.
####################################################################
# Simple GENERIC-MD5 type for md5($p)^^4 (i.e. 4 steps of md5 recursively)
####################################################################
[List.Generic:md5_gen(1001)]
# expression shown will be the string: md5_gen(1001) md5(md5(md5(md5($p))))
Expression=md5(md5(md5(md5($p))))
Flag=MGF_KEYS_INPUT
# here is the optimized 'script' to perform the md5 4 times on itself.
Func=MD5GenBaseFunc__crypt
Func=MD5GenBaseFunc__clean_input2
Func=MD5GenBaseFunc__append_from_last_output_to_input2_as_base16
Func=MD5GenBaseFunc__crypt2
Func=MD5GenBaseFunc__clean_input2_kwik
Func=MD5GenBaseFunc__append_from_last_output2_as_base16
Func=MD5GenBaseFunc__crypt2
Func=MD5GenBaseFunc__clean_input2_kwik
Func=MD5GenBaseFunc__append_from_last_output2_as_base16
Func=MD5GenBaseFunc__crypt_in2_to_out1
Test=md5_gen(1001)57200e13b490d4ae47d5e19be026b057:test1
Test=md5_gen(1001)c6cc44f9e7fb7efcde62ba2e627a49c6:thatsworking
Test=md5_gen(1001)0ae9549604e539a249c1fa9f5e5fb73b:test3
####################################################################
# Simple GENERIC-MD5 type for md5($p)^^5 (i.e. 5 steps of md5 recursively)
####################################################################
[List.Generic:md5_gen(1002)]
# expression shown will be the string: md5_gen(1002) md5(md5(md5(md5(md5($p)))))
Expression=md5(md5(md5(md5(md5($p)))))
Flag=MGF_KEYS_INPUT
# here is the optimized 'script' to perform the md5 5 times on itself.
Func=MD5GenBaseFunc__crypt
Func=MD5GenBaseFunc__clean_input2
Func=MD5GenBaseFunc__append_from_last_output_to_input2_as_base16
Func=MD5GenBaseFunc__crypt2
Func=MD5GenBaseFunc__clean_input2_kwik
Func=MD5GenBaseFunc__append_from_last_output2_as_base16
Func=MD5GenBaseFunc__crypt2
Func=MD5GenBaseFunc__clean_input2_kwik
Func=MD5GenBaseFunc__append_from_last_output2_as_base16
Func=MD5GenBaseFunc__crypt2
Func=MD5GenBaseFunc__clean_input2_kwik
Func=MD5GenBaseFunc__append_from_last_output2_as_base16
Func=MD5GenBaseFunc__crypt_in2_to_out1
# These are test strings for this format.
Test=md5_gen(1002)25de8cd0b0cf69c5b5bc19c8ee64adab:test1
Test=md5_gen(1002)a0b535420ea47849f7c2cc09a3ad0ac3:thatsworking
Test=md5_gen(1002)4cb029bd5b4ef79f785ca685caf17bf8:test3
####################################################################
# Simple GENERIC-MD5 type for md5(md5($p).md5($p))
####################################################################
[List.Generic:md5_gen(1003)]
# expression shown will be the string: md5_gen(1003) md5(md5($p).md5($p))
Expression=md5(md5($p).md5($p))
# NOTE, this format does NOT work on SSE2. It requires a md5() of a 64 byte string.
# SSE (or MMX) is limtited to 54 byte max password, due to 'enhancements'
# Thus, we need a non-sse2 safe flag.
Flag=MGF_NOTSSE2Safe
Flag=MGF_KEYS_INPUT
# here is the optimized 'script' to perform hash 'like' IPB but salt replaced with password.
Func=MD5GenBaseFunc__crypt
Func=MD5GenBaseFunc__clean_input2_kwik
Func=MD5GenBaseFunc__append_from_last_output_to_input2_as_base16
Func=MD5GenBaseFunc__append_from_last_output_to_input2_as_base16
Func=MD5GenBaseFunc__crypt_in2_to_out1
# These are test strings for this format.
Test=md5_gen(1003)478b10974f15e7295883224fd286ccba:test1
Test=md5_gen(1003)18a59101e6c6fb38260d542a394ecb22:thatsworking
Test=md5_gen(1003)630b01b68b6db6fd43a751f8147d1faf:test3
####################################################################
# Simple GENERIC-MD5 type for md5($p)^^6 (i.e. 6 steps of md5 recursively)
####################################################################
[List.Generic:md5_gen(1004)]
# expression shown will be the string: md5_gen(1004) md5(md5(md5(md5(md5(md5($p))))))
Expression=md5(md5(md5(md5(md5(md5($p))))))
Flag=MGF_KEYS_INPUT
# here is the optimized 'script' to perform the md5 6 times on itself.
Func=MD5GenBaseFunc__crypt
Func=MD5GenBaseFunc__clean_input2
Func=MD5GenBaseFunc__append_from_last_output_to_input2_as_base16
Func=MD5GenBaseFunc__crypt2
Func=MD5GenBaseFunc__clean_input2_kwik
Func=MD5GenBaseFunc__append_from_last_output2_as_base16
Func=MD5GenBaseFunc__crypt2
Func=MD5GenBaseFunc__clean_input2_kwik
Func=MD5GenBaseFunc__append_from_last_output2_as_base16
Func=MD5GenBaseFunc__crypt2
Func=MD5GenBaseFunc__clean_input2_kwik
Func=MD5GenBaseFunc__append_from_last_output2_as_base16
Func=MD5GenBaseFunc__crypt2
Func=MD5GenBaseFunc__clean_input2_kwik
Func=MD5GenBaseFunc__append_from_last_output2_as_base16
Func=MD5GenBaseFunc__crypt_in2_to_out1
# These are test strings for this format.
Test=md5_gen(1004)de1b991dd27fb9813e88b957a455dccd:test1
Test=md5_gen(1004)6a62cd3c4d81139f61fb2553cdef0dc7:thatsworking
Test=md5_gen(1004)a977990e521c5d1d17c6d65fdf2681b4:test3
####################################################################
# Simple GENERIC-MD5 type for md5($p)^^7 (i.e. 7 steps of md5 recursively)
####################################################################
[List.Generic:md5_gen(1005)]
# expression shown will be the string: md5_gen(1005) md5(md5(md5(md5(md5(md5(md5($p)))))))
Expression=md5(md5(md5(md5(md5(md5(md5($p)))))))
Flag=MGF_KEYS_INPUT
# here is the optimized 'script' to perform the md5 7 times on itself.
Func=MD5GenBaseFunc__crypt
Func=MD5GenBaseFunc__clean_input2
Func=MD5GenBaseFunc__append_from_last_output_to_input2_as_base16
Func=MD5GenBaseFunc__crypt2
Func=MD5GenBaseFunc__clean_input2_kwik
Func=MD5GenBaseFunc__append_from_last_output2_as_base16
Func=MD5GenBaseFunc__crypt2
Func=MD5GenBaseFunc__clean_input2_kwik
Func=MD5GenBaseFunc__append_from_last_output2_as_base16
Func=MD5GenBaseFunc__crypt2
Func=MD5GenBaseFunc__clean_input2_kwik
Func=MD5GenBaseFunc__append_from_last_output2_as_base16
Func=MD5GenBaseFunc__crypt2
Func=MD5GenBaseFunc__clean_input2_kwik
Func=MD5GenBaseFunc__append_from_last_output2_as_base16
Func=MD5GenBaseFunc__crypt2
Func=MD5GenBaseFunc__clean_input2_kwik
Func=MD5GenBaseFunc__append_from_last_output2_as_base16
Func=MD5GenBaseFunc__crypt_in2_to_out1
# These are test strings for this format.
Test=md5_gen(1005)784c527d0d92873ff9c0773e1c35621d:test1
Test=md5_gen(1005)efcbbe6331caecf0e7f40160e65aadcc:thatsworking
Test=md5_gen(1005)abb8bdd2c6ac2dfea2b2af6f5aed5446:test3
####################################################################
# Simple GENERIC-MD5 type for md5($p)^^8 (i.e. 8 steps of md5 recursively)
####################################################################
[List.Generic:md5_gen(1006)]
# expression shown will be the string: md5_gen(1006) md5(md5(md5(md5(md5(md5(md5(md5($p))))))))
Expression=md5(md5(md5(md5(md5(md5(md5(md5($p))))))))
Flag=MGF_KEYS_INPUT
# here is the optimized 'script' to perform the md5 8 times on itself.
Func=MD5GenBaseFunc__crypt
Func=MD5GenBaseFunc__clean_input2
Func=MD5GenBaseFunc__append_from_last_output_to_input2_as_base16
Func=MD5GenBaseFunc__crypt2
Func=MD5GenBaseFunc__clean_input2_kwik
Func=MD5GenBaseFunc__append_from_last_output2_as_base16
Func=MD5GenBaseFunc__crypt2
Func=MD5GenBaseFunc__clean_input2_kwik
Func=MD5GenBaseFunc__append_from_last_output2_as_base16
Func=MD5GenBaseFunc__crypt2
Func=MD5GenBaseFunc__clean_input2_kwik
Func=MD5GenBaseFunc__append_from_last_output2_as_base16
Func=MD5GenBaseFunc__crypt2
Func=MD5GenBaseFunc__clean_input2_kwik
Func=MD5GenBaseFunc__append_from_last_output2_as_base16
Func=MD5GenBaseFunc__crypt2
Func=MD5GenBaseFunc__clean_input2_kwik
Func=MD5GenBaseFunc__append_from_last_output2_as_base16
Func=MD5GenBaseFunc__crypt2
Func=MD5GenBaseFunc__clean_input2_kwik
Func=MD5GenBaseFunc__append_from_last_output2_as_base16
Func=MD5GenBaseFunc__crypt_in2_to_out1
# These are test strings for this format.
Test=md5_gen(1006)1ec1f32398f64cab51183f63630eceea:test1
Test=md5_gen(1006)f66b339ac21d6fd6af216f2b70aab2c9:thatsworking
Test=md5_gen(1006)e9d38522b5eeec753332e576e2e0fe5d:test3
####################################################################
# Simple GENERIC-MD5 type for vBulletin md5(md5($p).$s) Included here to 'exercise' the script parser
####################################################################
[List.Generic:md5_gen(1007)]
# expression shown will be the string: md5_gen(1007) md5(md5($p).$s) [vBulletin]
Expression=md5(md5($p).$s) [vBulletin]
# Flag needed here, is Salt. There is no 'fixed' saltlen.
Flag=MGF_SALTED
Flag=MGF_ColonNOTValid
Flag=MGF_KEYS_BASE16_IN1
# vBulletin has a 'fixed' 3 byte salt, so list the fixed size
SaltLen=3
ColonChar=;
# here is the optimized 'script' to perform vBulletin hash
Func=MD5GenBaseFunc__set_input_len_32
Func=MD5GenBaseFunc__append_salt
Func=MD5GenBaseFunc__crypt
# NOTE, vBulletin is setup to 'override' the ':'. USUALLY, it is good to use something
# outside of the ASCII values from 0x20 to 0x7F. 0x1F is a 'good' choice, but it will
# cause john.conf to have a 'non-normal' ASCII char. Thus for this 'simple' example, I
# have used the ';' character. NOTE this would have the same 'problems' as the ':' character
# if used for real, since ; is also a valid character within the salt of vBulletin.
# NOTE to run, you MUST use the command line switch: -field-separator-char=;
Test=md5_gen(1007)daa61d77e218e42060c2fa198ac1feaf$SXB;test1
Test=md5_gen(1007)de56b00bb15d6db79204bd44383469bc$T &;thatsworking
Test=md5_gen(1007)fb685c6f469f6e549c85e4c1fb5a65a6$\\H:;test3
####################################################################
# Simple GENERIC-MD5 type for joomla md5($p.$s) Included here to 'exercise' the script parser
####################################################################
[List.Generic:md5_gen(1008)]
# expression shown will be the string: md5_gen(1008) md5($p.$s) [joomla]
Expression=md5($p.$s) [joomla]
# Flag needed here, is Salt. There is no 'fixed' saltlen.
Flag=MGF_SALTED
# here is the optimized 'script' to perform the md5 8 times on itself.
Func=MD5GenBaseFunc__clean_input
Func=MD5GenBaseFunc__append_keys
Func=MD5GenBaseFunc__append_salt
Func=MD5GenBaseFunc__crypt
Test=md5_gen(1008)ed52af63d8ecf0c682442dfef5f36391$1aDNNojYGSc7pSzcdxKxhbqvLtEe4deG:test1
Test=md5_gen(1008)4fa1e9d54d89bfbe48b4c0f0ca0a3756$laxcaXPjgcdKdKEbkX1SIjHKm0gfYt1c:thatsworking
Test=md5_gen(1008)82568eeaa1fcf299662ccd59d8a12f54$BdWwFsbGtXPGc0H1TBxCrn0GasyAlJBJ:test3
[List.Rules:KoreLogicRules]
;[List.Rules:KoreLogicRulesPrependNumNum]
-[c:] \p[c:] A0"[0-9][0-9]"
;[List.Rules:KoreLogicRulesPrependYears]
A0"20[0-1][0-9]"
A0"19[3-9][0-9]"
# Notice: Your wordlist should likely be all lowercase - or you are wasting work
;[List.Rules:KoreLogicRulesAppendYears]
-[c:] \p[c:] Az"19[0-9][0-9]" <+
-[c:] \p[c:] Az"20[01][0-9]" <+
;[List.Rules:KoreLogicRulesPrependNumNumNum]
-[c:] \p[c:] A0"[0-9][0-9][0-9]"
;[List.Rules:KoreLogicRulesMonthsFullPreface]
-[:c] A0"\p[jJ]anuary"
-[:c] A0"\p[fF]ebruary"
-[:c] A0"\p[mM]arch"
-[:c] A0"\p[aA]pril"
-[:c] A0"\p[mM]ay"
-[:c] A0"\p[jJ]uner"
-[:c] A0"\p[jJ]uly"
-[:c] A0"\p[aA]ugust"
-[:c] A0"\p[sS]eptember"
-[:c] A0"\p[oO]ctober"
-[:c] A0"\p[nN]ovember"
-[:c] A0"\p[dD]ecember"
;[List.Rules:KoreLogicRulesPrepend4LetterMonths]
## Preface each dictionary with Janu janu Febr febr
-[:c] A0"\p[jJ]anu"
-[:c] A0"\p[fF]ebr"
-[:c] A0"\p[mM]arc"
-[:c] A0"\p[aA]pr"
-[:c] A0"\p[mM]ay"
-[:c] A0"\p[jJ]une"
-[:c] A0"\p[jJ]uly"
-[:c] A0"\p[Aa]ugu"
-[:c] A0"\p[sS]ept"
-[:c] A0"\p[oO]cto"
-[:c] A0"\p[nN]ove"
-[:c] A0"\p[Dd]ece"
# Use this rule with 2EVERYTHING.dic or 3EVERYTHING.dic
;[List.Rules:KoreLogicRulesPrependSeason]
A0"[Ss$][uU][mM][mM][eE3][rR]"
A0"[Ww][iI|][nN][tT+][eE3][rR]"
A0"[Ff][aA][lL][lL]"
A0"[Ss][pP][rR][iI][nN][gG]"
A0"[Aa][uU][tT][uU][mM][nN]"
# Use this rule with 2EVERYTHING.dic or 3EVERYTHING.dic
;[List.Rules:KoreLogicRulesAppendSeason]
<* Az"[Ss$][uU][mM][mM][eE3][rR]"
<* Az"[Ww][iI|][nN][tT+][eE3][rR]"
<* Az"[Ff][aA][lL][lL]"
<* Az"[Ss][pP][rR][iI][nN][gG]"
<* Az"[Aa][uU][tT][uU][mM][nN]"
;[List.Rules:KoreLogicRulesPrependHello]
A0"[hH][eE][lL][lL][oO0]"
# Notice how we
# 1) do caps first b/c they are more common in 'complex' environments
# 2) Do !$@#%. first b/c they are the most common special chars
;[List.Rules:KoreLogicRulesAppendCurrentYearSpecial]
-[c:] \p[c:] Az"201[0-9][!$@#%.]" <+
-[c:] \p[c:] Azq201[0-9][^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+
;[List.Rules:KoreLogicRulesPrependSpecialSpecial]
-[c:] \p[c:] A0q[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q
;[List.Rules:KoreLogicRulesAppend2Letters]
<- Az"[a-z][a-z]"
-c <- Az"[A-Z][A-Z]"
-c <- Az"[a-z][A-Z]"
-c <- Az"[A-Z][a-z]"
# Append numbers - but limit the total length.
;[List.Rules:KoreLogicRulesAddJustNumbers]
-[c:] <* >1 \p[c:] $[0-9]
-[c:] <* >1 \p[c:] ^[0-9]
-[c:] <- >1 \p[c:] Az"[0-9][0-9]"
-[c:] <- >1 \p[c:] A0"[0-9][0-9]"
-[c:] >1 \p[c:] Az"[0-9][0-9][0-9]" <+
# Redundant with KoreLogicRulesAppend4Num
;-[c:] >1 \p[c:] Az"[0-9][0-9][0-9][0-9]" <+
;[List.Rules:KoreLogicRulesDevProdTestUAT]
-\r[::cc] <* A\p\r[0l0l]"dev" \p\r[::TT]\p\r[::0l]
-\r[::cc] <* A\p\r[0l0l]"uat" \p\r[::TT]\p\r[::0l]
-\r[::cc] <* A\p\r[0l0l]"prod" \p\r[::TT]\p\r[::0l]
-\r[::cc] <* A\p\r[0l0l]"test" \p\r[::TT]\p\r[::0l]
;[List.Rules:KoreLogicRulesPrependAndAppendSpecial]
-[c:] <- \p[c:] ^[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] $[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]
# Redundant with KoreLogicRulesAddJustNumbers and KoreLogicRulesAppend4Num
;[List.Rules:KoreLogicRulesAppendJustNumbers]
;-[c:] <* \p[c:] $[0-9]
;-[c:] <- \p[c:] Az"[0-9][0-9]"
;-[c:] \p[c:] Az"[0-9][0-9][0-9]" <+
;-[c:] \p[c:] Az"[0-9][0-9][0-9][0-9]" <+
;[List.Rules:KoreLogicRulesAppendNumbers_and_Specials_Simple]
# cap first letter then add a 0 2 6 9 ! * to the end
-[c:] <* \p[c:] $[0-9!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]
# cap first letter then add a special char - THEN a number !0 %9 !9 etc
-[c:] <- \p[c:] Azq[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*][0-9]q
# Cap the first letter - then add 0? 0! 5_ .. 9!
## add NUMBER then SPECIAL 1! .. 9?
-[c:] <- \p[c:] Azq[0-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q
## Add Number Number Special
;-[c:] \p[c:] Azq[0-9][0-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+
## Add Special Number Number
;-[c:] \p[c:] Azq[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*][0-9][0-9]q <+
# Add 100! ... 999! to the end
;-[c:] \p[c:] Azq[0-9][0-9][0-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+
;[List.Rules:KoreLogicRulesAppendJustSpecials]
-[c:] <* \p[c:] $[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]
-[c:] <- \p[c:] Azq[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q
;[List.Rules:KoreLogicRulesAddShortMonthsEverywhere]
<* >\r[00123456789] A\p[z0-9]"[jJ][aA][nN]"
<* >\r[00123456789] A\p[z0-9]"[fF][eE][bB]"
<* >\r[00123456789] A\p[z0-9]"[mM][aA][rRyY]"
<* >\r[00123456789] A\p[z0-9]"[aA][pP][rR]"
<* >\r[00123456789] A\p[z0-9]"[jJ][uU][nNlL]"
<* >\r[00123456789] A\p[z0-9]"[aA][uU][gG]"
<* >\r[00123456789] A\p[z0-9]"[sS][eE][pP]"
<* >\r[00123456789] A\p[z0-9]"[oO][cC][tT]"
<* >\r[00123456789] A\p[z0-9]"[nN][oO][vV]"
<* >\r[00123456789] A\p[z0-9]"[dD][eE][cC]"
# this will add the string '2010' at all places in the word:
# USE this with a 4 or 5 char dictionary file with ALL characters
# soo abcde will become
# 2010abcde a2010bcde ab2010cde acd2010de abcd2010e abcde2010
;[List.Rules:KoreLogicRulesAdd2010Everywhere]
<* >\r[00123456789] A\p[z0-9]"201[0-9]"
;[List.Rules:KoreLogicRulesAdd1234_Everywhere]
<* >\r[00123456789] A\p[z0-9]"1234"
;[List.Rules:KoreLogicRulesAppendMonthDay]
-[:c] <* Az"\p[jJ]anuary"
-[:c] Az"\p[jJ]anuary[0-9]" <+
-[:c] Az"\p[jJ]anuary[0-9][0-9]" <+
-[:c] <* Az"\p[fF]ebruary"
-[:c] Az"\p[fF]ebruary[0-9]" <+
-[:c] Az"\p[fF]ebruary[0-9][0-9]" <+
-[:c] Az"\p[mM]arch"
-[:c] Az"\p[mM]arch[0-9]" <+
-[:c] Az"\p[mM]arch[0-9][0-9]" <+
-[:c] <* Az"\p[aA]pril"
-[:c] Az"\p[aA]pril[0-9]" <+
-[:c] Az"\p[aA]pril[0-9][0-9]" <+
-[:c] <* Az"\p[mM]ay"
-[:c] Az"\p[mM]ay[0-9]" <+
-[:c] Az"\p[mM]ay[0-9][0-9]" <+
-[:c] <* Az"\p[jJ]une"
-[:c] Az"\p[jJ]une[0-9]" <+
# There was a typo in Kore's original revision of this rule
-[:c] Az"\p[jJ]une[0-9][0-9]" <+
-[:c] <* Az"\p[jJ]uly"
-[:c] Az"\p[jJ]uly[0-9]" <+
-[:c] Az"\p[jJ]uly[0-9][0-9]" <+
-[:c] <* Az"\p[aA]ugust"
-[:c] Az"\p[aA]ugust[0-9]" <+
-[:c] Az"\p[aA]ugust[0-9][0-9]" <+
-[:c] <* Az"\p[sS]eptember"
-[:c] Az"\p[sS]eptember[0-9]" <+
# There was a typo in Kore's original revision of this rule
-[:c] Az"\p[sS]eptember[0-9][0-9]" <+
-[:c] <* Az"\p[oO]ctober"
-[:c] Az"\p[oO]ctober[0-9]" <+
-[:c] Az"\p[oO]ctober[0-9][0-9]" <+
-[:c] <* Az"\p[nN]ovember"
-[:c] Az"\p[nN]ovember[0-9]" <+
-[:c] Az"\p[nN]ovember[0-9][0-9]" <+
-[:c] <* Az"\p[dD]ecember"
-[:c] Az"\p[dD]ecember[0-9]" <+
-[:c] Az"\p[dD]ecember[0-9][0-9]" <+
;[List.Rules:KoreLogicRulesAppendMonthCurrentYear]
-[:c] <* Az"\p[jJ]an201[0-9]"
-[:c] <* Az"\p[fF]eb201[0-9]"
-[:c] <* Az"\p[mM]ar201[0-9]"
-[:c] <* Az"\p[aA]pr201[0-9]"
-[:c] <* Az"\p[mM]ay201[0-9]"
-[:c] <* Az"\p[jJ]un201[0-9]"
-[:c] <* Az"\p[jJ]ul201[0-9]"
-[:c] <* Az"\p[Aa]ug201[0-9]"
-[:c] <* Az"\p[sS]ep201[0-9]"
-[:c] <* Az"\p[oO]ct201[0-9]"
-[:c] <* Az"\p[nN]ov201[0-9]"
-[:c] <* Az"\p[Dd]ec201[0-9]"
;[List.Rules:KoreLogicRulesReplaceNumbers2Special]
/[1-90] s\0\p[!@#$%^&*()]
/1 /[2-90] s1! s\0\p[@#$%^&*()]
/2 /[3-90] s2@ s\0\p[#$%^&*()]
/3 /[4-90] s3# s\0\p[$%^&*()]
/4 /[5-90] s4$ s\0\p[%^&*()]
/5 /[6-90] s5% s\0\p[^&*()]
/6 /[7-90] s6^ s\0\p[&*()]
/7 /[890] s7& s\0\p[*()]
/8 /[90] s8* s\0\p[()]
/9 /0 s9( s0)
;[List.Rules:KoreLogicRulesReplaceNumbers]
/0 s0[1-9]
/1 s1[02-9]
/2 s2[013-9]
/3 s3[0-24-9]
/4 s4[0-35-9]
/5 s5[0-46-9]
/6 s6[0-57-9]
/7 s7[0-68-9]
/8 s8[0-79]
/9 s9[0-8]
# 10 lines above can be replaced with just one:
# /[0-9] s\0[0-9] Q
# but it's slower (generates, then rejects some duplicates).
# This is a lamer/faster version of --rules:nt
;[List.Rules:KoreLogicRulesReplaceLettersCaps]
-c /[a-z] s\0\p[A-Z]
;[List.Rules:KoreLogicRulesAddDotCom]
-[c:] <- \p[c:] Az".com"
-[c:] <- \p[c:] Az".net"
-[c:] <- \p[c:] Az".org"
;[List.Rules:KoreLogicRulesPrependJustSpecials]
-[c:] \p[c:] ^[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]
-[c:] \p[c:] A0q[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q
;[List.Rules:KoreLogicRulesAppend1_AddSpecialEverywhere]
-[c:] >4 <- \p[c:] i[0-5][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] $1
-[c:] >[5-8] <- \p1[c:] i\p2[6-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] $1
;[List.Rules:KoreLogicRulesAppendNum_AddSpecialEverywhere]
# This should probably use $[02-9] since we try $1 in
# KoreLogicRulesAppend1_AddSpecialEverywhere
-[c:] >4 <- \p[c:] i[0-5][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] $[0-9]
-[c:] >[5-8] <- \p1[c:] i\p2[6-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] $[0-9]
;[List.Rules:KoreLogicRulesAppendNumNum_AddSpecialEverywhere]
-[c:] >4 \p[c:] i[0-5][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] Az"[0-9][0-9]" <+
-[c:] >[5-8] \p1[c:] i\p2[6-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] Az"[0-9][0-9]" <+
;[List.Rules:KoreLogicRulesAppendNumNumNum_AddSpecialEverywhere]
-[c:] >4 \p[c:] i[0-5][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] Az"[0-9][0-9][0-9]" <+
-[c:] >[5-8] \p1[c:] i\p2[6-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] Az"[0-9][0-9][0-9]" <+
;[List.Rules:KoreLogicRulesAppendYears_AddSpecialEverywhere]
-[c:] >4 \p[c:] i[0-5][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] Az"19[4-9][0-9]" <+
-[c:] >4 \p[c:] i[0-5][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] Az"20[0-1][0-9]" <+
-[c:] >[5-8] \p1[c:] i\p2[6-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] Az"19[4-9][0-9]" <+
-[c:] >[5-8] \p1[c:] i\p2[6-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] Az"20[0-1][0-9]" <+
# This rule needs work actually --- you have to 'sort -u' its output rick
# /a = reject if it doesnt have an 'a'
# the [:c] does waste some effort - and generate dupes. This is wasteful,
# but I want to keep it in b/c the original crack/JtR rules use it.
;[List.Rules:KoreLogicRulesL33t]
-[:c] /\r[aaAAbBeEiiiIIIllll] s\0\r\p[@44@88331!|1!|17|!] \p1[:M] \p1[:c] \p1[:Q]
# The following line differs from Kore's erroneous 4 lines:
-[:c] /\r[LLLL] s\0\r\p[17|!] \p1[:M] \p1[:c] \p1[:Q]
#/Lsl1[:c]
#/Lsl7[:c]
#/Lsl|[:c]
#/Lsl![:c]
-[:c] /\r[oOssSStT1111003344557788] s\0\r\p[00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q]
# Full set (same as above, but on one line):
#-[:c] /\r[aaAAbBeEiiiIIIllllLLLLoOssSStT1111003344557788] s\0\r\p[@44@88331!|1!|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q]
# Double substitutions start here.
# Compared to Kore's, we check for both chars first, then replace both.
# This produces different results from Kore's, which would replace all
# instances of the first char before checking for the second.
# Kore's behavior may be restored by moving "sa[@4]" to be right after "/a"
# on the line below, and ditto for further lines.
-[:c] /a /\r[AAbBeEiiiIIIllllLLLLoOssSStT1111003344557788] sa[@4] s\2\r\p2[4@88331!|1!|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q]
# Kore had these (probably unintentionally, so we don't duplicate them):
#/asa4/4s4a[:c]
#/asa4/4s4A[:c]
-[:c] /A /\r[aabBeEiiiIIIllllLLLLoOssSStT1111003344557788] sA4 s\0\r\p[@488331!|1!|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q]
# Kore also had these, but (intentionally?) missed sb8 on this set (after sA4)
#/AsA4/4s4a[:c]
#/AsA4/4s4A[:c]
-[:c] /b /\r[aaAABeEiiiIIIllllLLLLoOssSStT1111003344557788] sb8 s\0\r\p[@44@8331!|1!|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q]
-[:c] /B /\r[aaAAbeEiiiIIIllllLLLLoOssSStT1111003344557788] sB8 s\0\r\p[@44@8331!|1!|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q]
-[:c] /e /\r[aaAAbBEiiiIIIllllLLLLoOssSStT1111003344557788] se3 s\0\r\p[@44@8831!|1!|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q]
-[:c] /E /\r[aaAAbBeiiiIIIllllLLLLoOssSStT1111003344557788] sE3 s\0\r\p[@44@8831!|1!|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q]
-[:c] /i /\r[aaAAbBeEIIIllllLLLLoOssSStT1111003344557788] si[1!|] s\2\r\p2[@44@88331!|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q]
-[:c] /I /\r[aaAAbBeEiiillllLLLLoOssSStT1111003344557788] sI[1!|] s\2\r\p2[@44@88331!|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q]
# Kore's rules only included sl[17|], but not sl!
-[:c] /l /\r[aaAAbBeEiiiIIILLLLoOssSStT1111003344557788] sl[17|!] s\2\r\p2[@44@88331|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q]
# All "/L" rules (171 lines) were buggy
-[:c] /L /\r[aaAAbBeEiiiIIIlllloOssSStT1111003344557788] sl[17|!] s\2\r\p2[@44@88331|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q]
-[:c] /o /\r[aaAAbBeEiiiIIIllllLLLLOssSStT1111003344557788] so0 s\0\r\p[@44@88331!|1!|17|!17|!0$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q]
-[:c] /O /\r[aaAAbBeEiiiIIIllllLLLLossSStT1111003344557788] sO0 s\0\r\p[@44@88331!|1!|17|!17|!0$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q]
-[:c] /s /\r[aaAAbBeEiiiIIIllllLLLLoOSStT1111003344557788] ss[$5] s\2\r\p2[@44@88331!|1!|17|!17|!00$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q]
-[:c] /S /\r[aaAAbBeEiiiIIIllllLLLLoOsstT1111003344557788] sS[$5] s\2\r\p2[@44@88331!|1!|17|!17|!00$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q]
-[:c] /t /\r[aaAAbBeEiiiIIIllllLLLLoOssSST1111003344557788] st+ s\0\r\p[@44@88331!|1!|17|!17|!00$5$5+!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q]
-[:c] /T /\r[aaAAbBeEiiiIIIllllLLLLoOssSSt1111003344557788] sT+ s\0\r\p[@44@88331!|1!|17|!17|!00$5$5+!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q]
-[:c] /1 /\r[aaAAbBeEiiiIIIllllLLLLoOssSStT003344557788] s1[!iI|] s\2\r\p2[@44@88331!|1!|17|!17|!00$5$5++oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q]
-[:c] /0 /\r[aaAAbBeEiiiIIIllllLLLLoOssSStT11113344557788] s0[oO] s\2\r\p2[@44@88331!|1!|17|!17|!00$5$5++!iI|eEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q]
-[:c] /3 /\r[aaAAbBeEiiiIIIllllLLLLoOssSStT11110044557788] s3[eE] s\2\r\p2[@44@88331!|1!|17|!17|!00$5$5++!iI|oOaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q]
#-[:c] /\r[aaAAbBeEiiiIIIllllLLLLoOssSStT1111003344557788] s\0\r\p[@44@88331!|1!|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q]
-[:c] /4 /\r[aaAAbBeEiiiIIIllllLLLLoOssSStT11110033557788] s4[aA] s\2\r\p2[@44@88331!|1!|17|!17|!00$5$5++!iI|oOeEsSlLbB] \p1[:M] \p1[:c] \p1[:Q]
-[:c] /5 /\r[aaAAbBeEiiiIIIllllLLLLoOssSStT11110033447788] s5[sS] s\2\r\p2[@44@88331!|1!|17|!17|!00$5$5++!iI|oOeEaAlLbB] \p1[:M] \p1[:c] \p1[:Q]
-[:c] /7 /\r[aaAAbBeEiiiIIIllllLLLLoOssSStT11110033445588] s7[lL] s\2\r\p2[@44@88331!|1!|17|!17|!00$5$5++!iI|oOeEaAsSbB] \p1[:M] \p1[:c] \p1[:Q]
-[:c] /8 /\r[aaAAbBeEiiiIIIllllLLLLoOssSStT11110033445577] s8[bB] s\2\r\p2[@44@88331!|1!|17|!17|!00$5$5++!iI|oOeEaAsSlL] \p1[:M] \p1[:c] \p1[:Q]
# These are some popular triple/quad l33t rules
-[:c] /a /e /[los] sa4 se3 s\0\p[10$] \p1[:M] \p1[:c] \p1[:Q]
-[:c] /[ae] /l /[os] s\2\p2[43] sl1 s\3\p3[0$] \p1[:M] \p1[:c] \p1[:Q]
-[:c] /[ae] /o /s s\2\p2[43] so0 ss$ \p1[:M] \p1[:c] \p1[:Q]
-[:c] /l /o /s sl1 so0 ss$ \p1[:M] \p1[:c] \p1[:Q]
-[:c] /a /e /l /[os] sa4 se3 sl1 s\0\p[0$] \p1[:M] \p1[:c] \p1[:Q]
-[:c] /a /[el] /o /s sa4 s\0\p[31] so0 ss$ \p1[:M] \p1[:c] \p1[:Q]
-[:c] /e /l /o /s se3 sl1 so0 ss$ \p1[:M] \p1[:c] \p1[:Q]
-[:c] /a /e /l /o /s sa4 se3 sl1 so0 ss$ \p1[:M] \p1[:c] \p1[:Q]
;[List.Rules:KoreLogicRulesReplaceSpecial2Special]
# Kore's rules were missing "*"
/! s![@#$%^&*()\-=_+\\|;:'",./?><]
/@ s@[!#$%^&*()\-=_+\\|;:'",./?><]
/# s#[!@$%^&*()\-=_+\\|;:'",./?><]
/$ s$[!@#%^&*()\-=_+\\|;:'",./?><]
/% s%[!@#$^&*()\-=_+\\|;:'",./?><]
/^ s^[!@#$%&*()\-=_+\\|;:'",./?><]
/& s&[!@#$%^*()\-=_+\\|;:'",./?><]
/( s([!@#$%^&*)\-=_+\\|;:'",./?><]
/) s([!@#$%^&*(\-=_+\\|;:'",./?><]
# Kore's ruleset erroneously had:
#/-s--
/- s-[!@#$%^&*()=_+\\|;:'",./?><]
/= s=[!@#$%^&*()\-_+\\|;:'",./?><]
/_ s_[!@#$%^&*()\-=+\\|;:'",./?><]
/+ s+[!@#$%^&*()\-=_\\|;:'",./?><]
# Kore's rules did not replace backslash
/\\ s\\[!@#$%^&*()\-=_+|;:'",./?><]
/| s|[!@#$%^&*()\-=_+\\;:'",./?><]
/; s;[!@#$%^&*()\-=_+\\|:'",./?><]
/: s:[!@#$%^&*()\-=_+\\|;'",./?><]
/' s'[!@#$%^&*()\-=_+\\|;:",./?><]
/" s"[!@#$%^&*()\-=_+\\|;:',./?><]
/, s,[!@#$%^&*()\-=_+\\|;:'"./?><]
/. s.[!@#$%^&*()\-=_+\\|;:'",/?><]
// s/[!@#$%^&*()\-=_+\\|;:'",.?><]
/> s>[!@#$%^&*()\-=_+\\|;:'",./?<]
/< s<[!@#$%^&*()\-=_+\\|;:'",./?>]
;[List.Rules:KoreLogicRulesReplaceLetters]
/a sa[b-z]
/b sb[ac-z]
/c sc[abd-z]
/d sd[a-ce-z]
/e se[a-df-z]
/f sf[a-eg-z]
/g sg[a-fh-z]
/h sh[a-gi-z]
/i si[a-hj-z]
/j sj[a-ik-z]
/k sk[a-jl-z]
/l sl[a-km-z]
/m sm[a-ln-z]
/n sn[a-mo-z]
/o so[a-np-z]
/p sp[a-oq-z]
/q sq[a-pr-z]
/r sr[a-qs-z]
/s ss[a-rt-z]
/t st[a-su-z]
/u su[a-tv-z]
/v sv[a-uw-z]
/w sw[a-vx-z]
/x sx[a-wyz]
/y sy[a-xz]
# Kore's ruleset was truncated after "/zszr"
/z sz[a-y]
-c /[a-z] s\0[A-Z]
;[List.Rules:KoreLogicRulesAppendSpecialNumberNumber]
-[c:] \p[c:] Az"[!$@#%.][0-9][0-9]" <+
-[c:] \p[c:] Azq[^&()_+\-={}|[\]\\;'":,/<>?`~*][0-9][0-9]q <+
;[List.Rules:KoreLogicRulesPrependNumNumAppendSpecial]
-[c:] \p[c:] A0"[0-9][0-9]" <* $[!$@#%.]
-[c:] \p[c:] A0"[0-9][0-9]" <* $[^&()_+\-={}|[\]\\;'":,/<>?`~*]
;[List.Rules:KoreLogicRulesPrependNumNumSpecial]
-[c:] \p[c:] A0"[0-9][0-9][!$@#%.]"
-[c:] \p[c:] A0q[0-9][0-9][^&()_+\-={}|[\]\\;'":,/<>?`~*]q
;[List.Rules:KoreLogicRulesAppend2NumSpecial]
-[c:] \p[c:] Az"[0-9][0-9][!$@#%.]" <+
-[c:] \p[c:] Azq[0-9][0-9][^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+
;[List.Rules:KoreLogicRulesPrependDaysWeek]
A0"[Mm][oO0][nN][dD][aA4@][yY]"
A0"[Tt][uU][eE3][sS$][dD][aA4@][yY]"
A0"[Ww][eE3][dD][nN][eE3][sS$][dD][aA4@][yY]"
A0"[Tt][hH][uU][rR][sS$][dD][aA4@][yY]"
A0"[Ff][rR][iI1!][dD][aA4@][yY]"
A0"[Ss][aA4@][tT+][uU][rR][dD][aA4@][yY]"
A0"[Ss][uU][nN][dD][aA4@][yY]"
;[List.Rules:KoreLogicRulesAppendNumbers_and_Specials_Simple-3]
## Add Number Number Special
-[c:] \p[c:] Azq[0-9][0-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+
## Add Special Number Number
-[c:] \p[c:] Azq[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*][0-9][0-9]q <+
;[List.Rules:KoreLogicRulesPrependSpecialSpecialAppendNumber]
-[c:] \p[c:] A0"[!$@#%.][!$@#%.]" <* $[0-9]
-[c:] \p[c:] A0q[^&()_+\-={}|[\]\\;'":,/<>?`~*][^&()_+\-={}|[\]\\;'":,/<>?`~*]q <* $[0-9]
;[List.Rules:KoreLogicRulesAppend4Num]
-[c:] \p[c:] Az"[0-9][0-9][0-9][0-9]" <+
;[List.Rules:KoreLogicRulesPrependNumNumNumNum]
-[c:] \p[c:] A0"[0-9][0-9][0-9][0-9]"
;[List.Rules:KoreLogicRulesPrepend2NumbersAppend2Numbers]
-[c:] \p[c:] A0"[0-9][0-9]" <- Az"[0-9][0-9]"
;[List.Rules:KoreLogicRulesPrependCAPCAPAppendSpecial]
A0"[A-Z][A-Z]" <* $[!$@#%.]
A0"[A-Z][A-Z]" <* $[^&()_+\-={}|[\]\\;'":,/<>?`~*]
;[List.Rules:KoreLogicRulesAppendSpecialLowerLower]
-[c:] \p[c:] AzQ[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*][a-z][a-z]Q <+
# The last line of KoreLogicRulesAppendNumbers_and_Specials_Simple
;[List.Rules:KoreLogicRulesAppendNumbers_and_Specials_Simple-4]
# Add 100! ... 999! to the end
-[c:] \p[c:] Azq[0-9][0-9][0-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+
;[List.Rules:KoreLogicRulesAppendSpecial3num]
-[c:] \p[c:] Az"[!$@#%.][0-9][0-9][0-9]" <+
-[c:] \p[c:] Azq[^&()_+\-={}|[\]\\;'":,/<>?`~*][0-9][0-9][0-9]q <+
;[List.Rules:KoreLogicRulesAppendSpecialNumberNumberNumber]
-[c:] \p[c:] Az"[!$@#%.][0-9][0-9][0-9]" <+
-[c:] \p[c:] Azq[^&()_+\-={}|[\]\\;'":,/<>?`~*][0-9][0-9][0-9]q <+
;[List.Rules:KoreLogicRulesAppend3NumSpecial]
-[c:] \p[c:] Az"[0-9][0-9][0-9][!$@#%.]" <+
-[c:] \p[c:] Azq[0-9][0-9][0-9][^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+
;[List.Rules:KoreLogicRulesPrependNumNum_AppendNumSpecial]
-[c:] \p[c:] A0"[0-9][0-9]" Azq[0-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+
;[List.Rules:KoreLogicRulesAppendJustSpecials3Times]
-[c:] \p[c:] Az"[!$@#%.][!$@#%.][!$@#%.]" <+
-[c:] \p[c:] Azq[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+
;[List.Rules:KoreLogicRulesAppendCap-Num_or_Special-Twice]
-[c:] \p[c:] Az"[A-Z][0-9][0-9]" <+
-[c:] \p[c:] Azq[A-Z][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*][0-9]q <+
-[c:] \p[c:] Azq[A-Z][0-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+
-[c:] \p[c:] Azq[A-Z][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+
;[List.Rules:KoreLogicRulesPrependSpecialSpecialAppendNumbersNumber]
-[c:] \p[c:] A0"[!$@#%.][!$@#%.]" <- Az"[0-9][0-9]"
-[c:] \p[c:] A0q[^&()_+\-={}|[\]\\;'":,/<>?`~*][^&()_+\-={}|[\]\\;'":,/<>?`~*]q <- Az"[0-9][0-9]"
;[List.Rules:KoreLogicRulesAppend5Num]
-[c:] \p[c:] Az"[0-9][0-9][0-9][0-9][0-9]" <+
;[List.Rules:KoreLogicRulesAppendSpecial4num]
-[c:] \p[c:] Az"[!$@#%.][0-9][0-9][0-9][0-9]" <+
-[c:] \p[c:] Azq[^&()_+\-={}|[\]\\;'":,/<>?`~*][0-9][0-9][0-9][0-9]q <+
;[List.Rules:KoreLogicRulesPrepend4NumAppendSpecial]
-[c:] \p[c:] A0"[0-9][0-9][0-9][0-9]" <- $[!$@#%.]
-[c:] \p[c:] A0"[0-9][0-9][0-9][0-9]" <- Azq[^&()_+\-={}|[\]\\;'":,/<>?`~*]q
;[List.Rules:KoreLogicRulesAppend4NumSpecial]
-[c:] \p[c:] Az"[0-9][0-9][0-9][0-9][!$@#%.]" <+
-[c:] \p[c:] Azq[0-9][0-9][0-9][0-9][^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+
;[List.Rules:KoreLogicRulesPrependSpecialSpecialAppendNumbersNumberNumber]
-[c:] \p[c:] A0"[!$@#%.][!$@#%.]" Az"[0-9][0-9][0-9]" <+
-[c:] \p[c:] A0q[^&()_+\-={}|[\]\\;'":,/<>?`~*][^&()_+\-={}|[\]\\;'":,/<>?`~*]q Az"[0-9][0-9][0-9]" <+
;[List.Rules:KoreLogicRulesAppend6Num]
-[c:] \p[c:] Az"[0-9][0-9][0-9][0-9][0-9][0-9]" <+