Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions wifite/attack/eviltwin.py
Original file line number Diff line number Diff line change
Expand Up @@ -974,11 +974,18 @@ def _check_dependencies(self) -> bool:
True if all dependencies are available, False otherwise
"""
try:
# TODO: Implement dependency checking
# This will be implemented in task 6.2
log_info('EvilTwin', 'Dependency check passed (placeholder)')
from ..util.process import Process
missing = []
for tool in ['hostapd', 'dnsmasq']:
if not Process.exists(tool):
missing.append(tool)
if missing:
log_error('EvilTwin', f'Missing required tools: {", ".join(missing)}')
self.error_message = f'Missing required tools: {", ".join(missing)}'
return False
log_info('EvilTwin', 'All required dependencies found')
return True

except Exception as e:
log_error('EvilTwin', f'Dependency check failed: {e}', e)
self.error_message = f'Dependency check failed: {e}'
Expand Down
2 changes: 1 addition & 1 deletion wifite/attack/pmkid.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
try:
from ..native.pmkid import ScapyPMKID, PMKIDResult as NativePMKIDResult
NATIVE_PMKID_AVAILABLE = ScapyPMKID.is_available()
except ImportError:
except BaseException:

Copilot AI Mar 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Catching BaseException here will also swallow KeyboardInterrupt/SystemExit, which can lead to surprising behavior at import time. If BaseException is needed to handle specific native import crashes, consider re-raising interrupt/exit exceptions and/or logging the underlying error when verbose so native PMKID availability doesn't silently flip to False on unexpected failures.

Suggested change
except BaseException:
except BaseException as e:
# Do not swallow interrupt/exit exceptions; re-raise them.
if isinstance(e, (KeyboardInterrupt, SystemExit)):
raise
# For any other failure, disable native PMKID support and log the reason.
log_debug("Native PMKID unavailable due to import error: %s" % (e,))

Copilot uses AI. Check for mistakes.
NATIVE_PMKID_AVAILABLE = False


Expand Down
13 changes: 10 additions & 3 deletions wifite/model/attack.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@
class Attack:
"""Contains functionality common to all attacks."""

target_wait = min(60, Configuration.wpa_attack_timeout)
@staticmethod
def _get_target_wait():
"""Get target wait time, safely handling uninitialized Configuration."""
timeout = Configuration.wpa_attack_timeout
if timeout is None:
return 60
return min(60, timeout)

def __init__(self, target):
self.target = target
Expand All @@ -18,12 +24,13 @@ def run(self):

def wait_for_target(self, airodump):
"""Waits for target to appear in airodump."""
target_wait = Attack._get_target_wait()
start_time = time.time()
targets = airodump.get_targets(apply_filter=False)
while len(targets) == 0:
# Wait for target to appear in airodump.
if int(time.time() - start_time) > Attack.target_wait:
raise Exception(f'Target did not appear after {Attack.target_wait:d} seconds, target may be out of range or turned off')
if int(time.time() - start_time) > target_wait:
raise Exception(f'Target did not appear after {target_wait:d} seconds, target may be out of range or turned off')
time.sleep(1)
targets = airodump.get_targets()
continue
Expand Down
3 changes: 2 additions & 1 deletion wifite/model/target.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ def __init__(self, fields):
elif len(self.encryption) == 0: # Default to WPA if not specified, as per old logic
self.primary_encryption = 'WPA'
else: # Fallback for unknown types
self.primary_encryption = self.encryption.split(' ')[0]
parts = self.encryption.split(' ')
self.primary_encryption = parts[0] if parts and parts[0] else 'WPA'
Comment on lines +114 to +115

Copilot AI Mar 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using split(' ') preserves empty tokens and can yield [''] for strings with multiple spaces, causing the fallback to default to 'WPA' even when a later token contains the real encryption (e.g. ' WPA2' or 'WPA2 WPA3'). Consider using self.encryption.split() (no argument) and selecting the first non-empty token instead.

Copilot uses AI. Check for mistakes.


if 'SAE' in self.authentication:
Expand Down
74 changes: 57 additions & 17 deletions wifite/native/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,54 @@
- scapy >= 2.6.1 (already a project dependency)
"""

from .mac import NativeMac
from .deauth import ScapyDeauth, ContinuousDeauth as NativeDeauth
from .handshake import ScapyHandshake
from .wps import ScapyWPS, WPSInfo
from .interface import NativeInterface, InterfaceInfo
from .pmkid import ScapyPMKID, PMKIDResult, PMKIDCapture
from .scanner import ChannelHopper, NativeScanner, AccessPoint, Client
from .beacon import BeaconGenerator, create_fake_ap as create_beacon
try:
from .mac import NativeMac
except BaseException:
NativeMac = None

try:
from .deauth import ScapyDeauth, ContinuousDeauth as NativeDeauth
except BaseException:
ScapyDeauth = None
NativeDeauth = None

try:
from .handshake import ScapyHandshake
except BaseException:
ScapyHandshake = None

try:
from .wps import ScapyWPS, WPSInfo
except BaseException:
ScapyWPS = None
WPSInfo = None

try:
from .interface import NativeInterface, InterfaceInfo
except BaseException:
NativeInterface = None
InterfaceInfo = None

try:
from .pmkid import ScapyPMKID, PMKIDResult, PMKIDCapture
except BaseException:
ScapyPMKID = None
PMKIDResult = None
PMKIDCapture = None

try:
from .scanner import ChannelHopper, NativeScanner, AccessPoint, Client
except BaseException:
ChannelHopper = None
NativeScanner = None
AccessPoint = None
Client = None

try:
from .beacon import BeaconGenerator, create_fake_ap as create_beacon
except BaseException:
BeaconGenerator = None
create_beacon = None
Comment on lines +26 to +73

Copilot AI Mar 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Catching BaseException will also swallow KeyboardInterrupt and SystemExit, which can make Ctrl+C or normal interpreter shutdown behave unexpectedly during imports. If BaseException is required for specific import-time crashes, consider re-raising KeyboardInterrupt/SystemExit (and possibly GeneratorExit) while handling the rest, and/or capturing/logging the original exception for debugging when native features are unexpectedly unavailable.

Copilot uses AI. Check for mistakes.

__all__ = [
# MAC manipulation
Expand Down Expand Up @@ -80,49 +120,49 @@ def check_native_availability() -> dict:
try:
from .mac import NativeMac
status['mac'] = True
except ImportError:
except BaseException:
status['mac'] = False

try:
from .deauth import SCAPY_AVAILABLE
status['deauth'] = SCAPY_AVAILABLE
except ImportError:
except BaseException:
status['deauth'] = False

try:
from .handshake import SCAPY_AVAILABLE
status['handshake'] = SCAPY_AVAILABLE
except ImportError:
except BaseException:
status['handshake'] = False

try:
from .wps import SCAPY_AVAILABLE
status['wps'] = SCAPY_AVAILABLE
except ImportError:
except BaseException:
status['wps'] = False

try:
from .interface import NativeInterface
status['interface'] = True
except ImportError:
except BaseException:
status['interface'] = False

try:
from .pmkid import SCAPY_AVAILABLE
status['pmkid'] = SCAPY_AVAILABLE
except ImportError:
except BaseException:
status['pmkid'] = False

try:
from .scanner import SCAPY_AVAILABLE
status['scanner'] = SCAPY_AVAILABLE
except ImportError:
except BaseException:
status['scanner'] = False

try:
from .beacon import SCAPY_AVAILABLE
status['beacon'] = SCAPY_AVAILABLE
except ImportError:
except BaseException:
status['beacon'] = False
Comment on lines 120 to 166

Copilot AI Mar 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check_native_availability() catches BaseException, which includes KeyboardInterrupt/SystemExit and also masks unexpected coding/runtime errors in the native modules. Consider re-raising KeyboardInterrupt/SystemExit and recording/logging the caught exception (at least under verbose/debug) so users can distinguish "not installed" from "native module crashed during import".

Copilot uses AI. Check for mistakes.

return status
Expand Down Expand Up @@ -156,5 +196,5 @@ def print_native_status():
import scapy
scapy_version = scapy.VERSION if hasattr(scapy, 'VERSION') else 'unknown'
print(f"\nScapy Version: {scapy_version}")
except ImportError:
except BaseException:
print("\nScapy: Not Installed")
2 changes: 1 addition & 1 deletion wifite/native/beacon.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
sendp, sniff, conf as scapy_conf
)
SCAPY_AVAILABLE = True
except ImportError:
except BaseException:
SCAPY_AVAILABLE = False
Comment on lines +34 to 35

Copilot AI Mar 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same concern as other native modules: except BaseException also catches KeyboardInterrupt/SystemExit and hides unexpected runtime/coding errors as "Scapy unavailable". Consider re-raising interrupt/exit exceptions and optionally storing/logging the underlying import exception for debugging.

Suggested change
except BaseException:
SCAPY_AVAILABLE = False
SCAPY_IMPORT_ERROR = None
except BaseException as e:
# Do not swallow critical exceptions like KeyboardInterrupt/SystemExit.
if isinstance(e, (KeyboardInterrupt, SystemExit)):
raise
# Scapy failed to import for some other reason; mark as unavailable
# and keep the original exception for potential debugging.
SCAPY_AVAILABLE = False
SCAPY_IMPORT_ERROR = e

Copilot uses AI. Check for mistakes.


Expand Down
2 changes: 1 addition & 1 deletion wifite/native/deauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
sendp, conf as scapy_conf
)
SCAPY_AVAILABLE = True
except ImportError:
except BaseException:
SCAPY_AVAILABLE = False


Expand Down
2 changes: 1 addition & 1 deletion wifite/native/handshake.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
Dot11Elt, Raw, conf as scapy_conf
)
SCAPY_AVAILABLE = True
except ImportError:
except BaseException:
SCAPY_AVAILABLE = False

Comment on lines 38 to 43

Copilot AI Mar 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Catching BaseException here will also swallow KeyboardInterrupt/SystemExit and can mask genuine bugs in the Scapy import path as a simple availability toggle. Consider re-raising interrupt/exit exceptions and capturing/logging the underlying exception so unexpected failures are diagnosable.

Copilot uses AI. Check for mistakes.

Expand Down
2 changes: 1 addition & 1 deletion wifite/native/pmkid.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
sniff, sendp, conf as scapy_conf
)
SCAPY_AVAILABLE = True
except ImportError:
except BaseException:
SCAPY_AVAILABLE = False

Comment on lines 43 to 48

Copilot AI Mar 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same pattern: except BaseException catches KeyboardInterrupt/SystemExit and can hide unexpected exceptions as a simple "Scapy unavailable" flag. Consider re-raising interrupt/exit exceptions and logging/preserving the underlying exception for debugging.

Copilot uses AI. Check for mistakes.

Expand Down
2 changes: 1 addition & 1 deletion wifite/native/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
sniff, conf as scapy_conf
)
SCAPY_AVAILABLE = True
except ImportError:
except BaseException:

Copilot AI Mar 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Catching BaseException here will also intercept KeyboardInterrupt/SystemExit and can hide unexpected Scapy/runtime errors as simply "unavailable". Consider re-raising interrupt/exit exceptions and optionally recording/logging the underlying import exception to make failures diagnosable.

Suggested change
except BaseException:
except BaseException as e:
if isinstance(e, (KeyboardInterrupt, SystemExit)):
raise

Copilot uses AI. Check for mistakes.
SCAPY_AVAILABLE = False


Expand Down
2 changes: 1 addition & 1 deletion wifite/native/wps.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
conf as scapy_conf
)
SCAPY_AVAILABLE = True
except ImportError:
except BaseException:
SCAPY_AVAILABLE = False


Expand Down
5 changes: 3 additions & 2 deletions wifite/util/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import contextlib
import re
import shlex
import time
import signal
import os
Expand Down Expand Up @@ -111,7 +112,7 @@ def call(command, cwd=None, shell=False):
# Split string commands into list of args for Popen when not using shell mode
if Configuration.verbose > 1:
Color.pe(f'\n {{C}}[?]{{W}} Executing: {{B}}{command}{{W}}')
command = command.split()
command = shlex.split(command)

Copilot AI Mar 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shlex.split() can raise ValueError for malformed/unbalanced quoting. Right now that would bubble up and potentially crash the caller in cases that previously worked (even if parsed imperfectly). Consider catching ValueError here and either (a) raising a clearer error that includes the original command string, or (b) falling back to a simpler split strategy.

Suggested change
command = shlex.split(command)
orig_command = command
try:
command = shlex.split(command)
except ValueError as e:
# Fall back to a naive split if shlex.split fails (e.g., malformed quoting)
log_warning(
f"Failed to parse command with shlex.split(): {e}. "
f"Falling back to naive split for command: {orig_command!r}"
)
command = orig_command.split()

Copilot uses AI. Check for mistakes.
elif shell:
if Configuration.verbose > 1:
Color.pe(f'\n {{C}}[?] {{W}} Executing (Shell): {{B}}{command}{{W}}')
Expand Down Expand Up @@ -150,7 +151,7 @@ def exists(program):

def __init__(self, command, devnull=False, stdout=PIPE, stderr=PIPE, cwd=None, bufsize=0, stdin=PIPE):
if isinstance(command, str):
command = command.split(' ')
command = shlex.split(command)

Copilot AI Mar 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as in Process.call(): shlex.split() can raise ValueError on unmatched quotes. Since this is in the constructor path for many subprocesses, it may be worth handling ValueError explicitly (clear message / fallback) to avoid unexpected crashes from user-supplied command strings.

Suggested change
command = shlex.split(command)
try:
command = shlex.split(command)
except ValueError as e:
# Provide a clear error message for malformed command strings (e.g., unmatched quotes)
log_error('Process', f'Failed to parse command string {command!r}: {e}', e)
raise

Copilot uses AI. Check for mistakes.

self.command = command
self._cleaned_up = False
Expand Down
2 changes: 1 addition & 1 deletion wifite/util/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
try:
from ..native.scanner import NativeScanner, AccessPoint as NativeAP, is_available as native_scanner_available
NATIVE_SCANNER_AVAILABLE = native_scanner_available()
except ImportError:
except BaseException:
NATIVE_SCANNER_AVAILABLE = False
Comment on lines +16 to 17

Copilot AI Mar 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Catching BaseException here will also intercept KeyboardInterrupt/SystemExit, which can prevent expected termination during startup. If the goal is to handle rare import-time crashes, consider re-raising interrupt/exit exceptions and (optionally) logging the underlying import error in verbose mode to aid debugging when native scanning is disabled.

Suggested change
except BaseException:
NATIVE_SCANNER_AVAILABLE = False
except BaseException as e:
# Do not swallow interrupts/exits during startup
if isinstance(e, (KeyboardInterrupt, SystemExit)):
raise
# Any other error means the native scanner is not available
NATIVE_SCANNER_AVAILABLE = False
# Optionally log the underlying import error when in verbose mode
if Configuration.verbose > 0:
Color.pexception(e)

Copilot uses AI. Check for mistakes.


Expand Down
7 changes: 4 additions & 3 deletions wifite/wifite.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,10 @@ def cleanup_old_sessions():
# Only log if verbose mode is enabled and sessions were deleted
if deleted > 0 and Configuration.verbose > 0:
Color.pl('{+} {D}Cleaned up {C}%d{D} old session file(s){W}' % deleted)
except Exception:
# Silently ignore cleanup errors on startup
pass
except Exception as e:
# Log cleanup errors but don't block startup
if Configuration.verbose > 0:
Color.pl('{!} {O}Session cleanup error: %s{W}' % str(e))

def detect_and_assign_interfaces(self, attack_type='wpa'):
"""
Expand Down
Loading