John the Ripper
John the Ripper takes an offline hash or a protected file and tries to recover the password behind it, using wordlists, mutation rules, mask patterns, and a large catalog of hash formats. The real work is rarely the cracking itself: it is preparing the input, naming the format correctly, and picking a smart attack so you do not burn hours on the wrong run. Reach for it the moment you have a /etc/shadow line, a locked ZIP or SSH key, or a captured NetNTLMv2 hash from an authorized test.
Mental model: john [mode] [--format=NAME] [--wordlist=... --rules] HASHFILE. Everything else is one flag away.
New to cracking? Core concepts
- Hash: the target John attacks; it hashes each guess and compares, it never reverses (
$6$...sha512crypt,$2y$...bcrypt, a bare 32-hex NTLM) - Format: how John hashes each guess (
--format=sha512crypt,nt,bcrypt); the single most important choice - Mode: how candidates are generated -
--single,--wordlist,--mask,--incremental - Rules: per-word mutations (
--rules,--rules=Jumbo) that append digits, capitalize, and leet-swap - Converter: a
*2johnscript that turns a file into a crackable hash line (zip2john,ssh2john,keepass2john) - Pot file:
~/.john/john.pot, every password John has ever recovered; checked automatically so you never crack a hash twice - Session: a named, resumable run (
--session=NAME,--restore=NAME) - Jumbo vs core: the community
jumbobuild adds the converters and hundreds of formats the strippedcorebuild lacks
When to reach for John (and when not)
Reach for it when you have an offline hash or a protected file you are authorized to test: a shadow line, a password-protected ZIP or SSH key, a captured NetNTLMv2 or Kerberos ticket, or a quick check that a password policy resists common guesses. John shines at recognizing odd inputs and converting files into something crackable.
Reach for something else when raw speed on a big hash list matters and you have a GPU (hashcat), when you only need to verify a plaintext you already know (sha256sum and compare), when you still need to name the hash (hashid), or when the target is a live login rather than an offline hash (that is a different tool, and in-scope only).
Install, update, verify#
sudo apt install -y john # Debian / Ubuntu / Kali (ships the jumbo build)
sudo dnf install -y john # Fedora / RHEL
brew install john-jumbo # macOS (Homebrew)
sudo apt install --only-upgrade -y john # update
john --list=build-info # version + build info (confirms the jumbo build)
command -v john # confirm it is on PATH
john --list=formats # the format catalog loaded (jumbo lists hundreds)
john --test=10 --format=nt # 10-second self-test / benchmark for one format
On Kali the package is already jumbo, so the *2john converters are present. If apt hands you a stripped “core” John with no converters, build jumbo from source: git clone --depth 1 https://github.com/openwall/john.git, then cd john/src && ./configure && make -sj4. The binaries land in ../run, including run/john and every *2john script.
Flags you’ll actually use#
Skim these first; the cheat sheet below is these flags combined.
| Flag | Does | Flag | Does |
|---|---|---|---|
--wordlist= | Dictionary attack | --show | Print cracked plaintext |
--rules | Mutate words (Wordlist ruleset) | --show=left | Print what is still uncracked |
--rules=Jumbo | Bigger mutation ruleset | --status | Progress of a running session |
--single | Derive guesses from usernames | --session= | Name a run for resume |
--mask= | Pattern brute force (?l?d?s) | --restore= | Resume a saved session |
--incremental | Charset brute force | --fork= | Split across CPU cores |
--format= | Force the hash format | --pot= | Use a per-job pot file |
--list=formats | List supported formats | --max-length= | Cap candidate length |
--loopback | Reuse pot words as the list | --stdout | Print candidates, do not crack |
--test | Benchmark a format | --min-length= | Floor candidate length |
Cheat sheet#
Each attack block starts simple and adds one flag at a time, so you can stop at the line that cracks it.
# Identify the hash before you attack anything
john --list=formats # every format name John knows
john --list=formats | tr ',' '\n' | grep -i crypt # narrow to a family
head -c 60 HASHFILE; echo # eyeball the prefix ($6$, $2y$, $krb5...)
hashid '$6$abc$def...' # guess the type from the string
# Turn a protected file into a crackable hash line (*2john)
unshadow /etc/passwd /etc/shadow > hashes/linux.hash # merge so --single sees usernames
zip2john secret.zip > hashes/zip.hash # ZIP archive
rar2john archive.rar > hashes/rar.hash # RAR archive
7z2john.pl archive.7z > hashes/7z.hash # 7-Zip archive (Perl script)
ssh2john id_rsa > hashes/ssh.hash # encrypted SSH private key
keepass2john db.kdbx > hashes/kp.hash # KeePass database
office2john report.docx > hashes/office.hash # Office document
gpg2john secret.gpg > hashes/gpg.hash # GPG key
# Build up an attack: stop at the line that cracks it
john HASHFILE # 1. auto-detect + default modes
john --wordlist=WORDLIST HASHFILE # 2. plain dictionary
john --wordlist=WORDLIST --rules HASHFILE # 3. + mutation rules
john --wordlist=WORDLIST --rules=Jumbo HASHFILE # 4. + the big ruleset
# Attack modes, cheapest to most expensive
john --single HASHFILE # derive guesses from usernames/GECOS
john --wordlist=WORDLIST --rules HASHFILE # dictionary + rules
john --loopback HASHFILE # reuse already-cracked words
john --mask='?u?l?l?l?l?d?d?d' HASHFILE # known pattern (mask mode)
john --incremental=Digits HASHFILE # brute force one charset
# Force the format when detection is wrong or ambiguous
john --format=nt --wordlist=WORDLIST HASHFILE # Windows NTLM
john --format=sha512crypt --wordlist=WORDLIST HASHFILE # Linux $6$
john --format=bcrypt --wordlist=WORDLIST HASHFILE # $2y$
john --format=netntlmv2 --wordlist=WORDLIST HASHFILE # captured NetNTLMv2
# Speed and scope control
john --fork=4 --wordlist=WORDLIST HASHFILE # split across 4 CPU cores
john --test --format=nt # benchmark a format
john --incremental --max-length=6 HASHFILE # cap the keyspace
# Long runs: name, watch, resume
john --session=box01 --wordlist=WORDLIST --rules HASHFILE # name it (press q to pause)
john --status=box01 # progress without stopping it
john --restore=box01 # resume after a pause or crash
# Read results out of the pot file
john --show HASHFILE # cracked plaintext (username)
john --show=left HASHFILE # what is still uncracked
john --pot=cracked/box01.pot --show HASHFILE # read a per-job pot file
# Preview what a ruleset actually generates
john --wordlist=WORDLIST --rules --stdout | head # see the mangled candidates
Command breakdowns#
Each block explains one situation, the exact command, and what to expect back.
Identify the hash format before you attack#
head -c 60 HASHFILE; echo
john --list=formats | tr ',' '\n' | grep -i crypt
The prefix names the algorithm: $1$ md5crypt, $5$ sha256crypt, $6$ sha512crypt, $2y$ bcrypt, $krb5tgs$ Kerberoast, a bare 32-hex string is usually NTLM. Confirm the exact John name against --list=formats, then pass it to --format.
Merge passwd and shadow so single-crack sees usernames#
unshadow /etc/passwd /etc/shadow > hashes/linux.hash
unshadow stitches each account’s hash back onto its username and GECOS fields. Do this before --single, otherwise the mode has no usernames to build guesses from.
Convert a password-protected ZIP into a hash#
zip2john secret.zip > hashes/zip.hash
john --wordlist=WORDLIST hashes/zip.hash
zip2john writes one hash line describing the archive’s encryption; the second command runs the recovery. Not on PATH? The converters live near John: ls /usr/share/john/*2john* /usr/bin/*2john 2>/dev/null finds them.
Convert an encrypted SSH key and crack the passphrase#
ssh2john id_rsa > hashes/ssh.hash
john --wordlist=WORDLIST hashes/ssh.hash
Turns an encrypted private key into a crackable line so you can recover the passphrase. Only on keys you own or are authorized to test. An unencrypted key produces no usable hash.
Run a plain wordlist attack#
john --wordlist=WORDLIST HASHFILE
The usual first real attack. Cracked lines print as plaintext (username). Heed any format warning: if John is unsure, it may be hashing your guesses with the wrong algorithm.
Add mutation rules when plain words fail#
john --wordlist=WORDLIST --rules HASHFILE
john --wordlist=WORDLIST --rules=Jumbo HASHFILE
--rules applies the Wordlist ruleset (capitalize, append digits, leet-swap), generating many candidates per word. --rules=Jumbo is a much wider set: slower, but it reaches P@ssw0rd1-style passwords a plain list misses.
Force the format when detection is ambiguous#
john --format=sha512crypt --wordlist=WORDLIST HASHFILE
When John warns of several matching formats, pick one explicitly instead of letting it guess. Use --list=formats to find the exact name (sha512crypt, nt, bcrypt, netntlmv2, krb5tgs).
Crack NT hashes from a Windows box#
john --format=nt --wordlist=WORDLIST hashes/nt.hash
NT (NTLM) hashes are unsalted, so a good wordlist chews through them fast. Feed the 32-hex hash, or a full user:rid:lm:nt::: dump line and John reads the NT field.
Run single-crack mode on a shadow file#
john --single hashes/linux.hash
Single-crack builds guesses from each account’s own username and GECOS fields, so it catches admin:admin and name-based passwords for almost no cost. Run it first on unshadowed files.
Target a known password pattern with mask mode#
john --mask='?u?l?l?l?l?d?d?d' HASHFILE
Mask mode brute-forces a fixed shape: ?u upper, ?l lower, ?d digit, ?s special, ?a any printable. Perfect when you know the policy (one capital, five letters, three digits) and a full wordlist is overkill.
Brute force a small keyspace with incremental mode#
john --incremental=Digits --max-length=6 HASHFILE
Incremental tries character combinations from a charset defined in john.conf (Digits, Alpha, ASCII). It has no natural end, so cap it with --max-length or it runs effectively forever. Last resort only.
Speed up a CPU run with fork#
john --fork=4 --wordlist=WORDLIST HASHFILE
--fork=4 splits the keyspace across four child processes. Match the count to your physical cores. This is CPU parallelism, not GPU acceleration: for fast formats at scale, move to Hashcat.
Name, pause, and resume a long session#
john --session=box01 --wordlist=WORDLIST --rules HASHFILE
john --restore=box01
--session records progress under a name you choose. Press q to pause, then --restore=box01 picks up where it stopped. Check a running job non-invasively with john --status=box01.
Check what is already cracked without rerunning#
john --show HASHFILE
john --show=left HASHFILE
--show reads results straight from the pot file, no cracking; --show=left prints the hashes still unbroken. If a rerun seems to “do nothing,” this is why: the answers are already in ~/.john/john.pot.
Keep engagements separate with a per-job pot file#
john --pot=cracked/box01.pot --wordlist=WORDLIST HASHFILE
john --pot=cracked/box01.pot --show HASHFILE
By default every job writes to one shared ~/.john/john.pot, leaking recovered passwords between engagements. A per-job --pot= keeps each client’s loot scoped and the same flag reads it back.
Benchmark a format to estimate feasibility#
john --test=10 --format=bcrypt
Prints the guesses-per-second rate for that format on your hardware. Use it to sanity-check before a long run: a slow salted hash like bcrypt at a few thousand c/s tells you incremental is hopeless and only a targeted wordlist will pay off.
Reading the output#
| You see | Meaning | Do next |
|---|---|---|
Summer2024 (admin) | Cracked: plaintext then label | This is your finding, record it |
password (?) | Cracked, no username field | Fine for a bare hash |
Loaded N password hashes... | Input parsed correctly | The attack is running |
0g 0:00:00:10 | Zero cracked after 10s | Wrong list or format, not broken yet |
No password hashes loaded | Empty file or wrong format | Check the line, set --format |
No password hashes left to crack | All already in the pot | Run --show |
| Ambiguous-format warning | Several formats match | Set --format explicitly |
g/s, p/s, c/s rates | Guess / candidate / crypt speed | Low c/s means a slow salted hash |
Troubleshooting#
| Problem | Cause | Fix |
|---|---|---|
command not found | Not installed / stale PATH | Reinstall; open a fresh shell |
No password hashes loaded | Wrong format or malformed line | Set --format=FORMAT; inspect the line |
Converter missing (zip2john) | Core build, not jumbo | Install jumbo or build from source |
| Warns of format ambiguity | Multiple matching formats | Pick one with --format=FORMAT |
Run finishes at 0g | Word not in list / no rules | Add --rules or a stronger WORDLIST |
No password hashes left to crack | Already in the pot file | Run john --show HASHFILE |
| Crawling speed | Slow salted hash on CPU | Add --fork, narrow scope, or use Hashcat |
| Cannot resume a job | Session name mismatch | Match --restore= to the --session= name |
| Pot mixes clients | Shared default pot | Use --pot=cracked/job.pot per job |
Gotchas#
- John format names are not Hashcat mode numbers.
ntin John is-m 1000in Hashcat; never copy an identifier from one tool into the other. --ruleswith no name is only the Wordlist ruleset, not “all rules.” Name a wider set like--rules=Jumbowhen the default coverage runs dry.--singleneeds usernames in the file. A bare hash with nouser:field starves the mode; rununshadowfirst so it has account fields to work from.- A rerun that “does nothing” usually means the pot file already has it. John silently skips cracked hashes;
--showreveals the answers instead of an empty screen. - Incremental has no built-in stop. Without
--max-lengthit explores a growing keyspace forever; always cap the length before you start. --forksplits CPU work, it does not add GPU speed. For fast unsalted formats at volume, that is Hashcat’s job, not more forks.
Pairs with#
hashid and hash-identifier name the hash before you set --format. The *2john scripts (zip2john, ssh2john, keepass2john, office2john) turn protected files into crackable input, and unshadow merges passwd and shadow for single-crack mode. hashcat takes over the heavy lifting when a GPU and a big list beat CPU cracking, using mode numbers instead of format names. For candidate lists, rockyou.txt and SecLists are where most attacks start, and tee/grep/awk capture John’s output and pot file into tidy notes.