July 1, 2026

Archive and Zip Password Cracking for CTF

Crack password-protected zip, rar, and 7z archives in CTF. zip2john plus john and hashcat, fcrackzip wordlists, and the bkcrack known-plaintext attack on ZipCrypto.

A password-protected archive: what do I run first?

You unzipped the challenge bundle and one file refuses to open: secret.zip wants a password you do not have. The fast path is almost always the same three moves. Turn the archive into a crackable hash, throw rockyou.txt at it, and read the password off the cracked line. Here is the whole loop for a zip, top to bottom:

# 1) extract the hash from the archive
zip2john secret.zip > hash.txt
# 2) run a wordlist against it
john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
# 3) print the cracked password
john --show hash.txt
# 4) open the archive with the recovered password
unzip -P <password> secret.zip

That is the 80 percent case. The rest of this guide is the other 20 percent: rar and 7z archives, when to reach for hashcat instead of john, fcrackzip as a single-command shortcut, and the one situation where a wordlist is the wrong tool entirely. That last case (a known file already inside the zip) is the known-plaintext attack with bkcrack, and it recovers the contents even when the password is long and random.

Note: If rockyou.txt is missing, it usually ships gzipped on Kali at /usr/share/wordlists/rockyou.txt.gz. Decompress it once with gunzip /usr/share/wordlists/rockyou.txt.gz and every tool below can read it.

What is the general workflow for any crackable archive?

Zip, rar, and 7z all follow the same three-stage shape. The only thing that changes is the helper that extracts the hash. Internalize the stages and the specific archive format stops mattering.

You almost never crack the archive directly. You crack a hash you extracted from it, then use the password the hash gave up.
  1. Identify. Confirm the format and the encryption scheme. A zip can use weak legacy ZipCrypto or strong AES; the difference decides your whole approach.
  2. Extract a hash. Run zip2john, rar2john, or 7z2john to pull a john-format hash string out of the archive header.
  3. Crack. Feed that hash to john or hashcat with a wordlist, then a mask if the wordlist misses.

The known-plaintext attack in the bkcrack section is the exception that skips the hash entirely. Keep it in your back pocket for the moment a wordlist clearly will not land.

How do I tell what kind of archive (and encryption) I have?

Do not trust the file extension. A .zip might be a renamed 7z, and a zip can encrypt with two completely different ciphers. Start with file for the container format, then look at the encryption with the archive's own tooling.

$ file secret.zip
secret.zip: Zip archive data, at least v2.0 to extract
# list entries and see whether encryption is ZipCrypto or AES
$ 7z l -slt secret.zip | grep -E 'Name|Method|Encrypted'
Encrypted = +
Method = ZipCrypto Deflate # weak legacy cipher -> bkcrack is possible
# Method = AES-256 Deflate # strong -> wordlist or mask only

The Method line is the fork in the road. ZipCrypto is the original 1990s PKZIP stream cipher and it is broken: if you know (or can guess) any file that is inside the archive, bkcrack recovers the keys regardless of password length. AES-128 or AES-256 has no such shortcut, so you are limited to guessing the password with a wordlist or mask.

Tip: When the contents look like an image, archive, or other format with a known header, note the Method. If it says ZipCrypto you may not need to crack the password at all. Jump to the bkcrack section.

How do I extract a crackable hash from the archive?

The *2john family ships with John the Ripper. Each tool reads the archive header and prints a single hash line that john and (after a small edit) hashcat understand. Pick the one that matches your format:

zip2john secret.zip > hash.txt # zip (ZipCrypto and AES)
rar2john secret.rar > hash.txt # rar3 and rar5
7z2john secret.7z > hash.txt # 7-Zip (7z2john.pl on some distros)
# the line looks like this for an AES zip:
# secret.zip:$zip2$*0*3*0*<...long hex...>*$/zip2$:...:secret.zip

On many systems 7z2john is a Perl script named 7z2john.pl and may need the Compress::Raw::Lzma module installed. If zip2john is not on your PATH, it lives next to the John binary, often at /usr/sbin/zip2john or inside the John run/ directory.

Warning: zip2john emits a different hash mode for ZipCrypto ($pkzip$) than for AES ($zip2$). That is expected. The mode string is exactly what tells john and hashcat which algorithm to run, so do not hand-edit it.

The hash file may contain the filename and other metadata after the hash. john handles the full line as-is. For hashcat you usually strip everything down to just the hash portion, covered next.

How do I crack the hash with John the Ripper?

John auto-detects the format from the hash string, so the basic invocation is the same for zip, rar, and 7z. Point it at a wordlist and let it run.

# straight wordlist attack
john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
# wordlist plus john's built-in mangling rules (l33t, appended digits, etc.)
john --wordlist=/usr/share/wordlists/rockyou.txt --rules=Jumbo hash.txt
# show what was cracked (reads john.pot)
john --show hash.txt
# resume an interrupted session
john --restore

The --rules flag is the highest-value option here. It transforms each wordlist entry (capitalizing, appending years, swapping a for @) and turns a plain dictionary into millions of realistic variants. For a CTF password like Summer2024! the base word is in rockyou but the exact string is not, and the rules are what bridge the gap.

Tip: If john finishes instantly and says nothing cracked, it may have silently loaded a different format than you expected. Add --format=ZIP (or RAR, 7z, PKZIP) to force it, and run john --list=formats to see the exact names your build supports.

Once you have the password, never forget the final step. The flag is inside the archive, not in the password itself. Open it: unzip -P 'Summer2024!' secret.zip or 7z x -p'Summer2024!' secret.7z.

When should I use hashcat instead, and what are the modes?

Reach for hashcat when you have a GPU. It is dramatically faster than john on the same hardware for these formats, which matters once you move past a plain wordlist into rules and masks. The cost is that you must tell it the hash mode by number and feed it a clean hash.

13600 WinZip (AES)
17200 PKZIP (compressed, legacy ZipCrypto)
17210 PKZIP (uncompressed)
23700 RAR3-p (compressed)
23800 RAR3-p (uncompressed)
13000 RAR5
11600 7-Zip

Trim the zip2john line down to just the $zip2$...$/zip2$ token (drop the leading filename and trailing metadata), then run the wordlist:

# AES zip with rockyou and the best64 rule set
hashcat -m 13600 -a 0 hash.txt /usr/share/wordlists/rockyou.txt -r rules/best64.rule
# 7-Zip, straight wordlist
hashcat -m 11600 -a 0 hash.txt /usr/share/wordlists/rockyou.txt
# show the cracked result
hashcat -m 13600 hash.txt --show

The attack-mode flag -a 0 is a straight wordlist, -a 3 is a brute-force mask, and -a 6 is a hybrid (wordlist plus appended mask). Hybrid mode is excellent for CTF passwords shaped like a dictionary word followed by a few digits or symbols.

Note: 7-Zip (-m 11600) and WinZip AES (-m 13600) use a slow key derivation function on purpose, so guess rates are low (often only thousands per second on a laptop GPU). That is fine for a short wordlist but it means a deep brute force is rarely realistic. If rockyou plus rules misses, rethink before you brute.

Is there a one-command shortcut for zip files?

For zip specifically, fcrackzip skips the hash-extraction step. It reads the archive directly and runs either a wordlist or a brute-force charset against it. For a quick wordlist pass it is the fastest thing to type:

# dictionary attack straight against the zip
fcrackzip -u -D -p /usr/share/wordlists/rockyou.txt secret.zip
# -u actually try to unzip with each candidate (filters false positives)
# -D use a dictionary
# -p the wordlist (or, with -b, the starting password)

The -u flag matters: without it, fcrackzip reports checksum matches that may be false positives, but with it the tool actually attempts the decryption and only reports a password that genuinely works. For a short brute force over a known charset:

# brute force: lowercase letters, length 1 to 6
fcrackzip -u -b -c 'a' -l 1-6 secret.zip
# brute force: lowercase + digits, length 4 to 6
fcrackzip -u -b -c 'aA1' -l 4-6 secret.zip
# -b brute force mode
# -c 'aA1' charset: a=lower, A=upper, 1=digits, !=symbols
# -l 4-6 password length range
Warning: fcrackzip is CPU-only and works against ZipCrypto-style zips. It does not handle AES-encrypted zips or rar and 7z archives. For those, go back to the *2john plus john or hashcat path.

The password is long and random: can I still get in?

Sometimes the password is not crackable by any wordlist, and that is the intended path. If the zip uses legacy ZipCrypto (check the Method line from the identify step) and you know any 12 contiguous bytes of any file inside it, you can recover the internal keys and decrypt the whole archive without ever learning the password. This is the Biham and Kocher known-plaintext attack, implemented in bkcrack.

ZipCrypto is not a password problem. With a sliver of known plaintext it is a key-recovery problem, and the password becomes irrelevant.

Where does known plaintext come from in a CTF? Files have predictable headers. A PNG always starts with the same 8 magic bytes, a PDF with %PDF-1., a gzip with 0x1f 0x8b. If you can guess the start of any entry, you have enough. Even better: if the same file exists unencrypted somewhere else (a sample, a template, or a second archive), you have the entire plaintext.

# list entries; note the name and the ZipCrypto method
bkcrack -L secret.zip
# you have the full known file 'logo.png' in plaintext
bkcrack -C secret.zip -c flag/logo.png -P known.zip -p logo.png
# or supply known plaintext by byte offset (here a known magic header)
bkcrack -C secret.zip -c flag/logo.png -p header.bin -o 0
# -C the encrypted archive
# -c the encrypted entry inside it you are targeting
# -p the known plaintext (a file, or bytes via an offset)

A successful run prints three 32-bit internal keys. Use them to decrypt every entry, or to set a brand-new password so a normal unzip can open the archive:

# bkcrack reports: Keys: 12345678 9abcdef0 deadbeef
# decrypt a single entry to a readable file
bkcrack -C secret.zip -k 12345678 9abcdef0 deadbeef -d flag.png
# or rewrite the whole archive with a new password 'pwned'
bkcrack -C secret.zip -k 12345678 9abcdef0 deadbeef -U cracked.zip pwned
unzip -P pwned cracked.zip
Key insight: bkcrack needs at least 12 bytes of known plaintext, and more is better (it makes the attack faster and the result certain). The attack is entirely independent of password length: a 40-character random password falls just as fast as a 4-character one, because you are attacking the cipher keystream, not the password. This only works on ZipCrypto, never on AES.

Wordlists missed. How do I structure a mask or brute attack?

When the password is not in rockyou and not derivable by rules, you move to a mask: a per-position charset that brute-forces a known shape. The art is using everything you know about the password to shrink the keyspace. A challenge that hints "the password is the year plus a word" is a mask, not a blind brute force.

# hashcat mask placeholders
?l = abcdefghijklmnopqrstuvwxyz
?u = ABCDEFGHIJKLMNOPQRSTUVWXYZ
?d = 0123456789
?s = special characters
?a = ?l?u?d?s (everything)
# example: exactly 8 lowercase letters
hashcat -m 13600 -a 3 hash.txt ?l?l?l?l?l?l?l?l
# example: a 6-char word then 2 digits (e.g. 'secret24')
hashcat -m 13600 -a 3 hash.txt ?l?l?l?l?l?l?d?d
# hybrid: every rockyou word with 0-99 appended
hashcat -m 13600 -a 6 hash.txt /usr/share/wordlists/rockyou.txt ?d?d

John expresses the same idea with incremental mode and mask mode:

# john mask: 4 to 6 digit numeric PIN
john --mask='?d?d?d?d?d?d' --min-length=4 hash.txt
# john incremental (its own optimized brute force)
john --incremental=Digits hash.txt
Tip: Every character you can pin down divides the work. A full ?a at each of 8 positions is 958 candidates and hopeless on AES key derivation. Knowing the password is all lowercase drops it to 268, and knowing the first letter is capitalized and the rest are lowercase drops it again. Read the challenge text for the shape before you launch anything.

How do I know when cracking is a rabbit hole?

The single biggest time-sink in archive challenges is brute-forcing a password that was never meant to be brute-forced. CTF authors expect rockyou plus rules to land in seconds, or they expect a different intended path entirely. If a basic wordlist run does not crack within a few minutes, stop and reconsider before you queue a multi-hour brute.

Signs you are off the intended path:

  • The archive uses AES and rockyou plus best64 missed. A deep AES brute is almost never the intended solution because the key derivation is deliberately slow. Look for the password elsewhere in the challenge.
  • The archive is ZipCrypto and you have known plaintext available but keep grinding the password anyway. Switch to bkcrack; that is the point.
  • You have not checked for the password in the obvious places: file metadata (exiftool), strings in the bundle (strings -n 8), comments in the zip itself (unzip -z secret.zip), or a steganography layer in an accompanying image.
  • The hash is the wrong type. Double-check with an on-site hash identifier before you spend GPU hours on the wrong mode.
Warning: A password-protected archive is often nested inside another puzzle: the password is the flag from an earlier stage, a string hidden in an image, or a value you compute. If cracking stalls, the password probably lives somewhere you have not looked, not at the far end of a keyspace.

Where can I practice the cracking workflow?

The hash-to-wordlist loop is the same muscle whether the target is an archive or a raw hash. These two picoCTF challenges drill it directly:

  • picoCTF 2025 hashcrack hands you raw hashes and asks you to crack them. It is the cleanest introduction to identifying a hash type and running it against a wordlist, which is exactly stage three of the archive workflow.
  • picoCTF 2021 crackme-py is a reverse-the-logic variant that teaches you to read how a password or key is checked, the same instinct you use when deciding whether an archive password is crackable or computed.

For the surrounding skills (identifying hashes, building wordlists, and the wider cracking toolkit) read the Hash Cracking for CTF post, and for the file, strings, and unzip fundamentals that surround every forensics challenge see the Linux CLI for CTF guide.

Quick reference

Decision order for any locked archive

  1. file secret.zip and 7z l -slt secret.zip. Note the format and whether the method is ZipCrypto or AES.
  2. ZipCrypto plus any known file inside? Use bkcrack and skip the password.
  3. Otherwise extract the hash: zip2john / rar2john / 7z2john.
  4. Crack with rockyou plus rules in john or hashcat.
  5. Still nothing? Shape a mask from the challenge hints. Do not blind-brute AES.
  6. Open the archive with the recovered password and read the flag.

Command cheat sheet

# extract hash
zip2john secret.zip > hash.txt # or rar2john / 7z2john
# crack with john
john --wordlist=/usr/share/wordlists/rockyou.txt --rules=Jumbo hash.txt
john --show hash.txt
# crack with hashcat (13600 zip-AES, 11600 7z, 13000 rar5, 17200 zipcrypto)
hashcat -m 13600 -a 0 hash.txt rockyou.txt -r rules/best64.rule
# fcrackzip direct dictionary
fcrackzip -u -D -p /usr/share/wordlists/rockyou.txt secret.zip
# bkcrack known-plaintext on ZipCrypto
bkcrack -C secret.zip -c file.png -p known.png
bkcrack -C secret.zip -k K0 K1 K2 -U cracked.zip newpass
# open the archive
unzip -P <password> secret.zip # or 7z x -p<password> secret.7z

Authoritative references worth bookmarking: John the Ripper, hashcat, fcrackzip, and bkcrack.

Identify the cipher first: a ZipCrypto archive with known plaintext is a 30-second bkcrack job, while everything else is just a hash you feed to rockyou.