How to generate candidate passwords that match password strength policies (filtering words with grep)

Disadvantages of Rule-Based Attacks

The method of filtering only suitable password candidates using Rule Based Attack, shown in the article “How to create dictionaries that comply with specific password strength policies”, is not always convenient. More precisely, it is convenient when working with existing dictionaries. If using this method to generate new dictionaries, then there is a problem with saving the intermediate dictionary, which can be very large.

Another approach can be used, with the following algorithm:

  1. The maskprocessor program generates all possible password candidates
  2. Using the grep command, only those that match the required criteria are filtered
  3. Filtered passwords are passed to standard hashcat input to crack the hash, or saved to a file - whichever you want

Cons of this approach:

  1. The grep command can become a bottleneck if passwords are filtered slower than hashcat calculates the hash
  2. If you pass passwords to hashcat standard input, then if necessary to stop the attack and then restart it, the attack will start again from the first password candidate
  3. If you are generating a dictionary, it can still be quite large

Regular expressions for filtering passwords

Examples of regular expressions that will be useful to us:

There must be one capital letter:

'.*[A-Z]{1,}.*'

There must be two capital letters:

'.*[A-Z]{1,}.*[A-Z]{1,}.*'

There must be three large letters:

'.*[A-Z]{1,}.*[A-Z]{1,}.*[A-Z]{1,}.*'

There must be one small letter:

'.*[a-z]{1,}.*'

There must be two small letters:

'.*[a-z]{1,}.*[a-z]{1,}.*'

There must be three small letters:

'.*[a-z]{1,}.*[a-z]{1,}.*[a-z]{1,}.*'

There must be one number:

'.*[0-9]{1,}.*'

There are two numbers required:

'.*[0-9]{1,}.*[0-9]{1,}.*'

There are three numbers required:

'.*[0-9]{1,}.*[0-9]{1,}.*[0-9]{1,}.*'

How to generate wordlists

The following command will generate passwords that have at least two uppercase letters, one lowercase letter and one number:

maskprocessor -1 ?l?u?d ?1?1?1?1?1?1?1?1 | grep -E '.*[A-Z]{1,}.*[A-Z]{1,}.*' | grep -E '.*[a-z]{1,}.*' | grep -E '.*[0-9]{1,}.*'

The generated passwords can be saved to a file:

maskprocessor -1 ?l?u?d ?1?1?1?1?1?1?1?1 | grep -E '.*[A-Z]{1,}.*[A-Z]{1,}.*' | grep -E '.*[a-z]{1,}.*' | grep -E '.*[0-9]{1,}.*' > llud.dic

Passing generated passwords to hashcat stdin

The generated and filtered password candidates can be used directly with hashcat by passing them to standard input.

Let's generate a hash for cracking:

echo -n aaazaAD1 | md5sum
f203600f24db0b34d3d568208c35cd4e

In hashcat, as the attack type, you need to select Dictionary Attack (-a 0).

An example of a command that cracks a test hash:

maskprocessor -1 ?l?u?d ?1?1?1?1?1?1?1?1 | grep -E '.*[A-Z]{1,}.*[A-Z]{1,}.*' | grep -E '.*[a-z]{1,}.*' | grep -E '.*[0-9]{1,}.*' | hashcat -m 0 -a 0 f203600f24db0b34d3d568208c35cd4e

In this command, the first half is the same as in the commands above, that is, maskprocessor generates all possible password candidates, and the grep command sequence filters out only matching words. The resulting words are passed to hashcat standard input.

Filtering existing dictionaries

The same method can be used to select from existing dictionaries only those candidates for passwords that meet the specified criteria.

Let's take a dictionary for the test:

cat /usr/share/wordlists/rockyou.txt.gz | gunzip > ~/rockyou.txt

Let's count the number of words in it:

cat ~/rockyou.txt | wc -l
14344392

Let's clear the dictionary of unreadable characters:

iconv -f utf-8 -t utf-8 -c ~/rockyou.txt > ~/rockyou_clean.txt

For details on the problem solved by the previous command, see the article “How to find and remove non-UTF-8 characters from a text file”.

Let's count the lines in it:

cat ~/rockyou_clean.txt | wc -l
14344392

Now, instead of the maskprocessor command to generate words from the mask, we use the cat command to read the file and use | (pipeline) let's pass it to grep commands for filtering (the same conditions are used - at least two capital letters, at least one small letter and at least one digit):

cat ~/rockyou_clean.txt | grep -E '.*[A-Z]{1,}.*[A-Z]{1,}.*' | grep -E '.*[a-z]{1,}.*' | grep -E '.*[0-9]{1,}.*' > ~/rockyou_llud.dic

Let's count the number of remaining password candidates in the new dictionary:

cat ~/rockyou_llud.dic | wc -l
124050

Let's calculate how much this is from the total:

124050÷14344392×100 = 0,86%

It turned out that there were less than 1 percent of the words left.

Why then the Rule-based attack?

As the authors of Hashcat write, the rule-based attack is faster than the grep command. In my tests with one video card on a laptop, the bottleneck is still the video card, that is, the speed of grep is enough so that Hashcat does not wait for the generation/filtering of the next candidate for passwords.

The Rule-based attack allows not only filtering words, but also modifying them, that is, this attack has many other possibilities.

Recommended for you:

Leave a Reply

Your email address will not be published.