Password Cracking using John The Ripper
Password Cracking john the ripper

Password Cracking using John The Ripper

February 09, 2021 • 27 min read • 135 views • 0 discussions
Table of Contents

    When working with security-related issues, one common challenge is dealing with passwords that we don't know. For example, during an authorized security assessment, we may obtain a password hash from a database or another source.

    But there is one problem. We don't have the original password.

    The password is usually not stored directly. Instead, applications should store passwords using a password-hashing mechanism.

    So, if all we have is the hash, we cannot simply read the original password from it.

    We have to test possible passwords and determine whether any of them produce a matching result. This is where password-auditing and password-recovery tools can help.

    Hello everyone, and welcome to a new video. In this article, we're going to learn about a popular password-auditing tool called John the Ripper, commonly known as John.

    We'll understand: 

    1. what this tool does 
    2. how they work and 
    3. how we can use it safely in a controlled laboratory environment. 

    So, let’s get started.

    Introduction to JTR

    Image

    John the Ripper is a widely used, open-source password auditing and password recovery tool. Its main purpose is to test the strength of passwords by working with password hashes and other supported password-protected formats.

    Features and capabilities of John the Ripper

    Let's explore the remarkable features and capabilities of John the Ripper!

    • John the Ripper can handle various password hash formats, making it compatible with different systems and databases.
    • It offers multiple attack modes, including brute-force, dictionary, and hybrid attacks, providing versatile options for cracking passwords.
    • John the Ripper is optimized for speed, utilizing multiple CPU cores and GPUs to accelerate the password-cracking process.
    • Users can easily use their own wordlists and apply custom rules to generate password variations efficiently.
    • Being an open-source tool, John the Ripper benefits from continuous support and contributions from the vibrant cybersecurity community.

    Now we have a basic understanding of what John the Ripper is and why security professionals use it. But simply understanding the theory isn't enough.

    To properly understand how a security tool works, we need to use that knowledge in a practical environment.

    Supported Platforms and Environments

    If we talk about Supported Platforms and Environments, John the Ripper is compatible with various operating systems, including Windows, macOS, Linux, and other Unix-like systems. 

    Windows MacOs Linux FreeBsd OpenBsd

    It also works on different architectures, making it highly versatile and widely accessible.

    For this demonstration, we'll be using Kali Linux.

    Kali Linux is a Linux-based operating system specifically designed for penetration testing, security research, digital forensics, and other cybersecurity tasks. It comes with a large collection of security tools, including John the Ripper.

    If you're using Kali Linux, John is generally available by default, so we don't need to spend time installing it. For Windows users, I'll cover the installation and usage of John the Ripper in a separate article.

    Now, before we start our practical demonstration, let's understand a few important options that we'll be using:

    ┌──(kali㉿kali)-[~]
    └─$ john
    John the Ripper 1.9.0-jumbo-1+bleeding-aec1328d6c 2021-11-02 10:45:52 +0100 OMP [linux-gnu 64-bit x86_64 SSE2 AC]
    Copyright (c) 1996-2021 by Solar Designer and others
    Homepage: https://www.openwall.com/john/

    Usage: john [OPTIONS] [PASSWORD-FILES]

    Use --help to list available options.                                                                                                                                
    ┌──(kali㉿kali)-[~]
    └─$ 

    The basic command structure looks like this:

    john[OPTIONS][PASSWORD-FILES]

    Here:

    • john starts the program.
    • The OPTIONS tell John how we want it to perform the password-auditing task.
    • And PASSWORD-FILES represents the file containing the password hashes or other supported data that we want John to process.

    About the OPTIONS, John provides many different options for different situations. Run john with the help flag; it displays all options to use:

    ┌──(kali㉿kali)-[~]
    └─$ john --help
    John the Ripper 1.9.0-jumbo-1+bleeding-aec1328d6c 2021-11-02 10:45:52 +0100 OMP [linux-gnu 64-bit x86_64 SSE2 AC]
    Copyright (c) 1996-2021 by Solar Designer and others
    Homepage: https://www.openwall.com/john/

    Usage: john [OPTIONS] [PASSWORD-FILES]

    --help                     Print usage summary
    --single[=SECTION[,..]]    "Single crack" mode, using default or named rules
    --single=:rule[,..]        Same, using "immediate" rule(s)
    --single-seed=WORD[,WORD]  Add static seed word(s) for all salts in single mode
    --single-wordlist=FILE     *Short* wordlist with static seed words/morphemes
    --single-user-seed=FILE    Wordlist with seeds per username (user:password[s]
                               format)
    --single-pair-max=N        Override max. number of word pairs generated (6)
    --no-single-pair           Disable single word pair generation
    --[no-]single-retest-guess Override config for SingleRetestGuess
    --wordlist[=FILE] --stdin  Wordlist mode, read words from FILE or stdin
                      --pipe   like --stdin, but bulk reads, and allows rules
    --rules[=SECTION[,..]]     Enable word mangling rules (for wordlist or PRINCE
                               modes), using default or named rules
    --rules=:rule[;..]]        Same, using "immediate" rule(s)
    --rules-stack=SECTION[,..] Stacked rules, applied after regular rules or to
                               modes that otherwise don't support rules
    --rules-stack=:rule[;..]   Same, using "immediate" rule(s)
    --rules-skip-nop           Skip any NOP ":" rules (you already ran w/o rules)
    --loopback[=FILE]          Like --wordlist, but extract words from a .pot file
    --mem-file-size=SIZE       Size threshold for wordlist preload (default 2048 MB)
    --dupe-suppression         Suppress all dupes in wordlist (and force preload)
    --incremental[=MODE]       "Incremental" mode [using section MODE]
    --incremental-charcount=N  Override CharCount for incremental mode
    --external=MODE            External mode or word filter
    --mask[=MASK]              Mask mode using MASK (or default from john.conf)
    --markov[=OPTIONS]         "Markov" mode (see doc/MARKOV)
    --mkv-stats=FILE           "Markov" stats file
    --prince[=FILE]            PRINCE mode, read words from FILE
    --prince-loopback[=FILE]   Fetch words from a .pot file
    --prince-elem-cnt-min=N    Minimum number of elements per chain (1)
    --prince-elem-cnt-max=[-]N Maximum number of elements per chain (negative N is
                               relative to word length) (8)
    --prince-skip=N            Initial skip
    --prince-limit=N           Limit number of candidates generated
    --prince-wl-dist-len       Calculate length distribution from wordlist
    --prince-wl-max=N          Load only N words from input wordlist
    --prince-case-permute      Permute case of first letter
    --prince-mmap              Memory-map infile (not available with case permute)
    --prince-keyspace          Just show total keyspace that would be produced
                               (disregarding skip and limit)
    --subsets[=CHARSET]        "Subsets" mode (see doc/SUBSETS)
    --subsets-required=N       The N first characters of "subsets" charset are
                               the "required set"
    --subsets-min-diff=N       Minimum unique characters in subset
    --subsets-max-diff=[-]N    Maximum unique characters in subset (negative N is
                               relative to word length)
    --subsets-prefer-short     Prefer shorter candidates over smaller subsets
    --subsets-prefer-small     Prefer smaller subsets over shorter candidates
    --make-charset=FILE        Make a charset, FILE will be overwritten
    --stdout[=LENGTH]          Just output candidate passwords [cut at LENGTH]
    --session=NAME             Give a new session the NAME
    --status[=NAME]            Print status of a session [called NAME]
    --restore[=NAME]           Restore an interrupted session [called NAME]
    --[no-]crack-status        Emit a status line whenever a password is cracked
    --progress-every=N         Emit a status line every N seconds
    --show[=left]              Show cracked passwords [if =left, then uncracked]
    --show=formats             Show information about hashes in a file (JSON)
    --show=invalid             Show lines that are not valid for selected format(s)
    --test[=TIME]              Run tests and benchmarks for TIME seconds each
                               (if TIME is explicitly 0, test w/o benchmark)
    --stress-test[=TIME]       Loop self tests forever
    --test-full=LEVEL          Run more thorough self-tests
    --no-mask                  Used with --test for alternate benchmark w/o mask
    --skip-self-tests          Skip self tests
    --users=[-]LOGIN|UID[,..]  [Do not] load this (these) user(s) only
    --groups=[-]GID[,..]       Load users [not] of this (these) group(s) only
    --shells=[-]SHELL[,..]     Load users with[out] this (these) shell(s) only
    --salts=[-]COUNT[:MAX]     Load salts with[out] COUNT [to MAX] hashes, or
    --salts=#M[-N]             Load M [to N] most populated salts
    --costs=[-]C[:M][,...]     Load salts with[out] cost value Cn [to Mn]. For
                               tunable cost parameters, see doc/OPTIONS
    --fork=N                   Fork N processes
    --node=MIN[-MAX]/TOTAL     This node's number range out of TOTAL count
    --save-memory=LEVEL        Enable memory saving, at LEVEL 1..3
    --log-stderr               Log to screen instead of file
    --verbosity=N              Change verbosity (1-5 or 6 for debug, default 3)
    --no-log                   Disables creation and writing to john.log file
    --bare-always-valid=Y      Treat bare hashes as valid (Y/N)
    --catch-up=NAME            Catch up with existing (paused) session NAME
    --config=FILE              Use FILE instead of john.conf or john.ini
    --encoding=NAME            Input encoding (eg. UTF-8, ISO-8859-1). See also
                               doc/ENCODINGS.
    --input-encoding=NAME      Input encoding (alias for --encoding)
    --internal-codepage=NAME   Codepage used in rules/masks (see doc/ENCODINGS)
    --target-encoding=NAME     Output encoding (used by format)
    --force-tty                Set up terminal for reading keystrokes even if we're
                               not the foreground process
    --field-separator-char=C   Use 'C' instead of the ':' in input and pot files
    --[no-]keep-guessing       Try finding plaintext collisions
    --list=WHAT                List capabilities, see --list=help or doc/OPTIONS
    --length=N                 Shortcut for --min-len=N --max-len=N
    --min-length=N             Request a minimum candidate length in bytes
    --max-length=N             Request a maximum candidate length in bytes
    --max-candidates=[-]N      Gracefully exit after this many candidates tried.
                               (if negative, reset count on each crack)
    --max-run-time=[-]N        Gracefully exit after this many seconds (if negative,
                               reset timer on each crack)
    --mkpc=N                   Request a lower max. keys per crypt
    --no-loader-dupecheck      Disable the dupe checking when loading hashes
    --pot=NAME                 Pot file to use
    --regen-lost-salts=N       Brute force unknown salts (see doc/OPTIONS)
    --reject-printable         Reject printable binaries
    --tune=HOW                 Tuning options (auto/report/N)
    --subformat=FORMAT         Pick a benchmark format for --format=crypt
    --format=[NAME|CLASS][,..] Force hash of type NAME. The supported formats can
                               be seen with --list=formats and --list=subformats.
                               See also doc/OPTIONS for more advanced selection of
                               format(s), including using classes and wildcards.
    ┌──(kali㉿kali)-[~]
    └─$ 

    However, I am not going through every single option one by one, it will take time, there is a chance it looks more theoretic. The best way to understand these options is to see them in action.

    So, instead of spending too much time on theory, we'll move into our lab and learn the important commands through practical examples.

    Let's start with our Practical demonstration. 

    Practical Demonstration

    So, what are we going to do here?

    • First, we'll create a password hash ourselves.
    • Then, we'll use John the Ripper to test password candidates against that hash and see whether the original password can be recovered.

    Everything in this demonstration is created inside our own lab environment. 

    We'll use the mkdir command to create a new directory, and then we change the directory to it:

    ┌──(kali㉿kali)-[~]
    └─$ mkdir john-lab
    ┌──(kali㉿kali)-[~]
    └─$ cd john-lab
    ┌──(kali㉿kali)-[~/john-lab]
    └─$ 

    We are now inside our laboratory directory.

    Next, we'll create a test MD5 hash.

    For this demonstration, I'll use a simple test password. We can generate its MD5 hash by using the md5sum command-line tool:

    ┌──(kali㉿kali)-[~/john-lab]
    └─$ echo -n 'password' | md5sum
    5f4dcc3b5aa765d61d8327deb882cf99 -

    ┌──(kali㉿kali)-[~/john-lab]
    └─$ 

    Here, 

    • the echo -n command outputs the password without adding a new line.
    • The pipe symbol, or | sends that output directly to md5sum. 
    • The md5sum command then calculates the MD5 hash of that text.

    The result is the hash value that we'll use for our demonstration. Now, let's save that hash into a file called hash.txt.

    We can use the echo command again, followed by the hash, and then use the redirection operator to write it into the file. 

    ┌──(kali㉿kali)-[~/john-lab]
    └─$ echo '5f4dcc3b5aa765d61d8327deb882cf99' > hash.txt
    ┌──(kali㉿kali)-[~/john-lab]
    └─$ ls
    hash.txt
    ┌──(kali㉿kali)-[~/john-lab]
    └─$ 

    As you can see, the hash has been stored inside hash.txt. 

    Now we have our test hash, so let's see what happens when we give it to John. For the first attempt, we won't specify any additional options.

    ┌──(kali㉿kali)-[~/john-lab]
    └─$ john hash.txt
    Warning: 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 instead
    Warning: detected hash type "LM", but the string is also recognized as "mdc2"
    Use the-format-mdc2" option to force loading these as that type instead
    Warning: detected hash type "LM", but the string is also recognized as "mscash"
    Use the-format-mscash" option to force loading these as that type instead
    Warning: detected hash type "LM", but the string is also recognized as "mscash2" Use the-format mscash2" option to force loading these as that type instead
    Warning: detected hash type "LM", but the string is also recognized as "NT"
    Use the-format-NT" option to force loading these as that type instead
    Warning: detected hash type "LM", but the string is also recognized as "Raw-MD4" Use the format Raw-MD4" option to force loading these as that type instead
    Warning: detected hash type "LM", but the string is also recognized as "Raw-MD5" Use the-format Raw-MD5" option to force loading these as that type instead
    Warning: detected hash type "LM", but the string is also recognized as "Raw-MD5u
    Use the format Raw-MD5u" option to force loading these as that type instead
    Warning: detected hash type "LM", but the string is also recognized as "Raw-SHA1-AxCrypt"
    Use the format Raw-SHA1-AxCrypt option to force loading these as that type instead Warning: detected hash type "LM", but the string is also recognized as "ripemd-128
    Use the-format-ripemd-128" option to force loading these as that type instead
    Warning: detected hash type "LM", but the string is also recognized as "Snefru-128"
    Use the format Snefru-128" option to force loading these as that type instead
    Warning: detected hash type "LM", but the string is also recognized as "ZipMonster"
    Use the-format-ZipMonster" option to force loading these as that type instead
    Using default input encoding: UTF-8
    Using default target encoding: CP850
    Loaded 2 password hashes with no different salts (LM [DES 256/256 AVX2])
    Warning: poor OpenMP scalability for this hash type, consider fork-2
    Will run 2 OpenMP threads.
    Proceeding with single, rules: Single
    Press 'q' or Ctrl-C to abort, almost any other key for status
    Almost done: Processing the remaining buffered candidate passwords, if any.
    Proceeding with wordlist:/usr/share/john/password.lst
    Proceeding with incremental:LM_ASCII

    John will try to identify the hash format automatically and start using its configured default settings. Depending on the John build and the input, you may see a warning or a message indicating that the hash format was not identified as expected.

    This is a good example of why understanding the hash format is important.

    In our case, we already know that the hash we created is an MD5 hash.

    So instead of relying on automatic detection, we can explicitly tell John which format to use. We'll use the --format option for this.

    • Here, John knows that the value should be treated as a raw MD5 hash. If the correct password is present in the candidates John is testing, it can find a matching value.

    When that happens, John reports the recovered password.

    ┌──(kali㉿kali)-[~/john-lab]
    └─$ john --format=Raw-MD5 hash.txt
    Using default input encoding: UTF-8
    Loaded 1 password hash (Raw-MD5 [MD5 256/256 AVX2 8×3])
    Warning: no OpenMP support for this hash type, consider -fork-2
    Proceeding with single, rules: Single
    Press 'q' or Ctrl-C to abort, almost any other key for status
    Almost done: Processing the remaining buffered candidate passwords, if any.
    Proceeding with wordlist:/usr/share/john/password.lst
    password (?)
    1g 0:00:00:00 DONE 2/3 (2026-09-21 14:17) 2.500g/s 960.0p/s 960.0c/s 960.0C/s 123456.. larry
    Use the "--show --format-Raw-MD5" options to display all of the cracked passwords reliably
    Session completed.
    ┌──(kali㉿kali)-[~/john-lab]
    └─$ 

    So, what exactly happened here?

    • John did not decrypt the MD5 hash.
    • Instead, it tested password candidates, calculated their MD5 values, and compared those results with our target hash.
    • When one of the candidates produced the same hash, John reported a successful match.

    Now let's consider a different situation. 

    What happens if the password is more complicated? 

    What if the password is not included in the candidates that John is currently using? 

    This is where a wordlist becomes useful.

    We can provide our own wordlist by using the --wordlist option. 

    Let's create a second test password and generate its MD5 hash using the same method. And we'll then append that new hash to our existing file.

    ┌──(kali㉿kali)-[~/john-lab]
    └─$ echo 'Cybersecmastery' | md5sum
    593ed296028cd517e7e68b5f534cc8c5 -
    ┌──(kali㉿kali)-[~/john-lab]
    └─$

    To add new content without replacing the existing data, we can use the >> redirection operator. After that, we'll use cat to verify whether both hashes are present or not.

    ┌──(kali㉿kali)-[~/john-lab]
    └─$ echo '593ed296028cd517e7e68b5f534cc8c5' >> hash.txt
    ┌──(kali㉿kali)-[~/john-lab]
    └─$ cat hash.txt
    5f4dcc3b5aa765d61d8327deb882cf99
    593ed296028cd517e7e68b5f534cc8c5
    ┌──(kali㉿kali)-[~/john-lab]
    └─$

    Now, let's run John again with our specified format.

    ┌──(kali㉿kali)-[~/john-lab]
    └─$ john --format=Raw-MD5 hash.txt
    Using default input encoding: UTF-8
    Loaded 2 password hashes with no different salts (Raw-MD5 [MD5 256/256 AVX2 8×3])
    Remaining 1 password hash
    Warning: no OpenMP support for this hash type, consider fork+2
    Proceeding with single, rules: Single
    Press 'q' or Ctrl-C to abort, almost any other key for status
    Almost done: Processing the remaining buffered candidate passwords, if any.
    Proceeding with wordlist:/usr/share/john/password.lst
    Proceeding with incremental: ASCII
    0g 0:00:00:26 3/3 0g/s 6312Kp/s 6312Kc/s 6312KC/s vwa..marl131
    Session aborted
    ┌──(kali㉿kali)-[~/john-lab]
    └─$

    You may notice that John does not report a new password. That can happen for several reasons.

    • One possibility is that the password isn't in the candidates being tested.
    • Another possibility is that John has already processed that hash and stored the result.

    So, let's provide our own wordlist.

    A common example on Kali Linux is the rockyou.txt wordlist.

    We can use it with rockyou.txt. The rockyou.txt file contains a large collection of password candidates. John will process those candidates and compare them against the hashes in our file.

    ┌──(kali㉿kali)-[~/john-lab]
    └─$ john --format=Raw-MD5 --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
    Using default input encoding: UTF-8
    Loaded 2 password hashes with no different salts (Raw-MD5 [MD5 256/256 AVX2 8×3])
    Remaining 1 password hash
    Warning: no OpenMP support for this hash type, consider fork-2 Press q or Ctrl-C to abort, almost any other key for status
    0g 0:00:00:03 DONE (2026-09-21 14:20) 0g/s 4672Kp/s 4672Kc/s 4672KC/s fuckyooh21.. 7; Vamos!
    Session completed.
    ┌──(kali㉿kali)-[~/john-lab]
    └─$

    But in our demonstration, the password we selected isn't in that wordlist. In that case, John is not able to recover it. This brings us to another useful technique.

    We can create our own small wordlist containing the password candidates that we want to test.

    Let's create a file called passwords.txt. 

    ┌──(kali㉿kali)-[~/john-lab]
    └─$ cat > passwords.txt << 'EOF'
    heredoc> password
    heredoc> admin
    heredoc> 123456
    heredoc> CyberSecurity
    heredoc> Cybersecmastery
    heredoc> EOF
    ┌──(kali㉿kali)-[~/john-lab]
    └─$

    In real security assessments, candidate lists can be created from many different sources, including password policies, previously known information, or password-generation and transformation techniques.

    The important security lesson is that people often choose passwords based on information that is easy to remember. That can include names, dates, favorite words, phone numbers, or other predictable patterns.

    Now our wordlist is ready. Let's use it with John to test the candidates from our custom wordlist against the hashes.

    ┌──(kali㉿kali)-[~/john-lab]
    └─$ john --format=Raw-MD5 --wordlist=passwords.txt hash.txt
    Using default input encoding: UTF-8
    Loaded 2 password hash with no different salts (Raw-MD5 [MD5 256/256 AVX2 8×3])
    Remaining 1 password hash
    Warning: no OpenMP support for this hash type, consider --fork-2
    Press 'q' or Ctrl-C to abort, almost any other key for status
    Warning: Only 5 candidates left, minimum 24 needed for performance.
    Cybersecmastery (?)
    1g 0:00:00:00 DONE (2026-09-21 14:21) 2.380g/s 11.90p/s 11.90c/s 11.90C/s 123456.. Cybersecmastery
    Use the "--show --format-Raw-MD5" options to display all of the cracked passwords reliably
    Session completed.
    ┌──(kali㉿kali)-[~/john-lab]
    └─$ 

    As you can see, the password has been recovered. 

    Notice something interesting here.

    Our hash.txt file contains two hashes. However, during the previous run, John reported only one newly recovered password.

    So, what happened to the other hash?

    The answer is that John keeps track of passwords it has already recovered. It stores these results in a password database, commonly known as the pot file.

    So, when John sees a hash that it has already successfully recovered, it doesn't need to perform the same password testing again.

    This is why you may see fewer new results, even though multiple hashes are present in the file.

    Instead, we can use the --show option. The --show option displays passwords that John has already recovered for the hashes in the file. 

    ┌──(kali㉿kali)-[~/john-lab]
    └─$  john --format=Raw-MD5 --show hash.txt
    ?:password
    ?:Cybersecmastery

    2 password hashes cracked, 0 left
    ┌──(kali㉿kali)-[~/john-lab]
    └─$ 

    This is usually the better way to review previously recovered results. If you remove or reset John's password database, those results will no longer be available to John, and he may need to perform the work again.

    The exact location of the pot file depends on the John installation and configuration.

    Let me explain this using our previous example:

    Now, when we run the john command with our wordlist and hash file, John displays a message like this:

    “Loaded 2 password hashes with no different salts. No password hashes left to crack.”

    So, what does this message mean?

    It means John has already processed both hashes and has recovered their corresponding passwords. Because those results are already stored in John's pot file, there are no remaining hashes for John to process.

    So, what happens if we delete the pot file?

    Let's find out.

    First, we need to locate John's pot file.

    On a typical Linux installation, John's configuration and data are stored under a hidden directory within the .john directory inside the current user's home directory. 

    The tilde (|) symbol is a shortcut that represents the current user's home directory. 

    Run ls command along with the path to the .john directory.

    ┌──(kali㉿kali)-[~/john-lab]
    └─$  ls ~/.john/
    john.logjohn.pot
    ┌──(kali㉿kali)-[~/john-lab]
    └─$ 

    Here, you see files such as john.log and john.pot.

    The john.pot file is particularly important for this demonstration because it stores passwords that John has already recovered. Now, let's remove the john.pot file. This removes John's stored recovery history for the passwords it has already found.

    ┌──(kali㉿kali)-[~/john-lab]
    └─$  rm ~/.john/john.pot
    ┌──(kali㉿kali)-[~/john-lab]
    └─$ 

    Now, let's run the same John command again. This time, John no longer has the previous recovery results stored in its pot file.

    So, it processes the hashes again. As you can see, the two passwords are now reported again. This demonstrates why John keeps a pot file: it prevents the tool from repeating work that it has already completed.

    Now let's move to another important capability.

    John the Ripper is not limited to simple hash files. It can also work with password-protected files and other supported formats.

    John includes a collection of utilities whose names commonly end with *2john. These utilities convert password-protected files into a representation that John can process.

    Let's see this with a ZIP archive.

    First, we'll create a simple text file.

    ┌──(kali㉿kali)-[~/john-lab]
    └─$  echo "This is a password-protected laboratory file -- Cybersecmastery' > secret.txt

    ┌──(kali㉿kali)-[~/john-lab]
    └─$

    The secret.txt file has now been created.

    Next, we'll create a password-protected ZIP archive. We'll use the zip command with the -e option.

    ┌──(kali㉿kali)-[~/john-lab]
    └─$ zip -e protected.zip secret.txt
    Enter password:
    Verify password:
    adding: secret.txt (stored 0%)
    ┌──(kali㉿kali)-[~/john-lab]
    └─$ ls
    hash.txt passwords.txt protected.zip secret.txt

    ┌──(kali㉿kali)-[~/john-lab]
    └─$

    The command asks us to enter a password for the archive.

    After we provide the password, the protected.zip file is created.

    Let's verify it.

    Now we have our password-protected ZIP archive.

    If we try to extract it using the normal unzip command, it asks for the password.

    ┌──(kali㉿kali)-[~/john-lab]
    └─$ unzip protected.zip
    Archive: protected.zip
    [protected.zip] secret.zip password: 
    skipping: secret.txtincorrect password
    ┌──(kali㉿kali)-[~/john-lab]
    └─$

    Without the correct password, we cannot extract the protected contents. But John the Ripper cannot simply take every protected file directly as input.

    This is where a format-specific*2john utility comes into the workflow.

    For ZIP archives, the utility is called zip2john. Its job is to extract the password-verification data from the ZIP archive and convert it into a format that John can process.

    Let's first check whether the zip2john utility can be run directly from the terminal.

    We can use the command:

    ┌──(kali㉿kali)-[~/john-lab]
    └─$ which zip2john
    /usr/sbin/zip2john

    ┌──(kali㉿kali)-[~/john-lab]
    └─$ 

     As you can see, the utility is available in the system's executable path, which means we can run it directly from the terminal without specifying the full path.

    Now, we'll use it against our protected archive. Let's use it zip2john with our protected ZIP file.

    Here, 

    • protected.zip is our password-protected ZIP archive.
    • The greater-than (>) symbol redirects the output from zip2john into a file called protected.hash.

    When we run the command, zip2john extracts the password-verification data from the ZIP archive and writes that data into protected.hash.

    ┌──(kali㉿kali)-[~/john-lab]
    └─$ zip2john protected.zip > protected.hash
    ver 1.0 efh 5455 efh 7875 protected.zip/secret.txt PKZIP Encr: 2b chk, TS_chk, cmplen-73, decmplen-61, crc-60098CA7 ts=7454 cs-745
    4 type-0

    ┌──(kali㉿kali)-[~/john-lab]
    └─$

    The output is redirected into a new file called protected.hash. Let's inspect that file.

    ┌──(kali㉿kali)-[~/john-lab]
    └─$ cat protected.hash
    protected.zip/secret.txt:Spkzip$1*2*2*0*49*30*60d98ca7+0*44*0*49*7454-12c3ee50b5dbcbe3ac80d85b5778a59b5c3bb80053ee6c0476129e3c2309 d3cdfcfe72f61e412c818d2b051608a83d2caaeb86c67efed22b591bb4e908c080c03bb4336d414f473080+$/pkzip$:secret.txt:protected.zip::protecte
    d.zip
    ┌──(kali㉿kali)-[~/john-lab]
    └─$

    As you can see, the file now contains the extracted verification data in a format that John understands.

    Now, we can provide that file to John.

    ┌──(kali㉿kali)-[~/john-lab]
    └─$ john --wordlist=passwords.txt protected.hash
    Using default input encoding: UTF-8
    Loaded 1 password hash (PKZIP [32/64])
    Will run 2 OpenMP threads
    Press 'q' or Ctrl-C to abort, almost any other key for status
    Cybersecmastery(protected.zip/secret.txt)
    1g 0:00:00:00 DONE (2029-09-21 14:39) 33.33g/s 166.6p/s 166.6c/s 166.6C/s password.. Cybersecmastery
    Use the show" option to display all of the cracked passwords reliably
    Session completed.
    ┌──(kali㉿kali)-[~/john-lab]
    └─$

    If the correct password is present in our wordlist, John can identify it.

    And there we have it. We now have the password that can be used to extract the password-protected zip file.

    We've now demonstrated the complete workflow.

    • First, we created a password-protected file.
    • Then, we converted the file into a format that John could process.
    • Finally, John tested the password candidates and recovered the password from our controlled laboratory example.

    There are many other *2john utilities for different file formats and password-protected data.

    The overall workflow is generally similar:

    • Convert the supported file into a John-readable format.
    • Then provide that output to John for password auditing.

    We're not going to cover every supported format in this video, because the basic concept remains the same.

    You can experiment with the other utilities safely in your own laboratory environment. And that's where we'll stop for this lesson.

    Community Q&A