In our last article, we talked about breaking passwords with brute force. Today, we’re going to apply that method to zip files. We’ll start simple, focusing on passwords that use only lowercase letters. This keeps things faster, but I’ll show you how to tweak it for any password, no matter how complex. Let’s get cracking on those zip file passwords.
Table of Contents
- Disclaimer
- Necessary Libraries
- Imports
- ZipCrackerApp Class
- Creating GUI Widgets
- Defining Functions
- Main Application Execution
- Example
- Full Code
- Summary
Disclaimer
Please note: This content is for educational purposes only. Don’t use these methods on files or systems without explicit permission. Hacking without consent is illegal and unethical.
Necessary Libraries
Let’s get everything set up before we dive into the code. Make sure to install the tkinter and pyzipper libraries for the code to function properly:
$ pip install tk
$ pip install pyzipper
Imports
import tkinter as tk
from tkinter import filedialog, messagebox
import zipfile
import pyzipper
from threading import Thread
As per usual, we will start our script with the necessary imports:
- tkinter Library: We’ll begin with the
tkinter
library to create a graphical user interface (GUI). Fromtkinter
, we specifically need thefiledialog
andmessagebox
modules. These allow us to choose files and use message boxes, respectively. - Zipfile Module: Next, we import the
zipfile
module, which is essential for handling Zip files. - PyZipper Module: After that, we’ll include the
pyzipper
module. This is important for working with AES-encrypted Zip files. - Thread Class: Lastly, we import the
Thread
class. This enables us to run multiple tasks in parallel without interference.
Every import we add is like a key ingredient in our recipe, ensuring our code runs just right and zips along without a hitch.
ZipCrackerApp Class
Next, we define a class called ZipCrackerApp
that inherits all the functionality of a regular tkinter application window. Then, we proceed to customize the class by creating an instance with the __init__()
method.
After that, we initialize the main window. In other words, we prepare the main window for display using the super().__init__()
method and also set its title. Next, we initialize the variables we’ll need and get ready to create widgets by calling the create_widgets()
function.
class ZipCrackerApp(tk.Tk):
def __init__(self):
super().__init__()
self.title("Zip File Brute Force")
self.file_path = tk.StringVar()
self.min_length = tk.IntVar()
self.max_length = tk.IntVar()
self.result_text = tk.StringVar()
self.zip_type = tk.StringVar(value="standard") # Default to standard zip
self.create_widgets()
Creating GUI Widgets
Following that, we create the widgets to be arranged using the grid layout on the main window. These include labels for displaying text, entry fields for inputs, radio buttons for selecting the type of encryption to crack, and buttons. Each button will have a different name and will call a specific function.
def create_widgets(self):
# File Selection
file_label = tk.Label(self, text="Select Zip File:")
file_label.grid(row=0, column=0, padx=5, pady=5)
file_entry = tk.Entry(self, textvariable=self.file_path, width=50)
file_entry.grid(row=0, column=1, padx=5, pady=5)
browse_button = tk.Button(self, text="Browse", command=self.browse_file)
browse_button.grid(row=0, column=2, padx=5, pady=5)
# Zip Type Selection
zip_type_label = tk.Label(self, text="Zip File Type:")
zip_type_label.grid(row=1, column=0, padx=5, pady=5)
zip_type_standard = tk.Radiobutton(self, text="Standard Zip", variable=self.zip_type, value="standard")
zip_type_standard.grid(row=1, column=1, padx=5, pady=5)
zip_type_aes = tk.Radiobutton(self, text="AES Encrypted Zip", variable=self.zip_type, value="aes")
zip_type_aes.grid(row=1, column=2, padx=5, pady=5)
# Password Length
min_length_label = tk.Label(self, text="Minimum Password Length:")
min_length_label.grid(row=2, column=0, padx=5, pady=5)
min_length_entry = tk.Entry(self, textvariable=self.min_length, width=10)
min_length_entry.grid(row=2, column=1, padx=5, pady=5)
max_length_label = tk.Label(self, text="Maximum Password Length:")
max_length_label.grid(row=2, column=2, padx=5, pady=5)
max_length_entry = tk.Entry(self, textvariable=self.max_length, width=10)
max_length_entry.grid(row=2, column=3, padx=5, pady=5)
# Result Label
result_label = tk.Label(self, textvariable=self.result_text)
result_label.grid(row=3, column=0, columnspan=4, padx=5, pady=5)
# Start Button
start_button = tk.Button(self, text="Start Brute Force", command=self.start_brute_force)
start_button.grid(row=4, column=0, columnspan=4, padx=5, pady=5)
Defining Functions
Now, let’s define the heart of our code – our Functions:
File Browsing Function
This part uses the filedialog
so that the user will be able to select and view the ZIP file he or she wants to crack, and all this can be done when the user clicks the “Browse” button.
def browse_file(self):
file_path = filedialog.askopenfilename(filetypes=[("Zip files", "*.zip")])
if file_path:
self.file_path.set(file_path)
Brute Force Function
This function retrieves the user’s choices, including the zip file and the encryption type, from the input fields. Based on the selected zip file type, either standard or AES, it initializes a zip_file
object. This kicks off the brute force attack, trying every possible password combination through the generate_passwords()
function, within the user-specified password length range (minimum and maximum).
If the correct password is found, it will be displayed on the main window. Should the password remain unfound, a message indicating its absence will be shown instead. Additionally, any errors encountered during the process will trigger a pop-up alert, courtesy of messagebox.showerror()
.
def brute_force(self):
zip_file_path = self.file_path.get()
min_length = self.min_length.get()
max_length = self.max_length.get()
try:
if self.zip_type.get() == "aes":
zip_file = pyzipper.AESZipFile(zip_file_path)
else:
zip_file = zipfile.ZipFile(zip_file_path, 'r')
with zip_file:
for length in range(min_length, max_length + 1):
for password in self.generate_passwords(length):
try:
if self.zip_type.get() == "aes":
zip_file.pwd = password.encode()
zip_file.extractall()
else:
zip_file.extractall(pwd=password.encode())
self.result_text.set(f"Password found: {password}")
return
except (RuntimeError, zipfile.BadZipFile):
pass
self.result_text.set("Password not found.")
except Exception as e:
messagebox.showerror("Error", str(e))
Starting Brute Force Function
First up, this function checks if you’ve picked a real zip file and if the password lengths you’ve entered make sense. Got both those things right? Great! It then gets everything in order, pops up a message saying “Starting brute force“, and kicks off the brute_force()
function in a new thread. This clever move makes sure our main window stays awake and doesn’t go into a frozen slumber.
Now, if things aren’t quite right with what you’ve entered, the function won’t leave you hanging. Instead, it’ll quickly show you an error message explaining what went wrong. This way, you know exactly what to fix to get things rolling.
def start_brute_force(self):
if not self.file_path.get():
messagebox.showerror("Error", "Please select a ZIP file.")
return
if self.min_length.get() <= 0 or self.max_length.get() <= 0:
messagebox.showerror("Error", "Password length should be greater than zero.")
return
if self.min_length.get() > self.max_length.get():
messagebox.showerror("Error", "Minimum password length cannot be greater than maximum.")
return
self.result_text.set("Starting brute force...")
Thread(target=self.brute_force).start()
Generating Passwords Function
This one is responsible for creating passwords by trying different combinations of the lowercase English alphabets within the specified length by the user.
def generate_passwords(self, length):
for i in range(26 ** length):
password = ""
for j in range(length):
password += chr(ord('a') + (i // (26 ** j)) % 26)
yield password
Main Application Execution
Lastly, this block ensures that this script can only be run directly and not imported as a module in which case it will not function, while also making sure that the main window keeps running and is responsive to the user until he exits willingly.
if __name__ == "__main__":
app = ZipCrackerApp()
app.mainloop()
Example
Full Code
import tkinter as tk
from tkinter import filedialog, messagebox
import zipfile
import pyzipper
from threading import Thread
class ZipCrackerApp(tk.Tk):
def __init__(self):
super().__init__()
self.title("Zip File Brute Force")
self.file_path = tk.StringVar()
self.min_length = tk.IntVar()
self.max_length = tk.IntVar()
self.result_text = tk.StringVar()
self.zip_type = tk.StringVar(value="standard") # Default to standard zip
self.create_widgets()
def create_widgets(self):
# File Selection
file_label = tk.Label(self, text="Select Zip File:")
file_label.grid(row=0, column=0, padx=5, pady=5)
file_entry = tk.Entry(self, textvariable=self.file_path, width=50)
file_entry.grid(row=0, column=1, padx=5, pady=5)
browse_button = tk.Button(self, text="Browse", command=self.browse_file)
browse_button.grid(row=0, column=2, padx=5, pady=5)
# Zip Type Selection
zip_type_label = tk.Label(self, text="Zip File Type:")
zip_type_label.grid(row=1, column=0, padx=5, pady=5)
zip_type_standard = tk.Radiobutton(self, text="Standard Zip", variable=self.zip_type, value="standard")
zip_type_standard.grid(row=1, column=1, padx=5, pady=5)
zip_type_aes = tk.Radiobutton(self, text="AES Encrypted Zip", variable=self.zip_type, value="aes")
zip_type_aes.grid(row=1, column=2, padx=5, pady=5)
# Password Length
min_length_label = tk.Label(self, text="Minimum Password Length:")
min_length_label.grid(row=2, column=0, padx=5, pady=5)
min_length_entry = tk.Entry(self, textvariable=self.min_length, width=10)
min_length_entry.grid(row=2, column=1, padx=5, pady=5)
max_length_label = tk.Label(self, text="Maximum Password Length:")
max_length_label.grid(row=2, column=2, padx=5, pady=5)
max_length_entry = tk.Entry(self, textvariable=self.max_length, width=10)
max_length_entry.grid(row=2, column=3, padx=5, pady=5)
# Result Label
result_label = tk.Label(self, textvariable=self.result_text)
result_label.grid(row=3, column=0, columnspan=4, padx=5, pady=5)
# Start Button
start_button = tk.Button(self, text="Start Brute Force", command=self.start_brute_force)
start_button.grid(row=4, column=0, columnspan=4, padx=5, pady=5)
def browse_file(self):
file_path = filedialog.askopenfilename(filetypes=[("Zip files", "*.zip")])
if file_path:
self.file_path.set(file_path)
def brute_force(self):
zip_file_path = self.file_path.get()
min_length = self.min_length.get()
max_length = self.max_length.get()
try:
if self.zip_type.get() == "aes":
zip_file = pyzipper.AESZipFile(zip_file_path)
else:
zip_file = zipfile.ZipFile(zip_file_path, 'r')
with zip_file:
for length in range(min_length, max_length + 1):
for password in self.generate_passwords(length):
try:
if self.zip_type.get() == "aes":
zip_file.pwd = password.encode()
zip_file.extractall()
else:
zip_file.extractall(pwd=password.encode())
self.result_text.set(f"Password found: {password}")
return
except (RuntimeError, zipfile.BadZipFile):
pass
self.result_text.set("Password not found.")
except Exception as e:
messagebox.showerror("Error", str(e))
def start_brute_force(self):
if not self.file_path.get():
messagebox.showerror("Error", "Please select a ZIP file.")
return
if self.min_length.get() <= 0 or self.max_length.get() <= 0:
messagebox.showerror("Error", "Password length should be greater than zero.")
return
if self.min_length.get() > self.max_length.get():
messagebox.showerror("Error", "Minimum password length cannot be greater than maximum.")
return
self.result_text.set("Starting brute force...")
Thread(target=self.brute_force).start()
def generate_passwords(self, length):
for i in range(26 ** length):
password = ""
for j in range(length):
password += chr(ord('a') + (i // (26 ** j)) % 26)
yield password
if __name__ == "__main__":
app = ZipCrackerApp()
app.mainloop()
Summary
So, all in all, if you want to protect yourself from this attack, you should make your password as unique as possible by lengthening it and mixing symbols with digits with uppercase and lowercase characters.
Learn also: How to Generate Random Passwords in Python