Author Topic: [Java source] Enhancing wordlists with letter substitutions  (Read 1248 times)

0 Members and 1 Guest are viewing this topic.

Offline Deque

  • P.I.N.N.
  • Global Moderator
  • Overlord
  • *
  • Posts: 1203
  • Cookies: 518
  • Programmer, Malware Analyst
    • View Profile
Hello EZ,

some people think they are clever by substituting certain letters of their passwords with special characters or numbers. You know this from leetspeak.

If your password is "leet" you might use "l33t" instead. Or you might substitute with different characters: "l€€t"

So I made a textfile with common substitutions (taken from https://de.wikipedia.org/wiki/Leetspeak):

Code: [Select]
A=4,@,/\,/-\,?,^,α,λ
B=8,|3,ß,l³,|>,13,I3,J3
C=(,[,<,©,¢
D=|),|],Ð,đ,1)
E=3,€,&,£,ε
F=|=,PH,|*|-|,|",ƒ,l²
G=6,&,9
H=4,|-|,#,}{,]-[,/-/,)-(
J=!,1,|,][,ỉ
I=_|,¿
K=|<,|{,|(,X
L=1,|_,£,|,][_
M=/\/\,/v\,|V|,]V[,|\/|,AA,[]V[],|11,/|\,^^,(V),|Y|
N=|\|,/\/,/V,|V,/\\/,|1,2,?,(\),11,r
O=0,9,(),[],*,°,<>,ø,{[]}
P=9,|°,p,|>,|*,[]D,][D,|²,|?,|D
Q=0_,0,
R=2,|2,1²,®,?,я,12,.-
S=5,$,§,?,ŝ,ş
T=7,+,†,'][',|
U=|_|,µ,[_],v
V=\/,|/,\|,\'
W=\/\/,VV,\A/,\\',uu,\^/,\|/,uJ
X=><,)(,}{,%,?,×,][
Y=`/,°/,¥
Z=z,2,"/_
Ö=03,°O°
Ü=|_|3,°U°
Ä=43,°A°,°4°


You can edit this as you wish or use your own one. I named this file "leetspeak".

I wrote this Java code that uses the substitutions specified in the "leetspeak" file and a given password to generate all possible substituted passwords out of it.

The usage of this class is demonstrated here in the last two methods (main() and generateAndPrintLeetWords() )

Code: [Select]
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

public class LeetSpeakGenerator {

    private final Map<Character, List<String>> multiDict = new HashMap<>();

    public LeetSpeakGenerator(Path dictionary) throws IOException {
        initDictionary(dictionary);
    }

    private void initDictionary(Path dictionary) throws IOException {
        Charset charset = Charset.forName("UTF-8");
        List<String> lines = Files.readAllLines(dictionary, charset);
        for (String line : lines) {
            String[] value = line.split(",");
            char key = value[0].charAt(0);
            value[0] = value[0].substring(2);
            multiDict.put(key, Arrays.asList(value));
        }
    }

    private Set<String> generateLeetWords(String word) {
        int numberOfCases = (int) Math.pow(2, word.length());
        Set<String> variants = new TreeSet<>();

        for (int i = 0; i < numberOfCases; i++) {
            variants.addAll(getLeetWordsFor(i, word.toCharArray()));
        }

        return variants;
    }

    private Set<String> getLeetWordsFor(int n, char[] originalWord) {
        int length = originalWord.length;
        Set<StringBuilder> modified = new HashSet<>();
        modified.add(new StringBuilder());
        for (int i = 0; i < length; i++) {
            int bitmask = (int) Math.pow(2, (length - 1) - i);
            if ((bitmask & n) == bitmask) {
                char ch = Character.toUpperCase(originalWord[i]);
                if (multiDict.containsKey(ch)) {
                    List<String> translations = multiDict.get(ch);
                    appendCharsTo(modified, translations);
                } else {
                    appendCharTo(modified, originalWord[i]);
                }
            } else {
                appendCharTo(modified, originalWord[i]);
            }
        }
        return convertToStringSet(modified);
    }

    private Set<String> convertToStringSet(Set<StringBuilder> builders) {
        Set<String> set = new TreeSet<>();
        for (StringBuilder builder : builders) {
            set.add(builder.toString());
        }
        return set;
    }

    private void appendCharTo(Set<StringBuilder> words, char c) {
        for (StringBuilder b : words) {
            b.append(c);
        }
    }

    private void appendCharsTo(Set<StringBuilder> words,
            List<String> translations) {
        Iterator<StringBuilder> it = words.iterator();
        List<StringBuilder> newWords = new LinkedList<>();

        while (it.hasNext()) {
            StringBuilder word = it.next();
            it.remove();
            for (String translation : translations) {
                StringBuilder newWord = new StringBuilder(word);
                newWord.append(translation);
                newWords.add(newWord);
            }
        }
        words.addAll(newWords);
    }

    public static void main(String[] args) throws IOException {
        String word = "leet";
        generateAndPrintLeetWords(word);
    }

    private static void generateAndPrintLeetWords(String word)
            throws IOException {
        LeetSpeakGenerator leetGen = new LeetSpeakGenerator(Paths.get("leetspeak"));
        Set<String> cases = leetGen.generateLeetWords(word);
        for (String variant : cases) {
            System.out.println(variant);
        }
        System.out.println("words generated: " + cases.size());
    }
}

Output example. If you put in "le" as word you get (including the original word):

Code: [Select]
1&
13
1e


1€
][_&
][_3
][_e
][_£
][_ε
][_€
l&
l3
le


l€
|&
|3
|_&
|_3
|_e
|_£
|_ε
|_€
|e


|€
£&
£3
£e
££
£ε
£€
words generated: 36

For the password "leet" 1296 leetspeak-words are generated. As you can see these are a lot. Because of that I would advice you to make a character substitution file with the most common substitutions only for actual use.

Have fun coding.

Deque
« Last Edit: May 15, 2013, 09:56:27 am by Deque »