I’ve been using Hashcat since I’ve been pentesting at my previous jobs, but I haven’t had the need to use it for a couple of years now. Recently I had another use case for it but I still don’t need to use nearly as often as I once did. I therefore decided to document some of this to easily look things up in the future.

Extracting All Hashes from Active Directory

To copy all hashes from Active Directory, you need domain administrator credentials. Once acquired, make a copy like so:

C:\> ntdsutil "ac i ntds" "ifm" "create full c:\extract" quit quit
C:\> dir c:\extract\Active Directory\ntds.dit
C:\> dir c:\extract\Registry\SYSTEM

Now move both the ntds.dit and SYSTEM files to your workstation.

On your workstation, extract the hashes:

user $ secretsdump.py -system SYSTEM -ntds ntds.dit -history > hashes.txt

Once extracted you can start cracking.

Dictionary Attack

Note
See this article to understand the difference between LM, NTHash, NTLMv1 and NTLMv2.

Assuming your extract contains NTHash hashes, you can start a simple dictionary attack like so (using a screen session):

user $ hashcat -m 1000 -w 3 -a 0 -p : --session=audit --username -o \
         cracked.out --outfile-format=3 --potfile-path hashcat.pot hashes.txt \
         dict.txt
-m 1000

1000 is the NTHash hash type

-a 0

Dictionary attack

-p :

Delimiter in the hashes

--session=audit

Just a session name

--username

Every row in the hash file first starts with a username

-o cracked.out

Keeps track of accounts of which the hashes are cracked

--outfile-format-3

Output file format

--potfile-path hashcat.pot

Saves all cracked hashes in a separate pot file.

I found several good wordlists over the past couple of years:

Rule Based Attack

This adds rules (common substitutions) to the cracking attack. For example, candidate 'password123' in the dictionary, a rule could also produce candidate 'P@$$w0rd2024!'. Observe that a rule could do some common leetspeak substitutions, replace the digits with the current year, and add a common symbol at the end.

user $ hashcat -m 1000 -w 3 -a 0 -p : --session=audit --username -o \
         cracked.out --outfile-format=3 --potfile-path hashcat.pot hashes.txt \
         dict.txt -r rules.txt

Notice the -r rules.txt option, to specify a rule file.

Apart from the standard rules (e.g. d3ad0ne, dive, etc.), I found several other rules that proved quite useful:

Mask Based Attack

A brute force attack of sorts, trying all characters in a given character space.

user $ hashcat -m 1000 -w 3 -a 3 -p : --session=audit --username -o \
         cracked.out --outfile-format=3 --potfile-path hashcat.pot hashes.txt \
         '?u?l?l?l?l?d?d?d?d?s'

Notice the -a 3 option (mask attack mode), and '?u?l?l?l?l?d?d?d?d?s' (the actual mask, here 1 upper, 4 lower, 4 digits, 1 symbol).

Hybrid Attack

Using a dictionary, and a mask:

user $ hashcat -O -m 1000 -w 3 -a 6 -p : --username --session=hybrid -o \
         cracked.out --outfile-format=3 --potfile-path hashcat.pot hashes.txt \
         dict.txt '?d?d?s'

Notice the '-a 6' option (hybrid mode), and the mask at the end. Here the mask is appended to each candidate from the dictionary.

Combinator Attack

This attacks uses more than 1 dictionary to generate candidates. It concatenates words from both dicts, and optionally applies a single rule per dict as well:

user $ hashcat -O -m 1000 -w 3 -a 1 -p : --username --session=combinator -o \
         cracked.out --outfile-format=3 --potfile-path hashcat.pot hashes.txt \
         dict1.txt -j '$-' dict2.txt -k '$!'

Notice the -a 1 option (combinator mode), and the 2 dicts at the end. The -j '$-' option applies a single rule (appending a dash) to the left word. The -k '$!' option applies another single rule (appending an exclamation mark) to the right word. In this example, this would produce candidates comprising of 2 words, separated with a dash, and suffixed with an exclamation mark.

You can also use complete rule files, but AFAIK you cannot use Hashcat’s built-in combinator mode. You’d need to use the combinator tool to concatenate words for 2 or more dicts, and pipe the output to hashcat:

user $ combinator dict1.txt dict2.txt | hashcat -O -m 1000 -w 0 -a 0 -p : \
         --username --session=combinator -o cracked.out --outfile-format=3 \
         --potfile-path hashcat.pot hashes.txt -r rules.txt

Custom Dictionaries

The ntds.dit file might also contain some CLEARTEXT passwords:

user $ grep CLEARTEXT hashes.txt | cut -d : -f 3 | sort -u >> cleartext.txt

Once you’ve cracked enough hashes from your set of hashes, you could also generate a dict comprising of those discovered passwords:

user $ cut -d : -f 2 hashcat.pot > cracked-dict-history-uniq

Another valuable tip I got from colleagues in the field is to generate a wordlist from Wikipedia, using WikiRaider.

Currently this tool no longer works, but I found a fork which did some improvements. That fork also doesn’t work anymore, but I found an easy fix. I forked it, fixed it, and created a pull request, but currently it’s not merged yet. For the time being you could use my fork, or manually apply this commit to the SmallKingfisher repo.

Once you’ve cloned the repo, you can create a wordlist like so:

user $ ./wikiraider.py parse -u https://dumps.wikimedia.org/nlwiki/20240901
Note
This might take a (very) long time (hours, plural) and may use several GiBs (tens, even) of space, depending on how large the database is.

You can also create smartlists using cracken. This splits words like HelloWorld123! into words like ['Hello', 'World', '123!']:

user $ cracken create -f cracked-dict-history-uniq -o smartlist

Password Analysis

Once you’re done cracking you can do some password analysis, for example:

  • most commonly used passwords

  • most commonly used words

  • password length distribution

  • etc.

You could use pipal for this:

user $ hashcat -m 1000 --show --username hashes.txt --potfile-path \
         hashcat.pot | grep -v 'Failed to parse hashes using the \'pwdump\' 
         format.' | grep -v '^$' | cut -d : -f 3 | sed 1,7d | grep -v '^$' | \
         sort > cracked-dict.txt

user $ pipal cracked-dict.txt --top 10
Basic Results

Total entries = xxxx
Total unique entries = xxxx

Top 10 passwords
xxxxxxxxxxxx = 295 (7.15%)
xxxxxxxxxxxxxxx = 48 (1.16%)
xxxxxxxxxxxxx = 30 (0.73%)
xxxxxxxxxxxxx = 30 (0.73%)
xxxxxxxxxxxxx = 28 (0.68%)
xxxxxxxxxxxxxxxxxxxx = 26 (0.63%)
xxxxxxxxxxxxxx = 24 (0.58%)
xxxxxxxxxxxxxxxx = 20 (0.48%)
xxxxxxxxxxxxxxxxx = 17 (0.41%)
xxxxxxxxxxxxx = 16 (0.39%)

Top 10 base words
xxxxxxxxx = 386 (9.35%)
xxxxxxxxxxxx = 111 (2.69%)
xxxxxxxxxxxxxxxx = 45 (1.09%)
xxxxxxxx = 43 (1.04%)
xxxxxxxxx = 34 (0.82%)
xxxxxxxxx = 34 (0.82%)
xxxxxxxx = 30 (0.73%)
xxxxxxxxxx = 30 (0.73%)
xxxxxxxx = 28 (0.68%)
xxxxxxxxxxxx = 27 (0.65%)

You could also analyse your passwords for probable masks using statsgen from PACK:

user $ statsgen cracked-dict.txt
[...]
    [*] Advanced Masks:
    [+]          ?l?l?l?l?l?l?l?l: 04% (687991)
    [+]              ?l?l?l?l?l?l: 04% (601152)
    [+]            ?l?l?l?l?l?l?l: 04% (585013)
    [+]        ?l?l?l?l?l?l?l?l?l: 03% (516830)
    [+]            ?d?d?d?d?d?d?d: 03% (487429)
[...]

If accounts are using a consistent naming convention, you can also check how many you cracked of a certain type. For example:

user $ hashcat -m 1000 --show --username hashes.txt --potfile-path \
         hashcat.pot | grep -i 'company.n(et|l).(acc|ext)[0-9]{6}' | sort | \
         wc -l