Cracking Password Hashes with Hashcat: A Walkthrough
A beginner walkthrough of Hashcat: generate practice hashes you own, identify the type, pick the right mode, and crack your first hash with a dictionary, rules, and a mask.
Hashcat is the tool most people reach for the first time they want to turn a password hash back into the password that made it, and this walkthrough takes you through that first crack start to finish. You will make a couple of practice hashes on your own machine, work out what type they are, pick the matching mode, and recover them three different ways. Nothing here touches a login form or a live account. The whole point is that cracking happens offline, on hashes you already hold, on hardware you own.
Read it top to bottom and run every command as you go. By the end you will have cracked an MD5 and an NTLM hash you generated yourself, and you will understand why some hashes fall in seconds while others outlast you.
Everything below runs against hashes you generate on your own machine, or hashes you are explicitly authorized to test in a lab such as lab.0xpriv.dev or a box on 10.10.10.0/24. Cracking hashes you pulled from someone else's system without written permission is illegal. Generate your own and practice on those.
01Offline cracking versus online guessing, and why Hashcat is silent
Offline cracking is what Hashcat does, and it is a completely different activity from online guessing even though both end with a password. Online guessing means typing candidate passwords at a live login: a form, SSH, an API. The target sees every attempt, counts the failures, locks the account, and writes a log line each time. It is loud and slow, and a few wrong tries can trip an alarm or a lockout.
Offline cracking starts after you already hold the hash. You dumped it from a database you are testing, read it from a SAM file on a lab host at 10.10.10.5, or in this walkthrough you made it yourself. From that point the target is out of the loop entirely. You hash guesses on your own GPU, compare each result to the stolen hash locally, and the real system never receives a single packet. There is no account to lock and no log to write, which is exactly why offline cracking is silent and why defenders cannot see it happening.
That silence cuts both ways. Cracking leaves no trace on the victim, so defenders must assume any stolen hash will eventually be attacked, and the only sane place to practice is on hashes you made yourself, which is what you do next.
02Getting practice hashes you own
Practice hashes you own are the safe way to learn, and making them takes two short commands. You will create one MD5 and one NTLM hash from passwords you choose, because those two cover the most common beginner cases and they crack fast enough to see results in seconds. Pick weak sample passwords on purpose so the dictionary stage has something to find.
MD5 is a plain unsalted hash of the input bytes. On Linux or Git Bash you can make one with the standard tools that ship with the system.
# make an MD5 of a sample password you choose # 0xpriv.dev/labs printf '%s' 'Summer2023' | md5sum | cut -d' ' -f1 printf '%s' 'letmein' | md5sum | cut -d' ' -f1
$ printf '%s' 'Summer2023' | md5sum | cut -d' ' -f1 31c8c0724c0cd1b5c92f00e4a1d7c5a1 $ printf '%s' 'letmein' | md5sum | cut -d' ' -f1 0d107d09f5bbe40cade3de5c71e9e9b7
NTLM is the hash Windows stores for local accounts, and it is just the MD4 of the password encoded as little endian UTF-16. You do not need Windows to make one. A single line of Python produces the exact value Windows would store, so you can practice the Windows case on any machine.
# make an NTLM hash of a sample password (MD4 of the UTF-16LE bytes) python3 -c "import hashlib; print(hashlib.new('md4','Password1'.encode('utf-16le')).hexdigest())"
$ python3 -c "import hashlib; print(hashlib.new('md4','Password1'.encode('utf-16le')).hexdigest())" 64f12cddaa88057e06a81b54e73b949b
Save each hash on its own line in a plain text file. Keep MD5 and NTLM in separate files for now, because Hashcat cracks one hash type per run and mixing them will only confuse you while you learn.
# one hash per line, grouped by type cat md5.txt # 31c8c0724c0cd1b5c92f00e4a1d7c5a1 # 0d107d09f5bbe40cade3de5c71e9e9b7 cat ntlm.txt # 64f12cddaa88057e06a81b54e73b949b
The three values above are genuine MD5 and NTLM hashes of Summer2023, letmein, and Password1. Run the commands yourself and you will get the same strings. That is the whole idea of a hash: the same input always produces the same output.
03Identifying the hash type and picking the right -m mode
Identifying the hash type comes before anything else, because Hashcat needs to be told exactly which algorithm a hash came from through its mode number, the -m flag. Give it the wrong mode and it will either refuse the hash or churn forever and find nothing. You already know your two hashes are MD5 and NTLM, but on a real engagement you often do not, so it helps to know how people guess.
Length and shape are the first clue. A 32 character hex string is probably MD5 or NTLM, a 40 character one is likely SHA-1, and a value starting with $2b$ is bcrypt. Tools automate this. Hashcat has a built in guesser, and hashid is a small standalone tool that does the same job.
$ hashcat --identify md5.txt The following hash-mode(s) match the structure of your input hash: # | Name | Category ======+===================================+====================== 0 | MD5 | Raw Hash 10 | md5($pass.$salt) | Raw Hash salted 900 | MD4 | Raw Hash
Notice that a bare 32 character hex string matches several modes, because MD5 and NTLM and plain MD4 all look identical on the wire. That is why context matters: a hash from a Windows SAM is NTLM, a hash from a PHP app is usually MD5 or something stronger. The table below lists the modes you will meet most often. Confirm any mode you are unsure about against the official example hashes page, which shows a sample hash for every single mode Hashcat supports.
Mode -m | Algorithm | Where you see it |
|---|---|---|
0 | MD5 | Old web apps, quick checksums |
100 | SHA-1 | Legacy web apps |
1400 | SHA-256 | Apps that upgraded past MD5 |
1000 | NTLM | Windows local and domain accounts |
1800 | sha512crypt $6$ | Modern Linux /etc/shadow |
3200 | bcrypt $2*$ | Well built web apps |
Mode numbers are easy to mix up and the list grows with every release. When you meet a hash you have not cracked before, match its shape against the Hashcat example hashes page before you start a long run. A wrong -m is the most common reason a beginner's crack finds nothing.
04Running a dictionary attack with rockyou
A dictionary attack is the first thing to try on any hash, because most real passwords are words or small variations of words that already sit in a public list. Mode -a 0 is the straight dictionary mode: Hashcat reads a wordlist line by line, hashes each candidate, and compares it to your target. The classic starter wordlist is rockyou.txt, a list of millions of real passwords from an old breach that ships with Kali and is free to download anywhere.
Point Hashcat at your MD5 file with mode 0 and attack mode 0, and hand it the wordlist as the last argument.
# -m 0 = MD5, -a 0 = straight dictionary attack hashcat -m 0 -a 0 md5.txt rockyou.txt
$ hashcat -m 0 -a 0 md5.txt rockyou.txt 31c8c0724c0cd1b5c92f00e4a1d7c5a1:Summer2023 0d107d09f5bbe40cade3de5c71e9e9b7:letmein Session..........: hashcat Status...........: Cracked Recovered........: 2/2 (100.00%) Digests
Hashcat prints each cracked hash next to its password, separated by a colon. Your NTLM hash cracks the same way, you just change the mode to 1000 and point it at the other file.
# same attack, NTLM this time hashcat -m 1000 -a 0 ntlm.txt rockyou.txt
If nothing cracks, the password simply is not in the list. That is not a dead end, it is your cue to make the list work harder, which is the next two sections.
05Adding rules to multiply a wordlist
Rules let one wordlist stand in for hundreds, by transforming each word on the fly before it is hashed. Real people rarely use a bare dictionary word. They capitalize it, stick a year on the end, swap an a for an @. A rule file is a list of these mutations written in Hashcat's own mini language, applied to every candidate so that password also becomes Password, password1, P@ssw0rd, and so on.
You enable rules with -r and a rule file. Hashcat ships several ready made in its rules/ folder. The one everyone starts with is best64.rule, a compact set of the 64 most productive mutations.
# multiply every rockyou word by the best64 ruleset hashcat -m 0 -a 0 md5.txt rockyou.txt -r rules/best64.rule
Each rule is a short instruction. A few examples show how readable the language is once you see it: c capitalizes, $1 appends a 1, sa@ swaps every a for an @. The official rule based attack page documents every function, and you can write your own file one rule per line.
# a tiny custom rule file, one mutation per line : # leave the word unchanged c # Capitalize first letter $1 # append 1 $2 $0 $2 $3 # append 2023 sa@ so0 # a -> @ and o -> 0
Rules are the highest value trick in this whole walkthrough. A medium wordlist plus a good ruleset cracks far more real passwords than a huge raw wordlist alone, because it models how humans actually build passwords out of base words.
06Running a mask attack for a known pattern
A mask attack brute forces a known pattern instead of reading a wordlist, and it is the right tool when you know the shape of a password but not its contents. Mode -a 3 is the mask mode. You describe the password with character set placeholders, and Hashcat tries every combination that fits. This only stays fast while the pattern is short, because the number of guesses explodes as you add positions.
Each placeholder stands for a character set. You can combine the built in ones or define your own.
| Mask | Character set |
|---|---|
?l | lowercase a to z |
?u | uppercase A to Z |
?d | digits 0 to 9 |
?s | symbols like !@#$ |
?a | all of the above |
Say you know a lab account uses one capital, five lowercase, then two digits, a pattern like Summer23. That is ?u?l?l?l?l?l?d?d. Hashcat walks every value of that exact shape.
# one uppercase, five lowercase, two digits: e.g. Summer23 hashcat -m 0 -a 3 md5.txt '?u?l?l?l?l?l?d?d' # do not know the length? let it grow the mask from short to long hashcat -m 0 -a 3 --increment md5.txt '?u?l?l?l?l?l?l?l?d?d'
Adding one ?a position multiplies the work by about ninety five. A seven character all sets mask is already tens of billions of guesses. Use masks when you know the pattern, and lean on dictionaries and rules when you do not.
07Reading the pot file and --show
The pot file is where Hashcat remembers every hash it has ever cracked, so you never lose a result and never redo work. Each time a hash falls, Hashcat writes a hash:password line to a file called hashcat.potfile in its data directory. Run the same hash again later and it will tell you it is already cracked rather than starting over.
To print what you have already recovered, run the same command with --show and no wordlist. Hashcat looks each hash up in the pot file and prints the matches.
$ hashcat -m 0 md5.txt --show 31c8c0724c0cd1b5c92f00e4a1d7c5a1:Summer2023 0d107d09f5bbe40cade3de5c71e9e9b7:letmein
If your hash file is in username:hash format, which is common when you dump a whole table, add --username so Hashcat ignores the name column, and add --show --username to get the names back next to the cracked passwords. You can also send live results to a file of your own with -o cracked.txt.
# crack a user:hash file, then list who cracked hashcat -m 1000 -a 0 --username domain.txt rockyou.txt -r rules/best64.rule hashcat -m 1000 --username domain.txt --show
08Performance and realistic expectations
Performance is the part beginners misjudge most, so it helps to see real numbers before you start a run that would take a century. Hashcat's speed depends on two things: how fast your hardware is, and how slow the hash algorithm is by design. A modern GPU hashes fast algorithms like MD5 and NTLM in the billions per second, but deliberately slow algorithms like bcrypt in only a few thousand per second. Run hashcat -b to benchmark your own card.
$ hashcat -b -m 0 Speed.#1.........: 25000.0 MH/s (MD5) $ hashcat -b -m 1000 Speed.#1.........: 45000.0 MH/s (NTLM) $ hashcat -b -m 3200 Speed.#1.........: 15.0 kH/s (bcrypt)
Those numbers decide what is realistic. The table shows roughly how the same guess budget plays out. The lesson is not that you need a bigger GPU, it is that the algorithm chosen by the defender sets the ceiling, and no hardware saves you from a well chosen slow hash.
| Hash | GPU speed | What that buys you |
|---|---|---|
| MD5 / NTLM | billions/sec | Full 8 char keyspace in hours |
| sha512crypt | ~hundreds of thousands/sec | Only dictionaries and rules are practical |
| bcrypt | thousands/sec | Only weak, short, or leaked passwords fall |
So your plan on any real hash is the same order you learned here: dictionary first, then rules, then a targeted mask, and accept that a long random password behind a slow hash is simply not coming out. Add -O for the optimized kernel and -w 3 to push the workload when you want more speed on a dedicated box.
09A first crack end to end
A first crack end to end ties the pieces together so you can see the whole rhythm in one place. These are the exact steps you just ran, in the order you will repeat them on every hash from now on.
Generate or collect the hash
Make a practice MD5 and NTLM as above, or work from hashes you are authorized to test. One hash type per file.
Identify the type
Use hashcat --identify or hashid, then confirm the mode against the example hashes page and set -m.
Dictionary first
Run -a 0 with rockyou. Most weak passwords fall here in seconds.
Add rules
Re-run with -r rules/best64.rule to catch capitalized, suffixed, and substituted variants.
Mask for a known pattern
If you know the shape, switch to -a 3 with a mask. Keep it short.
Collect results
Read everything back with --show from the pot file, and write keepers to -o cracked.txt.
10Ethics and handling recovered passwords
Handling recovered passwords responsibly is part of the job, not an afterthought, because a cracked password is one of the most sensitive things you can hold during an engagement. The first rule is scope: you crack only hashes you generated or were authorized in writing to test, and you crack them only for the engagement that authorized it. A hash you found interesting on an unrelated system is off limits, full stop.
Once you have cleartext, treat it like live credentials, because it is. Store cracked passwords in an encrypted vault tied to that engagement, never in a plain file that syncs to a cloud drive. Report them to the client in the agreed secure channel, note any password reuse you spot since reuse is often the most useful finding, and then destroy your copies when the engagement closes. Do not reuse a cracked password to log into anything outside the agreed scope, even to prove it works, unless the rules of engagement say you may.
Assume every password you recover is in use somewhere else too. Reporting it clearly and handling it securely is what separates authorized testing from the thing you are supposed to be defending against.
11How to make cracking fail
Making cracking fail is the defender's side of this walkthrough, and a few sound choices move passwords from "falls in seconds" to "not coming out." The attacks you just ran succeed because of two mistakes: passwords that resemble dictionary words, and hashes that are fast and unsalted. Fix both and the same tools come up empty.
There is a detection angle too. You cannot see the cracking, but you can watch the steps around it: a bulk read of your user table or a SAM or NTDS dump means hashes just left the building, and a later wave of logins with those passwords shows up as credential stuffing. Alert on the theft and on the reuse, since the crack in the middle happens where you will never see it.
12FAQ
What is the difference between Hashcat and John the Ripper?FAQ
They do the same job, cracking hashes offline, and both are excellent. Hashcat is built around the GPU and is usually faster for raw dictionary and mask work, while John the Ripper has famously good automatic hash detection and handy cracking modes. A common workflow is to let John identify and seed, then let Hashcat grind at speed. Learning either teaches you the other.
Why did my crack find nothing even though the mode was right?FAQ
Almost always because the password is not in your wordlist and does not match any rule you applied. Try a bigger list, add -r rules/best64.rule, then a targeted mask if you know the pattern. If the hash is a slow algorithm like bcrypt, also accept that a strong password simply may not be recoverable.
Where does Hashcat store cracked passwords?FAQ
In a file called hashcat.potfile in its data directory. Every cracked hash is appended as hash:password, so running --show later prints your results without recracking. Point a run at a custom file with --potfile-path if you want to keep engagements separate.
Do I need an expensive GPU to start?FAQ
No. Hashcat runs on a CPU and will happily crack the practice hashes in this walkthrough on any laptop. A GPU matters when you move to large keyspaces or slow hashes, but for learning the method, your current machine is plenty.
Is it legal to run Hashcat?FAQ
The tool itself is legal and dual use, like nmap or curl. What matters is the hashes. Cracking hashes you generated or own, or ones you have written authorization to test, is fine. Cracking hashes taken from systems you do not own or have no permission to assess is a crime, regardless of the tool.
references
Founder of 0xpriv, covering offensive security, web application vulnerabilities, and practical security research through PHP, Python, and hands-on technical analysis.