hannabaker commited on
Commit
dd2242f
Β·
verified Β·
1 Parent(s): f797daa

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +246 -0
app.py ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import subprocess
3
+ import os
4
+ import tempfile
5
+ import time
6
+
7
+ def estimate_time(length, charset):
8
+ """Estimate time for brute force based on charset and length"""
9
+ charset_sizes = {
10
+ "a": 26,
11
+ "A": 26,
12
+ "1": 10,
13
+ "a1": 36,
14
+ "aA": 52,
15
+ "aA1": 62
16
+ }
17
+
18
+ size = charset_sizes.get(charset, 26)
19
+ total_combinations = sum(size ** i for i in range(1, length + 1))
20
+ # Rough estimate: 100k passwords per second on CPU
21
+ seconds = total_combinations / 100000
22
+
23
+ if seconds < 60:
24
+ return f"{seconds:.1f} seconds"
25
+ elif seconds < 3600:
26
+ return f"{seconds/60:.1f} minutes"
27
+ elif seconds < 86400:
28
+ return f"{seconds/3600:.1f} hours"
29
+ else:
30
+ return f"{seconds/86400:.1f} days"
31
+
32
+ def crack_zip(file, method, max_length=6, charset="a", progress=gr.Progress()):
33
+ if file is None:
34
+ return "Please upload a ZIP file"
35
+
36
+ # Show estimated time for brute force
37
+ if method == "Brute Force":
38
+ est_time = estimate_time(max_length, charset)
39
+ progress(0, desc=f"Starting brute force (estimated max time: {est_time})")
40
+
41
+ # Use temp directory that user has access to
42
+ temp_dir = tempfile.mkdtemp(dir="/tmp")
43
+ temp_path = os.path.join(temp_dir, "uploaded.zip")
44
+
45
+ try:
46
+ # Read and save the uploaded file
47
+ with open(temp_path, "wb") as f:
48
+ f.write(file.read())
49
+
50
+ if method == "Dictionary Attack":
51
+ progress(0.5, desc="Running dictionary attack...")
52
+ return crack_with_john(temp_path)
53
+ else:
54
+ return crack_with_fcrackzip_progress(temp_path, max_length, charset, progress)
55
+ except Exception as e:
56
+ return f"Error: {str(e)}"
57
+ finally:
58
+ # Clean up
59
+ try:
60
+ if os.path.exists(temp_path):
61
+ os.remove(temp_path)
62
+ if os.path.exists(temp_dir):
63
+ os.rmdir(temp_dir)
64
+ except:
65
+ pass
66
+
67
+ def crack_with_fcrackzip_progress(file_path, max_length, charset, progress):
68
+ """Run fcrackzip with progress updates"""
69
+ try:
70
+ # Try lengths progressively
71
+ for length in range(1, max_length + 1):
72
+ progress(length / max_length, desc=f"Trying length {length}/{max_length}")
73
+
74
+ cmd = [
75
+ "fcrackzip",
76
+ "-b", # brute force
77
+ "-c", charset, # character set
78
+ "-l", f"{length}-{length}", # specific length
79
+ "-u", # unzip to verify
80
+ "-v", # verbose
81
+ file_path
82
+ ]
83
+
84
+ result = subprocess.run(cmd, capture_output=True, text=True)
85
+ output = result.stdout + result.stderr
86
+
87
+ if "PASSWORD FOUND" in output:
88
+ # Extract password from output
89
+ for line in output.split('\n'):
90
+ if "PASSWORD FOUND" in line:
91
+ password = line.split("== ")[-1].strip()
92
+ return f"βœ… Password found: {password}\n\nFound at length: {length}"
93
+
94
+ return f"❌ Password not found (tried all combinations up to {max_length} characters)"
95
+
96
+ except Exception as e:
97
+ return f"Error with fcrackzip: {str(e)}"
98
+
99
+ def crack_with_john(file_path):
100
+ try:
101
+ # Use /tmp for hash file (writable by user)
102
+ hash_file = "/tmp/zip_hash.txt"
103
+
104
+ # Extract hash
105
+ result = subprocess.run(
106
+ ["zip2john", file_path],
107
+ capture_output=True,
108
+ text=True
109
+ )
110
+
111
+ if result.returncode != 0:
112
+ return f"Error extracting hash: {result.stderr}"
113
+
114
+ # Write hash to file
115
+ with open(hash_file, "w") as f:
116
+ f.write(result.stdout)
117
+
118
+ # Create custom john directory in /tmp
119
+ john_dir = "/tmp/.john"
120
+ os.makedirs(john_dir, exist_ok=True)
121
+ os.environ["JOHN_PRIVATE_HOME"] = john_dir
122
+
123
+ # Run John with wordlist
124
+ crack_result = subprocess.run(
125
+ ["john", "--wordlist=/usr/share/john/password.lst", hash_file],
126
+ capture_output=True,
127
+ text=True,
128
+ timeout=300 # 5 minute timeout
129
+ )
130
+
131
+ # Get cracked password
132
+ show_result = subprocess.run(
133
+ ["john", "--show", hash_file],
134
+ capture_output=True,
135
+ text=True
136
+ )
137
+
138
+ # Parse output
139
+ if show_result.stdout:
140
+ lines = show_result.stdout.strip().split('\n')
141
+ for line in lines:
142
+ if ':' in line and not line.startswith('0 password'):
143
+ parts = line.split(':')
144
+ if len(parts) >= 2:
145
+ password = parts[1]
146
+ return f"βœ… Password found: {password}"
147
+
148
+ return "❌ Password not found in wordlist"
149
+
150
+ except subprocess.TimeoutExpired:
151
+ return "⏱️ Dictionary attack timed out after 5 minutes"
152
+ except Exception as e:
153
+ return f"Error with John: {str(e)}"
154
+
155
+ # Create Gradio interface
156
+ with gr.Blocks(title="ZIP Password Recovery", theme=gr.themes.Soft()) as demo:
157
+ gr.Markdown("# πŸ” ZIP Password Recovery Tool")
158
+ gr.Markdown("Upload a password-protected ZIP file to attempt password recovery")
159
+
160
+ with gr.Row():
161
+ with gr.Column():
162
+ file_input = gr.File(
163
+ label="Upload ZIP File",
164
+ file_types=[".zip"],
165
+ type="binary"
166
+ )
167
+ method = gr.Radio(
168
+ ["Dictionary Attack", "Brute Force"],
169
+ label="Recovery Method",
170
+ value="Dictionary Attack"
171
+ )
172
+
173
+ with gr.Accordion("Brute Force Settings", open=False):
174
+ max_length = gr.Slider(
175
+ minimum=1,
176
+ maximum=12, # Extended to 12
177
+ value=4,
178
+ step=1,
179
+ label="Max Password Length",
180
+ info="⚠️ Length 8+ can take hours/days!"
181
+ )
182
+ charset = gr.Dropdown(
183
+ choices=[
184
+ ("Lowercase letters (a-z)", "a"),
185
+ ("Uppercase letters (A-Z)", "A"),
186
+ ("Numbers (0-9)", "1"),
187
+ ("Lowercase + Numbers", "a1"),
188
+ ("All letters (a-z, A-Z)", "aA"),
189
+ ("All letters + Numbers", "aA1")
190
+ ],
191
+ value="a",
192
+ label="Character Set",
193
+ info="More characters = much longer time"
194
+ )
195
+
196
+ # Time estimate display
197
+ time_estimate = gr.Textbox(
198
+ label="Estimated Maximum Time",
199
+ value="~0.1 seconds",
200
+ interactive=False
201
+ )
202
+
203
+ crack_btn = gr.Button("Start Recovery", variant="primary")
204
+
205
+ with gr.Column():
206
+ output = gr.Textbox(
207
+ label="Result",
208
+ lines=5,
209
+ max_lines=10
210
+ )
211
+
212
+ # Update time estimate when settings change
213
+ def update_estimate(length, charset):
214
+ return f"~{estimate_time(length, charset)}"
215
+
216
+ max_length.change(update_estimate, [max_length, charset], time_estimate)
217
+ charset.change(update_estimate, [max_length, charset], time_estimate)
218
+
219
+ crack_btn.click(
220
+ fn=crack_zip,
221
+ inputs=[file_input, method, max_length, charset],
222
+ outputs=output
223
+ )
224
+
225
+ gr.Markdown("""
226
+ ### πŸ“Š Time Estimates (approximate):
227
+ - **Length 4**: seconds to minutes
228
+ - **Length 6**: minutes to hours
229
+ - **Length 8**: hours to days
230
+ - **Length 10+**: days to weeks/months
231
+
232
+ ### ⚑ Tips:
233
+ - Start with Dictionary Attack first
234
+ - For brute force, start with shorter lengths
235
+ - Lowercase only is fastest
236
+ - Each additional character exponentially increases time
237
+ - HF Spaces may timeout on very long operations
238
+
239
+ ### ⚠️ Important:
240
+ - Only use on files you own
241
+ - Consider if recreating the content would be faster
242
+ - GPU instances would be much faster but cost money
243
+ """)
244
+
245
+ if __name__ == "__main__":
246
+ demo.launch()