Fundamentals 5 min read

Cracking Encrypted ZIP Files with Python and Solving Memory Exhaustion

This article walks through using Python's zipfile module to brute‑force an encrypted ZIP password, demonstrates a multithreaded approach that initially exhausts memory, and shows how replacing ThreadPoolExecutor's unbounded queue with a bounded one resolves the issue.

Python Crawling & Data Mining
Python Crawling & Data Mining
Python Crawling & Data Mining
Cracking Encrypted ZIP Files with Python and Solving Memory Exhaustion

While cleaning an old computer, the author discovered an encrypted ZIP file with a forgotten six‑character alphanumeric password. Using Python's built‑in zipfile module, a simple script can extract a ZIP when the correct password is supplied.

import zipfile
# create file handle
file = zipfile.ZipFile("test.zip", 'r')
# extract with password (bytes)
file.extractall(path='.', pwd='123'.encode('utf-8'))

The next step was to brute‑force the password. A multithreaded script using ThreadPoolExecutor and itertools.permutations generated all six‑character combinations of digits and uppercase letters.

import zipfile
import itertools
from concurrent.futures import ThreadPoolExecutor

def extract(file, password):
    if not flag: return
    file.extractall(path='.', pwd=''.join(password).encode('utf-8'))

def result(f):
    exception = f.exception()
    if not exception:
        print('Password is:', f.pwd)
        global flag
        flag = False

if __name__ == '__main__':
    flag = True
    pool = ThreadPoolExecutor(100)
    nums = [str(i) for i in range(10)]
    chrs = [chr(i) for i in range(65, 91)]
    password_lst = itertools.permutations(nums + chrs, 6)
    zfile = zipfile.ZipFile("encrypted.zip", 'r')
    for pwd in password_lst:
        if not flag: break
        f = pool.submit(extract, zfile, pwd)
        f.pwd = pwd
        f.add_done_callback(result)

Running this code quickly filled memory because ThreadPoolExecutor uses an unbounded work queue; tasks were produced faster than they could be executed, causing the queue to grow without limit and memory usage to spike to 95 % before the process crashed.

To fix the problem, the author rewrote the executor to use a bounded queue by subclassing ThreadPoolExecutor and overriding its internal work queue.

import queue
from concurrent.futures import ThreadPoolExecutor

class BoundedThreadPoolExecutor(ThreadPoolExecutor):
    def __init__(self, max_workers=None, thread_name_prefix=''):
        super().__init__(max_workers, thread_name_prefix)
        self._work_queue = queue.Queue(self._max_workers * 2)  # set queue size

Replacing the original executor with BoundedThreadPoolExecutor prevented the memory overflow, and the password was eventually recovered, as shown in the final screenshot.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

memory leakmultithreadingThreadPoolExecutorbrute forcezipfile
Python Crawling & Data Mining
Written by

Python Crawling & Data Mining

Life's short, I code in Python. This channel shares Python web crawling, data mining, analysis, processing, visualization, automated testing, DevOps, big data, AI, cloud computing, machine learning tools, resources, news, technical articles, tutorial videos and learning materials. Join us!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.