How to Use John the Ripper for Password Auditing
John the Ripper (JtR) audits the strength of stored password hashes. In a security assessment, you use it to identify accounts using weak or guessable passwords before an attacker does. This guide covers authorized use. auditing your own infrastructure and running penetration tests you have explicit written permission to perform.
Legal note - Only run password auditing on systems and hashes you own or have written authorization to test. Unauthorized access to computer systems is a criminal offense in nearly every jurisdiction.
Install John the Ripper (Jumbo)
The “Jumbo” community build supports hundreds more hash types than the stock version:
Ubuntu / Debian. build from source for best performance
sudo apt install -y build-essential libssl-dev libgmp-dev \
libpcap-dev pkg-config libbz2-dev
git clone https://github.com/openwall/john.git /opt/john
cd /opt/john/src
./configure && make -j$(nproc)
Binary location
ls /opt/john/run/john
Symlink for convenience
sudo ln -s /opt/john/run/john /usr/local/bin/john
john --version
For GPU acceleration (dramatically faster on bcrypt/MD5crypt):
sudo apt install -y opencl-headers ocl-icd-libopencl1 nvidia-opencl-dev
cd /opt/john/src && ./configure --enable-opencl && make -j$(nproc)
Step 1 - Extract Password Hashes
Linux (shadow file)
On the target Linux system (requires root)
sudo unshadow /etc/passwd /etc/shadow > /tmp/linux_hashes.txt
Or just copy the shadow file directly
sudo cp /etc/shadow /tmp/shadow_backup.txt
Windows (NTLM from SAM)
On a Windows system you own, use secretsdump or impacket:
From a mounted Windows volume (e.g., forensics scenario)
pip3 install impacket
impacket-secretsdump -system /mnt/windows/Windows/System32/config/SYSTEM \
-sam /mnt/windows/Windows/System32/config/SAM LOCAL
Output format - username:RID:LM_hash:NTLM_hash:::
Save NTLM hashes for John
PostgreSQL
-- As superuser
SELECT usename, passwd FROM pg_shadow;
-- Hashes start with 'md5' (MD5) or 'SCRAM-SHA-256'
MySQL
mysql -u root -p -e "SELECT User, authentication_string FROM mysql.user;" \
> /tmp/mysql_hashes.txt
Step 2 - Identify Hash Type
John auto-detects many types
john --list=formats | grep -i ntlm
john --list=formats | grep -i sha512
hash-identifier (separate tool)
pip3 install hashid
hashid '$6$rounds=656000$...'
[+] SHA-512 Crypt
Common format strings for --format flag:
sha512crypt = Linux $6$ (SHA-512)
sha256crypt = Linux $5$ (SHA-256)
bcrypt = $2a$, $2b$ (Blowfish)
NT = Windows NTLM
md5crypt = Linux $1$ and FreeBSD MD5
Step 3 - Wordlist Attack
The fastest attack. tries every word in a dictionary:
Download rockyou (most common wordlist)
wget https://github.com/brannondorsey/naive-hashcat/releases/download/data/rockyou.txt \
-O /opt/john/run/rockyou.txt
Run wordlist attack
john --format=sha512crypt --wordlist=/opt/john/run/rockyou.txt /tmp/linux_hashes.txt
Show cracked passwords
john --show /tmp/linux_hashes.txt
Show only accounts with cracked passwords
john --show=left /tmp/linux_hashes.txt # shows remaining uncracked
Step 4 - Rules-Based Mangling
Rules apply transformations to each wordlist entry. capitalizing, adding numbers, substituting characters. This catches “Password1”, “p@ssw0rd”, and similar patterns:
Use the built-in Jumbo rules (extremely thorough)
john --format=sha512crypt \
--wordlist=/opt/john/run/rockyou.txt \
--rules=Jumbo \
/tmp/linux_hashes.txt
Use "best64" rules (fast, high yield)
john --format=sha512crypt \
--wordlist=/opt/john/run/rockyou.txt \
--rules=best64 \
/tmp/linux_hashes.txt
Write a custom rule in john.conf:
/opt/john/run/john.conf. add in [List.Rules:Custom] section
[List.Rules:Custom]
Append 1-4 digits
Az"[0-9]"
Az"[0-9][0-9]"
Az"[0-9][0-9][0-9]"
Az"[0-9][0-9][0-9][0-9]"
Capitalize first letter, append !
c Az"!"
l33t substitutions
ss$s
se3e
so0o
john --format=sha512crypt \
--wordlist=/opt/john/run/rockyou.txt \
--rules=Custom \
/tmp/linux_hashes.txt
Step 5 - Incremental (Brute-Force) Mode
When wordlist attacks fail, try all character combinations within a keyspace:
All lowercase alpha up to 6 chars (Alpha6 built-in)
john --format=sha512crypt --incremental=Alpha /tmp/linux_hashes.txt
All digits (for PIN-style passwords)
john --format=sha512crypt --incremental=Digits /tmp/linux_hashes.txt
Custom character set. printable ASCII, max 8 chars
Define in john.conf:
[Incremental:Printable8]
File = $JOHN/printable.chr
MaxLen = 8
MinLen = 1
john --format=NT --incremental=Printable8 /tmp/ntlm_hashes.txt
Step 6 - Run Multiple Sessions in Parallel
Split hash file and run two instances on different CPUs
split -n l/2 /tmp/linux_hashes.txt /tmp/split_
john --format=sha512crypt \
--session=session1 \
--wordlist=/opt/john/run/rockyou.txt \
--rules=Jumbo \
/tmp/split_aa &
john --format=sha512crypt \
--session=session2 \
--wordlist=/opt/john/run/rockyou.txt \
--rules=Jumbo \
/tmp/split_ab &
Check status of a running session
john --status=session1
Step 7 - Crack NTLM Hashes (Windows)
NTLM hashes are unsalted and fast to crack. thousands per second on a GPU:
Format - user:rid:lm:ntlm:::
echo "administrator:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::" \
> /tmp/ntlm.txt
Wordlist + rules
john --format=NT \
--wordlist=/opt/john/run/rockyou.txt \
--rules=Jumbo \
/tmp/ntlm.txt
Show results
john --format=NT --show /tmp/ntlm.txt
Step 8 - Read Results and Write an Audit Report
All cracked credentials
john --show /tmp/linux_hashes.txt
Summary
echo "Total hashes: $(wc -l < /tmp/linux_hashes.txt)"
echo "Cracked - $(john --show /tmp/linux_hashes.txt | tail -1)"
Identify accounts using duplicate passwords
john --show /tmp/linux_hashes.txt | awk -F: '{print $2}' | sort | uniq -d
Document findings with:
- Account name
- Password complexity (weak/medium. do not log the actual password in reports)
- Attack vector used (wordlist, rules, brute-force)
- enforce minimum 12-char policy, MFA, credential rotation
Defending Against Cracking
The best defense against offline hash cracking:
- Use bcrypt (cost factor 12+), Argon2id, or scrypt. not MD5/SHA-1/NTLM
- Enforce minimum 16 characters for admin accounts
- Enable MFA so cracked passwords alone aren’t sufficient
- Use hibp-go or similar to reject passwords in known breach datasets at sign-up
Check against HaveIBeenPwned k-anonymity API
import hashlib, httpx
def is_pwned_password(password: str) -> int:
digest = hashlib.sha1(password.encode()).hexdigest().upper()
prefix, suffix = digest[:5], digest[5:]
resp = httpx.get(f"https://api.pwnedpasswords.com/range/{prefix}")
for line in resp.text.splitlines():
h, count = line.split(":")
if h == suffix:
return int(count) # number of times seen in breaches
return 0
Related Reading
- How to Use Volatility for Memory Forensics
- How to Use Metasploit for Authorized Pentesting
- How to Use Nessus for Vulnerability Scanning
Built by theluckystrike. More at zovo.one