A plain brute force tries every possible string, which is why it never finishes against anything longer than seven or eight characters. A mask attack is brute force with a brain: you describe the shape of the password (one capital, four lowercase, three digits) and hashcat tries only the strings matching that shape. The keyspace collapses from quadrillions to billions, and a search that was hopeless becomes minutes. This is how you brute force in a way that actually completes. Verified on hashcat 7.1.2.
TL;DR
The mask attack is hashcat's -a 3. A mask is a pattern, one token per character position, built from charsets: ?l lowercase, ?u uppercase, ?d digit, ?s symbol, ?a all of them. hashcat -m 0 -a 3 hashes.txt '?u?l?l?l?l?d?d?d' tries every "capital + 4 lowercase + 3 digits" string and nothing else. Quote the mask in zsh (the single quotes above), or the shell tries to glob the ? and aborts with "no matches found". Define your own charset with -1 (then reference it as ?1), and use --increment to try short lengths first. Use a mask when you know the password's shape but it is not in a wordlist. The catch: every extra character multiplies the keyspace, so masks only finish against fast hashes; against bcrypt or Argon2 they are hopeless.
How a mask works
In a mask, each ?x token is one character position and the charset it expands to. hashcat walks every combination. So ?l?l?l is every three-lowercase-letter string (aaa to zzz, 26^3 = 17,576 candidates), and ?d?d?d?d is every four-digit PIN (0000 to 9999, 10,000).
The built-in charsets, verified against hashcat --help:
| Token | Expands to |
|---|---|
?l | lowercase a-z |
?u | uppercase A-Z |
?d | digits 0-9 |
?h | lowercase hex 0-9a-f |
?H | uppercase hex 0-9A-F |
?s | symbols (space and punctuation) |
?a | everything: ?l?u?d?s |
?b | every byte 0x00 to 0xff |
You can mix literals and tokens freely. admin?d?d?d?d cracks admin0000 through admin9999. ?u?l?l?l?l?l?l20?d?d cracks a capitalised seven-letter word followed by a year in the 2000s.
A real mask crack
Here is a mask attack finding a five-character password of the shape "three letters, two digits." First the hash (MD5 of abc12), then the attack:
echo -n "abc12" | md5sum | cut -d' ' -f1 > target.hash
hashcat -m 0 -a 3 target.hash '?l?l?l?d?d'hashcat walks the 26 * 26 * 26 * 10 * 10 = 1,757,600 candidate keyspace and finds it:
b2157e7b2ae716a747597717f1efb7a0:abc12
Status...........: Cracked
Hash.Mode........: 0 (MD5)
Guess.Mask.......: ?l?l?l?d?d [5]Under two million candidates, instant. Compare that to ?a?a?a?a?a (all-printable, same length), which is 95^5 = about 7.7 billion, thousands of times larger for the same password length. Knowing the shape is what makes the difference.
Custom charsets
The eight built-in custom-charset slots, -1 through -8, let you define exactly the set a position should use. Define it, then reference it by number in the mask.
# -1 = lowercase + digits. Mask: 6 chars from that set.
hashcat -m 0 -a 3 -1 '?l?d' hashes.txt '?1?1?1?1?1?1'
# -1 = upper+lower (a letter), -2 = symbols.
# Mask: capital, 5 letters, one symbol.
hashcat -m 0 -a 3 -1 '?u?l' -2 '?s' hashes.txt '?u?1?1?1?1?1?2'Custom charsets are how you encode a known password policy precisely: "must start with a letter, must end with a symbol, the middle is alphanumeric" becomes one mask with two custom sets, and hashcat searches only the strings that policy allows.
Increment mode: try shorter first
A fixed mask is exactly one length. Real passwords vary, so --increment runs the mask at every length from 1 up to its full width, shortest first (where the cracks are cheapest):
# All-lowercase, lengths 1 through 8, short first
hashcat -m 0 -a 3 --increment hashes.txt '?l?l?l?l?l?l?l?l'
# Bound the range: only lengths 6 to 8
hashcat -m 0 -a 3 --increment --increment-min 6 --increment-max 8 hashes.txt '?l?l?l?l?l?l?l?l'Without increment you would crack an eight-character password but miss the six-character ones entirely. With it, you sweep the whole length range in increasing order of cost.
The keyspace maths (why masks have a ceiling)
A mask's size is the product of its charset sizes. Each token multiplies:
| Mask | Keyspace | Notes |
|---|---|---|
?d?d?d?d | 10,000 | A 4-digit PIN. Instant. |
?l?l?l?l?l?l | 308 million | 6 lowercase. Seconds on a fast hash. |
?u?l?l?l?l?d?d?d | ~11 billion | Policy shape. Minutes on a fast hash. |
?a?a?a?a?a?a?a?a | ~6.6 quadrillion | 8 all-printable. Hours to days on a fast hash. |
?a?a?a?a?a?a?a?a?a | ~630 quadrillion | 9 all-printable. The wall. |
Two lessons. First, constrain every position you can: dropping ?a to ?l?d on even a couple of positions cuts the keyspace by orders of magnitude. Second, the ceiling is real. Add characters and you eventually hit a wall no hardware clears in your lifetime, and against a slow hash that wall arrives at eight characters. When the estimated time reads in years, you are past the point where a mask is the right tool; switch to a wordlist plus rules.
When to use a mask (and when not to)
Use a mask when:
- You know the shape: a password policy, a leaked hint, an observed pattern like
Name@1234. - The password is plainly not in a wordlist (random-ish but structured).
- The hash is fast (MD5, NTLM, SHA-1) so a billion-candidate mask finishes.
Do not use a mask when:
- You have not run a wordlist and rules yet, those crack more, faster.
- The hash is slow (bcrypt, Argon2, sha512crypt); the maths does not allow it.
- You do not actually know the shape and are about to brute force
?a?a?a?a?a?a?a?aon a hope.
Where to go next
- Where masks fit in the bigger picture: dictionary vs brute force vs mask vs hybrid.
- The techniques that crack more: wordlists and rules.
- The fill-in-your-values commands: hashcat cheat sheet.
- The basics: how to use hashcat.
-a 3) is a targeted brute force where you specify the password's shape as a pattern of charset tokens, like ?u?l?l?l?d?d for "capital, three lowercase, two digits." hashcat tries only strings matching that pattern, which is far smaller than trying every possible string.?l is lowercase letters, ?u is uppercase, ?d is digits, ?s is symbols, and ?a is all of them combined. Each token is one character position. You can also define custom sets with -1 through -4 and reference them as ?1 to ?4.?a?a?a?a...), which is enormous. A mask constrains each position to a likely charset, collapsing the keyspace from quadrillions to billions. A mask is brute force, just a far smarter, finishable version of it.?a tokens or too many characters) or the hash is slow. Each extra token multiplies the keyspace, and slow hashes like bcrypt drop your guess rate by a factor of millions. Constrain the charsets, shorten the mask, or switch to a wordlist plus rules.Sources
Authoritative references this article was fact-checked against.
- hashcat, mask attack (official)hashcat.net
- hashcat wiki, core usage (official)hashcat.net





