| Tested on | Kali GNU/Linux Rolling 2026.2 (kali-rolling) |
|---|---|
| Package | john 1.9.0-Jumbo-1+git20211102-0kali10john-data 1.9.0-Jumbo-1+git20211102-0kali10 |
| Lab environment | Pentest lab |
| Cert prep | CompTIA PenTest+ PT0-003 — password attacks and offline hash cracking |
| Privilege | Normal user for cracking; sudo for apt install |
| Scope | Input pipeline for John the Ripper Jumbo on Kali: prepare hashes, identify formats, wordlist and rules, single mask and incremental modes, zip2john ssh2john pdf2john, pot file and troubleshooting. Does not cover GPU hashcat workflows, live login brute force, or cracking third-party dumps without authorization. |
John the Ripper recovers plaintext from password hashes, and from files that first need a *2john converter. Kali ships the Jumbo build, which is the one with extra formats and helpers such as zip2john.
Many John errors come from malformed or incorrectly identified input rather than the cracking command itself. I start from that input, then run the modes on hashes I generated under /tmp/john-lab.
/etc/shadow, customer dumps, or random pastebin files.
John the Ripper quick start
┌─────────────────────────────────────┐
│ Collect hash or protected file │
└──────────────────┬──────────────────┘
↓
┌─────────────────────────────────────┐
│ Convert with *2john if needed │
└──────────────────┬──────────────────┘
↓
┌─────────────────────────────────────┐
│ Identify or force --format │
└──────────────────┬──────────────────┘
↓
┌─────────────────────────────────────┐
│ Choose mode from what you know: │
│ account metadata → single │
│ likely dictionary words → wordlist │
│ / rules │
│ known pattern → mask │
│ little useful information → │
│ incremental (usually last) │
└──────────────────┬──────────────────┘
↓
┌─────────────────────────────────────┐
│ john --show / john.pot │
└─────────────────────────────────────┘How John the Ripper works
John does not reverse a hash. It hashes candidate passwords with the same algorithm and salt, then compares the result to the stored value. That is offline work. Guessing against a live SSH or web login is a different problem; see SSH brute force for that.
hash or file → prepare (*2john) → format → mode → candidates → compare → pot / --show| Stage | What you do |
|---|---|
| Input | Raw hash, user:hash, Unix shadow line, or encrypted file |
| Prepare | Run zip2john, ssh2john, pdf2john, or unshadow when the file is not already John-ready |
| Format | Let John auto-detect, or force --format= when the string is ambiguous |
| Mode | Single, wordlist, rules, mask, or incremental |
| Result | Match lands in the pot file; john --show prints plaintext |
Core Openwall John is a smaller binary. Kali ships Jumbo, with hundreds of formats and the *2john helpers. Check that you are on Jumbo before you spend time hunting a converter that core John never had.
Verify the Jumbo build and formats
Confirm the packages:
dpkg-query -W john john-datajohn 1.9.0-Jumbo-1+git20211102-0kali10
john-data 1.9.0-Jumbo-1+git20211102-0kali10Both packages are Jumbo. Print the build line:
john --list=build-info 2>&1 | head -8Version: 1.9.0-jumbo-1+bleeding-aec1328d6c 2021-11-02 10:45:52 +0100
Build: linux-gnu 64-bit x86_64 AVX2 AC OMP
SIMD: AVX2, interleaving: MD4:3 MD5:3 SHA1:1 SHA256:1 SHA512:1
System-wide exec: /usr/lib/john
System-wide home: /usr/share/john
Private home: ~/.john
CPU tests: AVX2
CPU fallback binary: john-xop-ompOn this Kali build, john --list=build-info reports Private home: ~/.john, so the default pot is ~/.john/john.pot. Other builds and layouts can differ.
List formats (truncated; this Jumbo build reports about 300):
john --list=formats 2>&1 | head -6descrypt, bsdicrypt, md5crypt, md5crypt-long, bcrypt, scrypt, LM, AFS,
tripcode, AndroidBackup, adxcrypt, agilekeychain, aix-ssha1, aix-ssha256,
aix-ssha512, andOTP, ansible, argon2, as400-des, as400-ssha1, asa-md5,
AxCrypt, AzureAD, BestCrypt, BestCryptVE4, bfegg, Bitcoin, BitLocker,
bitshares, Bitwarden, BKS, Blackberry-ES10, WoWSRP, Blockchain, chap,
Clipperz, cloudkeychain, dynamic_n, cq, CRC32, cryptoSafe, sha1crypt, You do not need to memorize that list. If a load fails, grep it for the name you expect: sha512crypt, Raw-MD5, PKZIP, SSH, PDF.
Prepare the hash correctly
Create a lab directory and a short wordlist so each mode finishes in a few seconds:
LAB=/tmp/john-lab
mkdir -p "$LAB"
printf 'password\nroot\nsecret123\nadmin\nsummer\n' > "$LAB/wordlist.txt"John accepts several shapes:
| Input shape | Example | Notes |
|---|---|---|
username:hash |
debianlab:$6$labsalt$… |
Best for Unix crypt; shows the account in --show |
| Raw hash only | 5d7845ac6ee7cfffafc5fe5f35cf666d |
Often needs --format= (ambiguous length) |
| unshadow line | From unshadow passwd shadow |
Needed for single mode with GECOS fields |
*2john line |
$pkzip$…, $sshng$…, $pdf$… |
Converter output, not the original file |
Pasting a random hex blob from a blog often fails because the salt, prefix, or file format is missing. For learning, generate the hashes yourself.
Build a SHA-512 crypt line that John can load without guessing:
HASH=$(openssl passwd -6 -salt labsalt secret123)
printf 'debianlab:%s\n' "$HASH" > "$LAB/hashes.txt"The file should look like:
debianlab:$6$labsalt$dBjQ56YjzkWY27Iq38NPmtW0AEEmCEe9WNVC8uk1nzd0PjQpoAL8BNCsDTEfmZizepT1JJcGa50QmDVR3DpVu1$6$ means SHA-512 crypt. That prefix is why this line auto-detects cleanly.
Identify or force the hash format
John auto-detects many formats. Treat that guess as a hint. A 32-character hex string can be LM, NT, Raw-MD5, or several other types.
Generate a raw MD5 of secret123 and load it without --format:
printf '%s\n' "$(printf 'secret123' | md5sum | awk '{print $1}')" > "$LAB/rawmd5.txt"
john --wordlist="$LAB/wordlist.txt" "$LAB/rawmd5.txt" 2>&1 | head -8Warning: detected hash type "LM", but the string is also recognized as "dynamic=md5($p)"
Use the "--format=dynamic=md5($p)" option to force loading these as that type instead
Warning: detected hash type "LM", but the string is also recognized as "HAVAL-128-4"
Use the "--format=HAVAL-128-4" option to force loading these as that type instead
Warning: detected hash type "LM", but the string is also recognized as "MD2"
Use the "--format=MD2" option to force loading these as that type insteadJohn guessed LM first. For this lab hash, force Raw-MD5:
john --format=raw-md5 --wordlist="$LAB/wordlist.txt" "$LAB/rawmd5.txt"Loaded 1 password hash (Raw-MD5 [MD5 256/256 AVX2 8x3])
secret123 (?)
1g 0:00:00:00 DONE (2026-09-03 12:45) 25.00g/s 125.0p/s 125.0c/s 125.0C/s password..summerLoaded 1 password hash (Raw-MD5 …) is the format John actually used. john --show=formats file prints a JSON list of labels it considered for each line.
A wrong --format often fails cleanly:
john --format=nt --wordlist="$LAB/wordlist.txt" "$LAB/hashes.txt"No password hashes loaded (see FAQ)The shadow line is sha512crypt, not NT. Change --format, or omit it when the $6$ prefix already names the type.
Choose a cracking mode
Pick the mode from what you know about the password. Openwall recommends single mode first when account metadata is available, and its default batch path moves through single, wordlist, then incremental. Mask mode is Jumbo-specific, and whether it belongs before or after rules depends on how much structure you already know.
| What you know | Start with |
|---|---|
Username or GECOS fields (unshadow) |
Single |
| Likely dictionary words | Wordlist, then rules |
Known pattern (secret plus three digits) |
Mask |
| Little useful information | Incremental, usually last |
An unrestricted incremental run against a long SHA-512 crypt password is rarely the right first move. Prefer targeted wordlists, rules, or a constrained mask when you have useful password information.
| Mode | Flag | Best when |
|---|---|---|
| Single | --single |
Password may match username or GECOS |
| Wordlist | --wordlist=FILE |
Password may be in a dictionary |
| Rules | --rules / --rules=NAME |
Variants of dictionary words |
| Mask | --mask=MASK |
Known structure (?d digits, ?l letters) |
| Incremental | --incremental[=MODE] |
Short charset search after smarter modes fail |
Crack hashes with a wordlist
Wordlist mode hashes each line from your list and compares it to the stored hash. Attack the SHA-512 crypt file from earlier:
john --wordlist="$LAB/wordlist.txt" "$LAB/hashes.txt"Loaded 1 password hash (sha512crypt, crypt(3) $6$ [SHA512 256/256 AVX2 4x])
Cost 1 (iteration count) is 5000 for all loaded hashes
secret123 (debianlab)
1g 0:00:00:00 DONE (2026-09-03 12:45) 14.28g/s 71.42p/s 71.42c/s 71.42C/s password..summersecret123 (debianlab) is the recovered password. Print it again with --show:
john --show "$LAB/hashes.txt"debianlab:secret123
1 password hash cracked, 0 leftFor larger runs on Kali, write RockYou into the lab directory so the system copy stays compressed:
gzip -dc /usr/share/wordlists/rockyou.txt.gz > "$LAB/rockyou.txt"
john --wordlist="$LAB/rockyou.txt" "$LAB/hashes.txt"Do not pass John the .gz path. If you know how the org names accounts, a custom list from a wordlist generator is usually a better start than the full RockYou file.
Use word mangling rules
Rules take each wordlist entry and change it: case, trailing digits, leetspeak, and similar. From summer you get Summer, SUMMER, summer1, and so on without typing every variant.
First, show that a capitalized password is missing from the plain list. Hash Secret123 while the wordlist only has lowercase secret123:
RULES_HASH=$(openssl passwd -6 -salt rules1 Secret123)
printf 'ruleslab:%s\n' "$RULES_HASH" > "$LAB/rules.txt"
john --wordlist="$LAB/wordlist.txt" "$LAB/rules.txt"0g 0:00:00:00 DONE (2026-09-03 12:46) 0g/s 33.33p/s 33.33c/s 33.33C/s secret123..adminNothing recovered. Add the built-in Single ruleset:
john --wordlist="$LAB/wordlist.txt" --rules=Single "$LAB/rules.txt"--rules=Single does not enable Single Crack mode; it applies the ruleset named Single to the supplied wordlist. Single Crack mode itself uses --single.
Loaded 1 password hash (sha512crypt, crypt(3) $6$ [SHA512 256/256 AVX2 4x])
Secret123 (ruleslab)
1g 0:00:00:01 DONE (2026-09-03 12:46) 0.7518g/s 192.4p/s 192.4c/s 192.4C/s secret123..admin.A rule that only appends 1 is enough to show the idea. Hash summer1, then use an immediate rule:
SUMMER1=$(openssl passwd -6 -salt r2 summer1)
printf 'ruleuser:%s\n' "$SUMMER1" > "$LAB/customrule.txt"
john --wordlist="$LAB/wordlist.txt" --rules=':$1' "$LAB/customrule.txt"summer1 (ruleuser)
1g 0:00:00:00 DONE (2026-09-03 12:46) 20.00g/s 60.00p/s 60.00c/s 60.00C/s secret1231..admin1The leading : tells Jumbo that the rest of the argument is an immediate command-line rule rather than a named ruleset; $1 appends the character 1. The full rule language is in the Openwall RULES docs. For beginner use, start with a named ruleset or a short immediate rule before moving into the full rule language.
Use single mode when account metadata exists
Single mode builds candidates from usernames and GECOS fields. Create a throwaway passwd and shadow pair where the password is the username:
printf 'johndoe:x:10001:10001:johndoe:/home/johndoe:/bin/bash\n' > "$LAB/passwd"
SINGLE_HASH=$(openssl passwd -6 -salt single1 johndoe)
printf 'johndoe:%s\n' "$SINGLE_HASH" > "$LAB/shadow"Combine them with unshadow:
unshadow "$LAB/passwd" "$LAB/shadow" > "$LAB/unshadowed.txt"Run single mode on the combined file:
john --single "$LAB/unshadowed.txt"Loaded 1 password hash (sha512crypt, crypt(3) $6$ [SHA512 256/256 AVX2 4x])
johndoe (johndoe)
1g 0:00:00:00 DONE (2026-09-03 12:46) 10.00g/s 40.00p/s 40.00c/s 40.00C/s johndoe..johndJohn recovered johndoe because the password matched the username. On a real job this only applies after you lawfully have passwd and shadow data.
Mask mode versus incremental mode
Mask mode fills a known pattern. Digits use ?d, lowercase ?l, uppercase ?u. Crack the earlier raw MD5 when you already know it looks like secret plus three digits:
john --format=raw-md5 --mask='secret?d?d?d' "$LAB/rawmd5.txt"Loaded 1 password hash (Raw-MD5 [MD5 256/256 AVX2 8x3])
secret123 (?)
1g 0:00:00:00 DONE (2026-09-03 12:46) 33.33g/s 12800p/s 12800c/s 12800C/s secret111..secret363Incremental mode walks a charset in a statistical order. It is not the automatic next step after a wordlist miss. Use it on short or weak hashes. An MD5 crypt hash of the single character a finished in tens of seconds here:
INC_HASH=$(openssl passwd -1 -salt in1 a)
printf 'shortlab:%s\n' "$INC_HASH" > "$LAB/incremental.txt"
john --incremental=ASCII "$LAB/incremental.txt"Loaded 1 password hash (md5crypt, crypt(3) $1$ (and variants) [MD5 256/256 AVX2 8x3])
a (shortlab)
1g 0:00:00:23 DONE (2026-09-03 12:46) 0.04244g/s 6454p/s 6454c/s 6454C/s jhunds..limAn unrestricted incremental run against a long SHA-512 crypt password may be computationally impractical and can run far longer than hours. Prefer targeted wordlists, rules, or a constrained mask when you have useful password information.
Crack ZIP, SSH, and PDF with *2john
A ZIP, SSH key, or PDF is not a shadow line. Convert it first, then crack.
file → *2john → john hash file → mode → --showZIP with zip2john
Create a password-protected ZIP in the lab. -P is used here only to create a disposable lab archive because it places the password on the command line:
printf 'hosts sample\n' > "$LAB/sample.txt"
zip -P secret123 -j "$LAB/protected.zip" "$LAB/sample.txt"Extract a John line with zip2john:
zip2john "$LAB/protected.zip" > "$LAB/zip.hashes"Crack that line with the lab wordlist:
john --wordlist="$LAB/wordlist.txt" "$LAB/zip.hashes"Loaded 1 password hash (PKZIP [32/64])
secret123 (protected.zip/sample.txt)
1g 0:00:00:00 DONE (2026-09-03 12:47) 20.00g/s 100.0p/s 100.0c/s 100.0C/s password..summerSSH private key with ssh2john
Generate a throwaway key with a known passphrase, then convert it:
ssh-keygen -t ed25519 -f "$LAB/labkey" -N "secret123" -q
ssh2john "$LAB/labkey" > "$LAB/ssh.hashes"Run John on the extracted hash:
john --wordlist="$LAB/wordlist.txt" "$LAB/ssh.hashes"Loaded 1 password hash (SSH, SSH private key [RSA/DSA/EC/OPENSSH 32/64])
secret123 (/tmp/john-lab/labkey)
1g 0:00:00:03 DONE (2026-09-03 12:47) 0.3267g/s 1.633p/s 1.633c/s 1.633C/s password..summerDelete the throwaway key when you finish.
PDF with pdf2john
On Kali, pdf2john is a symlink to pdf2john.pl. I encrypted a PDF with qpdf, then converted it:
qpdf --encrypt secret123 secret123 256 -- "$LAB/plain.pdf" "$LAB/secret.pdf"
pdf2john "$LAB/secret.pdf" > "$LAB/pdf.hashes"Crack the PDF hash with the same wordlist:
john --wordlist="$LAB/wordlist.txt" "$LAB/pdf.hashes"Loaded 1 password hash (PDF [MD5 SHA2 RC4/AES 32/64])
secret123 (/tmp/john-lab/secret.pdf)
1g 0:00:00:00 DONE (2026-09-03 12:47) 6.250g/s 31.25p/s 31.25c/s 31.25C/s password..summerOther Jumbo helpers (rar2john, 7z2john, keepass2john) follow the same pattern. Match the converter to the file type. Run the appropriate converter first; John reads the converter output rather than the original binary file.
Show cracked passwords and the pot file
Cracked plaintext lands in the pot file. On this Kali build, john --list=build-info reports Private home: ~/.john, so the default pot is ~/.john/john.pot. Other builds and layouts can differ. A second run on the same hash can finish immediately:
john --wordlist="$LAB/wordlist.txt" "$LAB/hashes.txt"No password hashes left to crack (see FAQ)That usually means the pot already holds the result. Print it:
john --show "$LAB/hashes.txt"debianlab:secret123
1 password hash cracked, 0 leftA pot line looks like ciphertext:plaintext. For a clean lab retest, use a new salt or username, or point John at a temporary pot with --pot=/tmp/john-lab/lab.pot.
John the Ripper versus hashcat
| John the Ripper | hashcat | |
|---|---|---|
| Strength | Convenient *2john converters, Single mode, mixed CPU workflows |
GPU acceleration and optimized high-throughput attacks |
| Best fit | Mixed file formats, quick audits on a laptop | High-volume offline cracking when a GPU is available |
| Overlap | Both crack many of the same hash types | Use both; pick by hardware and input type |
Pick by hardware and input type. For GPU-focused work, continue with crack hashes with hashcat.
Troubleshooting John the Ripper
| Symptom | Likely cause | What to check |
|---|---|---|
No password hashes loaded |
Malformed line, wrong format, unsupported type | Confirm user:hash or converter output; try --format=; see FAQ |
| Autodetect picks LM / NT for hex MD5 | Ambiguous 32-hex string | Force --format=raw-md5 (or the real type) |
Wrong --format |
Format name does not match the ciphertext | john --list=formats; john --show=formats file |
Session ends with 0g and no new crack |
Password not in list, or already in pot | Expand wordlist / add rules; run john --show |
No password hashes left to crack |
Hash already in pot | --show; new salt for a clean demo; or --pot= temp file |
*2john output will not load |
Wrong converter or unencrypted file | Recreate protected file; use zip2john / ssh2john / pdf2john that matches |
| RockYou path empty | Still gzipped | Write an uncompressed copy under $LAB with gzip -dc before --wordlist= |
| Incremental never finishes | Slow KDF / long password | Prefer wordlist + rules; check john --status |
Summary
John Jumbo on Kali hashes candidates and compares them to a prepared line. I checked the Jumbo build, built lab hashes under /tmp/john-lab, and forced --format=raw-md5 after auto-detect picked LM for a 32-character hex string. Wordlist mode recovered secret123 from sha512crypt. Rules found Secret123 and summer1. Single mode recovered a username match. A mask cracked secret123 when the pattern was known. Incremental recovered a one-character md5crypt hash in 23 seconds.
ZIP, SSH, and PDF used the same path: converter, then John, then --show. Recovered plaintext stays in the pot file, so a second run can say nothing is left. Prefer single, wordlist, rules, or a constrained mask when you know something about the password; leave unrestricted incremental for short or weak hashes. Use hashcat when you have a GPU and a large candidate set.
References
- John the Ripper documentation (Openwall)
- John the Ripper cracking modes
- John the Ripper RULES
- openwall/john on GitHub
Frequently Asked Questions
Why does John say no password hashes loaded?
The input line is not valid for the selected format. Typical causes: missing user: prefix, wrong --format, ciphertext John does not support, extra spaces, or a file that still needs a *2john converter.
How do I identify the hash format for John?
Use prefixes such as $6$ for sha512crypt. For raw hex, length is not enough. Check john --list=formats, john --show=formats file, and force --format= when auto-detect warns about several matches.
Where does John store cracked passwords?
In the pot file. On this Kali Jumbo build that is usually ~/.john/john.pot, matching Private home: ~/.john from john --list=build-info. Use john --show on the same hash file to print recovered plaintext. Override the path with --pot= when you want an isolated lab pot.
What is the difference between wordlist rules and mask mode?
Rules change dictionary words (case, digits, substitutions). Mask mode fills a pattern such as secret?d?d?d. Use rules when you have a base word. Use a mask when you know the shape.
How do I crack a ZIP or SSH key with John?
Convert first with zip2john or ssh2john, save the line to a file, then run John on that file. Finish with john --show.
Should I use John or hashcat?
John is convenient for *2john converters, Single mode, and mixed CPU lab work. hashcat is stronger when you have a GPU and a large candidate set. Many labs keep both.

