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 *2john script 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 jumbo build adds the converters and hundreds of formats the stripped core build 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.

FlagDoesFlagDoes
--wordlist=Dictionary attack--showPrint cracked plaintext
--rulesMutate words (Wordlist ruleset)--show=leftPrint what is still uncracked
--rules=JumboBigger mutation ruleset--statusProgress of a running session
--singleDerive guesses from usernames--session=Name a run for resume
--mask=Pattern brute force (?l?d?s)--restore=Resume a saved session
--incrementalCharset brute force--fork=Split across CPU cores
--format=Force the hash format--pot=Use a per-job pot file
--list=formatsList supported formats--max-length=Cap candidate length
--loopbackReuse pot words as the list--stdoutPrint candidates, do not crack
--testBenchmark 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 seeMeaningDo next
Summer2024 (admin)Cracked: plaintext then labelThis is your finding, record it
password (?)Cracked, no username fieldFine for a bare hash
Loaded N password hashes...Input parsed correctlyThe attack is running
0g 0:00:00:10Zero cracked after 10sWrong list or format, not broken yet
No password hashes loadedEmpty file or wrong formatCheck the line, set --format
No password hashes left to crackAll already in the potRun --show
Ambiguous-format warningSeveral formats matchSet --format explicitly
g/s, p/s, c/s ratesGuess / candidate / crypt speedLow c/s means a slow salted hash

Troubleshooting#

ProblemCauseFix
command not foundNot installed / stale PATHReinstall; open a fresh shell
No password hashes loadedWrong format or malformed lineSet --format=FORMAT; inspect the line
Converter missing (zip2john)Core build, not jumboInstall jumbo or build from source
Warns of format ambiguityMultiple matching formatsPick one with --format=FORMAT
Run finishes at 0gWord not in list / no rulesAdd --rules or a stronger WORDLIST
No password hashes left to crackAlready in the pot fileRun john --show HASHFILE
Crawling speedSlow salted hash on CPUAdd --fork, narrow scope, or use Hashcat
Cannot resume a jobSession name mismatchMatch --restore= to the --session= name
Pot mixes clientsShared default potUse --pot=cracked/job.pot per job

Gotchas#

  • John format names are not Hashcat mode numbers. nt in John is -m 1000 in Hashcat; never copy an identifier from one tool into the other.
  • --rules with no name is only the Wordlist ruleset, not “all rules.” Name a wider set like --rules=Jumbo when the default coverage runs dry.
  • --single needs usernames in the file. A bare hash with no user: field starves the mode; run unshadow first 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; --show reveals the answers instead of an empty screen.
  • Incremental has no built-in stop. Without --max-length it explores a growing keyspace forever; always cap the length before you start.
  • --fork splits 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.

Find us elsewhere

Merch, stickers, and moreSupport the work at the Solvere Labs shop