@@ -37,52 +37,63 @@ def crack_handshake(handshake_obj, target_is_wpa3_sae, show_command=False):
3737 return Aircrack .crack_handshake (handshake_obj , show_command = show_command )
3838
3939 key = None
40- # Mode 22000 supports both WPA/WPA2 and WPA3-SAE (WPA-PBKDF2-PMKID+EAPOL)
41- hashcat_mode = '22000'
42- file_type_msg = "WPA3-SAE hash" if target_is_wpa3_sae else "WPA/WPA2 hash"
43-
44- Color .pl (f"{{+}} {{C}}Attempting to crack { file_type_msg } using Hashcat mode { hashcat_mode } {{W}}" )
45-
46- # Crack hash_file
47- for additional_arg in ([], ['--show' ]):
48- command = [
49- 'hashcat' ,
50- '--quiet' ,
51- '-m' , hashcat_mode ,
52- hash_file ,
53- Configuration .wordlist
54- ]
55- if Hashcat .should_use_force ():
56- command .append ('--force' )
57- command .extend (additional_arg )
58- if show_command :
59- Color .pl (f'{{+}} {{D}}Running: {{W}}{{P}}{ " " .join (command )} {{W}}' )
60- process = Process (command )
61- stdout , stderr = process .get_output ()
62-
63- # Check for errors first
64- if 'No hashes loaded' in stdout or 'No hashes loaded' in stderr :
65- continue # No valid hashes to crack
66-
67- if ':' not in stdout :
68- continue # No cracked results
69-
70- # Parse the key from hashcat output
71- # Expected format: hash:password
72- lines = stdout .strip ().split ('\n ' )
73- for line in lines :
74- if ':' in line and not line .startswith ('The plugin' ) and 'hashcat.net' not in line :
75- # Take the last part after the last colon as the password
76- parts = line .split (':' )
77- if len (parts ) >= 2 :
78- key = parts [- 1 ].strip ()
79- if key and len (key ) > 0 :
80- break
81- else :
82- continue
83- break
40+ try :
41+ # Mode 22000 supports both WPA/WPA2 and WPA3-SAE (WPA-PBKDF2-PMKID+EAPOL)
42+ hashcat_mode = '22000'
43+ file_type_msg = "WPA3-SAE hash" if target_is_wpa3_sae else "WPA/WPA2 hash"
44+
45+ Color .pl (f"{{+}} {{C}}Attempting to crack { file_type_msg } using Hashcat mode { hashcat_mode } {{W}}" )
46+
47+ # Crack hash_file
48+ for additional_arg in ([], ['--show' ]):
49+ command = [
50+ 'hashcat' ,
51+ '--quiet' ,
52+ '-m' , hashcat_mode ,
53+ hash_file ,
54+ Configuration .wordlist
55+ ]
56+ if Hashcat .should_use_force ():
57+ command .append ('--force' )
58+ command .extend (additional_arg )
59+ if show_command :
60+ Color .pl (f'{{+}} {{D}}Running: {{W}}{{P}}{ " " .join (command )} {{W}}' )
61+ process = Process (command )
62+ stdout , stderr = process .get_output ()
63+
64+ # Check for errors first
65+ if 'No hashes loaded' in stdout or 'No hashes loaded' in stderr :
66+ continue # No valid hashes to crack
67+
68+ if ':' not in stdout :
69+ continue # No cracked results
70+
71+ # Parse the key from hashcat output
72+ # Expected format: hash:password
73+ lines = stdout .strip ().split ('\n ' )
74+ for line in lines :
75+ if ':' in line and not line .startswith ('The plugin' ) and 'hashcat.net' not in line :
76+ # Take the last part after the last colon as the password
77+ parts = line .split (':' )
78+ if len (parts ) >= 2 :
79+ key = parts [- 1 ].strip ()
80+ if key and len (key ) > 0 :
81+ break
82+ else :
83+ continue
84+ break
8485
85- return key
86+ return key
87+ finally :
88+ # Cleanup temporary hash file
89+ if hash_file and os .path .exists (hash_file ):
90+ try :
91+ os .remove (hash_file )
92+ if Configuration .verbose > 1 :
93+ Color .pl ('{!} {O}Cleaned up temporary hash file{W}' )
94+ except OSError as e :
95+ if Configuration .verbose > 0 :
96+ Color .pl ('{!} {O}Warning: Could not remove hash file: %s{W}' % str (e ))
8697
8798 @staticmethod
8899 def crack_pmkid (pmkid_file , verbose = False ):
@@ -175,73 +186,113 @@ def generate_hash_file(handshake_obj, is_wpa3_sae, show_command=False):
175186 For WPA3-SAE, generates hash file for mode 22001.
176187 Both use the same hcxpcapngtool -o flag, as mode 22000 supports both WPA2 and WPA3-SAE.
177188 """
189+ import tempfile
190+
178191 # Use mode 22000 format for both WPA2 and WPA3-SAE
179192 # Hashcat mode 22000 supports WPA-PBKDF2-PMKID+EAPOL (includes SAE)
180193 # Mode 22001 is for WPA-PMK-PMKID+EAPOL (pre-computed PMK)
181- hash_file = Configuration .temp ('generated.22000' )
182-
183- if os .path .exists (hash_file ):
184- os .remove (hash_file )
185-
186- command = [
187- 'hcxpcapngtool' ,
188- '-o' , hash_file ,
189- handshake_obj .capfile # Assuming handshake_obj has a capfile attribute
190- ]
194+
195+ # Create secure temporary file with proper permissions (0600)
196+ # Using NamedTemporaryFile with delete=False to prevent race conditions
197+ with tempfile .NamedTemporaryFile (mode = 'w' , suffix = '.22000' , delete = False , prefix = 'wifite_hash_' ) as tmp :
198+ hash_file = tmp .name
199+
200+ # Verify file permissions are secure (0600)
201+ os .chmod (hash_file , 0o600 )
191202
192- if show_command :
193- Color .pl ('{+} {D}Running: {W}{P}%s{W}' % ' ' .join (command ))
203+ try :
204+ command = [
205+ 'hcxpcapngtool' ,
206+ '-o' , hash_file ,
207+ handshake_obj .capfile # Assuming handshake_obj has a capfile attribute
208+ ]
194209
195- process = Process (command )
196- stdout , stderr = process .get_output ()
197- if not os .path .exists (hash_file ) or os .path .getsize (hash_file ) == 0 :
198- # Check if this is due to missing frames (common with airodump captures)
199- if 'no hashes written' in stdout .lower () or 'missing frames' in stdout .lower ():
200- Color .pl ('{!} {O}Warning: hcxpcapngtool could not extract hash (capture quality issue){W}' )
201- Color .pl ('{!} {O}The capture file is missing required frames or metadata{W}' )
202- Color .pl ('{!} {O}This is common with airodump-ng captures - consider using hcxdumptool instead{W}' )
203- # Return None to signal fallback to aircrack-ng should be used
204- return None
205-
206- # For other errors, provide detailed error message
207- error_msg = f'Failed to generate { "SAE hash" if is_wpa3_sae else "WPA/WPA2 hash" } file.'
208- error_msg += f'\n Output from hcxpcapngtool:\n STDOUT: { stdout } \n STDERR: { stderr } '
209- # Also include tshark check for WPA3
210- if is_wpa3_sae :
211- from .tshark import Tshark
212- tshark_check_cmd = ['tshark' , '-r' , handshake_obj .capfile , '-Y' , 'wlan.fc.type_subtype == 0x0b' ] # Authentication frames
213- tshark_process = Process (tshark_check_cmd )
214- tshark_stdout , _ = tshark_process .get_output ()
215- if not tshark_stdout :
216- error_msg += '\n Additionally, tshark found no authentication frames in the capture file. Ensure it is a valid WPA3-SAE handshake.'
217- else :
218- error_msg += f'\n Tshark found { len (tshark_stdout .strip ().split (chr (10 )))} authentication frames in the capture.'
210+ if show_command :
211+ Color .pl ('{+} {D}Running: {W}{P}%s{W}' % ' ' .join (command ))
219212
220- raise ValueError (error_msg )
221- return hash_file
213+ process = Process (command )
214+ stdout , stderr = process .get_output ()
215+ if not os .path .exists (hash_file ) or os .path .getsize (hash_file ) == 0 :
216+ # Check if this is due to missing frames (common with airodump captures)
217+ if 'no hashes written' in stdout .lower () or 'missing frames' in stdout .lower ():
218+ Color .pl ('{!} {O}Warning: hcxpcapngtool could not extract hash (capture quality issue){W}' )
219+ Color .pl ('{!} {O}The capture file is missing required frames or metadata{W}' )
220+ Color .pl ('{!} {O}This is common with airodump-ng captures - consider using hcxdumptool instead{W}' )
221+ # Cleanup failed hash file
222+ if os .path .exists (hash_file ):
223+ try :
224+ os .remove (hash_file )
225+ except OSError :
226+ pass
227+ # Return None to signal fallback to aircrack-ng should be used
228+ return None
229+
230+ # For other errors, provide detailed error message
231+ error_msg = f'Failed to generate { "SAE hash" if is_wpa3_sae else "WPA/WPA2 hash" } file.'
232+ error_msg += f'\n Output from hcxpcapngtool:\n STDOUT: { stdout } \n STDERR: { stderr } '
233+ # Also include tshark check for WPA3
234+ if is_wpa3_sae :
235+ from .tshark import Tshark
236+ tshark_check_cmd = ['tshark' , '-r' , handshake_obj .capfile , '-Y' , 'wlan.fc.type_subtype == 0x0b' ] # Authentication frames
237+ tshark_process = Process (tshark_check_cmd )
238+ tshark_stdout , _ = tshark_process .get_output ()
239+ if not tshark_stdout :
240+ error_msg += '\n Additionally, tshark found no authentication frames in the capture file. Ensure it is a valid WPA3-SAE handshake.'
241+ else :
242+ error_msg += f'\n Tshark found { len (tshark_stdout .strip ().split (chr (10 )))} authentication frames in the capture.'
243+
244+ raise ValueError (error_msg )
245+ return hash_file
246+ except Exception :
247+ # Cleanup hash file on any error
248+ if hash_file and os .path .exists (hash_file ):
249+ try :
250+ os .remove (hash_file )
251+ if Configuration .verbose > 1 :
252+ Color .pl ('{!} {O}Cleaned up temporary hash file after error{W}' )
253+ except OSError :
254+ pass
255+ raise
222256
223257 @staticmethod
224258 def generate_john_file (handshake , show_command = False ):
225- john_file = Configuration .temp ('generated.john' )
226- if os .path .exists (john_file ):
227- os .remove (john_file )
259+ import tempfile
260+
261+ # Create secure temporary file with proper permissions (0600)
262+ # Using NamedTemporaryFile with delete=False to prevent race conditions
263+ with tempfile .NamedTemporaryFile (mode = 'w' , suffix = '.john' , delete = False , prefix = 'wifite_john_' ) as tmp :
264+ john_file = tmp .name
265+
266+ # Verify file permissions are secure (0600)
267+ os .chmod (john_file , 0o600 )
228268
229- command = [
230- 'hcxpcapngtool' ,
231- '--john' , john_file ,
232- handshake .capfile
233- ]
234-
235- if show_command :
236- Color .pl ('{+} {D}Running: {W}{P}%s{W}' % ' ' .join (command ))
269+ try :
270+ command = [
271+ 'hcxpcapngtool' ,
272+ '--john' , john_file ,
273+ handshake .capfile
274+ ]
237275
238- process = Process (command )
239- stdout , stderr = process .get_output ()
240- if not os .path .exists (john_file ):
241- raise ValueError ('Failed to generate .john file, output: \n %s\n %s' % (
242- stdout , stderr ))
276+ if show_command :
277+ Color .pl ('{+} {D}Running: {W}{P}%s{W}' % ' ' .join (command ))
243278
244- return john_file
279+ process = Process (command )
280+ stdout , stderr = process .get_output ()
281+ if not os .path .exists (john_file ):
282+ raise ValueError ('Failed to generate .john file, output: \n %s\n %s' % (
283+ stdout , stderr ))
284+
285+ return john_file
286+ except Exception :
287+ # Cleanup john file on any error
288+ if john_file and os .path .exists (john_file ):
289+ try :
290+ os .remove (john_file )
291+ if Configuration .verbose > 1 :
292+ Color .pl ('{!} {O}Cleaned up temporary john file after error{W}' )
293+ except OSError :
294+ pass
295+ raise
245296
246297 def get_pmkid_hash (self , pcapng_file ):
247298 if os .path .exists (self .pmkid_file ):
@@ -283,11 +334,15 @@ def extract_all_pmkids(pcapng_file):
283334 Returns:
284335 List of dicts: [{'bssid': str, 'essid': str, 'hash': str}, ...]
285336 """
286- temp_hash_file = Configuration .temp ('all_pmkids.22000' )
287-
288- # Remove temp file if it exists
289- if os .path .exists (temp_hash_file ):
290- os .remove (temp_hash_file )
337+ import tempfile
338+
339+ # Create secure temporary file with proper permissions (0600)
340+ # Using NamedTemporaryFile with delete=False to prevent race conditions
341+ with tempfile .NamedTemporaryFile (mode = 'w' , suffix = '.22000' , delete = False , prefix = 'wifite_pmkids_' ) as tmp :
342+ temp_hash_file = tmp .name
343+
344+ # Verify file permissions are secure (0600)
345+ os .chmod (temp_hash_file , 0o600 )
291346
292347 # Check if pcapng file exists
293348 if not os .path .exists (pcapng_file ):
@@ -367,7 +422,10 @@ def extract_all_pmkids(pcapng_file):
367422 if os .path .exists (temp_hash_file ):
368423 try :
369424 os .remove (temp_hash_file )
370- except :
371- pass
425+ if Configuration .verbose > 1 :
426+ Color .pl ('{!} {O}Cleaned up temporary PMKID hash file{W}' )
427+ except OSError as e :
428+ if Configuration .verbose > 0 :
429+ Color .pl ('{!} {O}Warning: Could not remove PMKID hash file: %s{W}' % str (e ))
372430
373431 return pmkids
0 commit comments