Skip to content

Commit

Permalink
Implement ignore feature
Browse files Browse the repository at this point in the history
  • Loading branch information
mendelgusmao committed Oct 21, 2024
1 parent c0bbf51 commit 61b4f34
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 24 deletions.
5 changes: 4 additions & 1 deletion wifite/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ def start(self):
from .util.crack import CrackHelper

if Configuration.show_cracked:
CrackResult.display()
CrackResult.display('cracked')

elif Configuration.show_ignored:
CrackResult.display('ignored')

elif Configuration.check_handshake:
Handshake.check()
Expand Down
5 changes: 5 additions & 0 deletions wifite/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,11 @@ def _add_command_args(commands):
dest='cracked',
help=Color.s('Print previously-cracked access points'))

commands.add_argument('--ignored',
action='store_true',
dest='ignored',
help=Color.s('Print ignored and previously-cracked access points'))

commands.add_argument('-cracked',
help=argparse.SUPPRESS,
action='store_true',
Expand Down
32 changes: 24 additions & 8 deletions wifite/attack/all.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from enum import Enum
from .pmkid import AttackPMKID
from .wep import AttackWEP
from .wpa import AttackWPA
Expand All @@ -9,6 +10,11 @@
from ..model.target import WPSState
from ..util.color import Color

class Answer(Enum):
Skip = 1
ExitOrReturn = 2
Continue = 3
Ignore = 4

class AttackAll(object):
@classmethod
Expand Down Expand Up @@ -109,10 +115,14 @@ def attack_single(cls, target, targets_remaining):
except KeyboardInterrupt:
Color.pl('\n{!} {O}Interrupted{W}\n')
answer = cls.user_wants_to_continue(targets_remaining, len(attacks))
if answer is True:
if answer == Answer.Continue:
continue # Keep attacking the same target (continue)
elif answer is None:
elif answer == Answer.Skip:
return True # Keep attacking other targets (skip)
elif answer == Answer.Ignore:
from ..model.result import CrackResult
CrackResult.ignore_target(target)
return True # Ignore current target and keep attacking other targets (ignore)
else:
return False # Stop all attacks (exit)

Expand All @@ -126,9 +136,10 @@ def user_wants_to_continue(cls, targets_remaining, attacks_remaining=0):
"""
Asks user if attacks should continue onto other targets
Returns:
None if the user wants to skip the current target
True if the user wants to continue to the next attack on the current target
False if the user wants to stop the remaining attacks
Answer.Skip if the user wants to skip the current target
Answer.Ignore if the user wants to ignore the current target
Answer.Continue if the user wants to continue to the next attack on the current target
Answer.ExitOrReturn if the user wants to stop the remaining attacks
"""
if attacks_remaining == 0 and targets_remaining == 0:
return # No targets or attacksleft, drop out
Expand All @@ -152,6 +163,9 @@ def user_wants_to_continue(cls, targets_remaining, attacks_remaining=0):
prompt += ' {O}skip{W} to the next target,'
options += '{O}s{W}{D}, {W}'

prompt += ' skip and {P}ignore{W} current target,'
options += '{P}i{W}{D}, {W}'

if Configuration.infinite_mode:
options += '{R}r{W})'
prompt += ' or {R}return{W} to scanning %s? {C}' % options
Expand All @@ -163,8 +177,10 @@ def user_wants_to_continue(cls, targets_remaining, attacks_remaining=0):
answer = input().lower()

if answer.startswith('s'):
return None # Skip
return Answer.Skip
elif answer.startswith('e') or answer.startswith('r'):
return False # Exit/Return
return Answer.ExitOrReturn # Exit/Return
elif answer.startswith('i'):
return Answer.Ignore # Ignore
else:
return True # Continue
return Answer.Continue # Continue
11 changes: 8 additions & 3 deletions wifite/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class Configuration(object):
scan_time = None
show_bssids = None
show_cracked = None
show_ignored = None
show_manufacturers = None
skip_crack = None
target_bssid = None
Expand Down Expand Up @@ -209,6 +210,7 @@ def initialize(cls, load_interface=True):

# Commands
cls.show_cracked = False
cls.show_ignored = False
cls.check_handshake = None
cls.crack_handshake = False

Expand Down Expand Up @@ -257,6 +259,8 @@ def load_from_arguments(cls):
# Commands
if args.cracked:
cls.show_cracked = True
if args.ignored:
cls.show_ignored = True
if args.check_handshake:
cls.check_handshake = args.check_handshake
if args.crack_handshake:
Expand Down Expand Up @@ -356,10 +360,11 @@ def parse_settings_args(cls, args):
Color.pl('{+} {C}option: {O}ignoring ESSID(s): {R}%s{W}' %
', '.join(args.ignore_essids))

from .model.result import CrackResult
cls.ignore_cracked = CrackResult.load_ignored_bssids(args.ignore_cracked)

if args.ignore_cracked:
from .model.result import CrackResult
if cracked_targets := CrackResult.load_all():
cls.ignore_cracked = [item['bssid'] for item in cracked_targets]
if cls.ignore_cracked:
Color.pl('{+} {C}option: {O}ignoring {R}%s{O} previously-cracked targets' % len(cls.ignore_cracked))

else:
Expand Down
49 changes: 49 additions & 0 deletions wifite/model/ignored_result.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from ..util.color import Color
from ..model.result import CrackResult
from contextlib import contextmanager, redirect_stderr, redirect_stdout
from os import devnull


@contextmanager
def suppress_stdout_stderr():
"""A context manager that redirects stdout and stderr to devnull"""
with open(devnull, 'w') as fnull:
with redirect_stderr(fnull) as err, redirect_stdout(fnull) as out:
yield err, out


class CrackResultIgnored(CrackResult):
def __init__(self, bssid, essid):
self.result_type = 'IGN'
self.bssid = bssid
self.essid = essid
super(CrackResultIgnored, self).__init__()

def dump(self):
if self.essid is not None:
Color.pl(f'{{+}} {"ESSID".rjust(12)}: {{C}}{self.essid}{{W}}')
Color.pl('{+} %s: {C}%s{W}' % ('BSSID'.rjust(12), self.bssid))

def print_single_line(self, longest_essid):
self.print_single_line_prefix(longest_essid)
Color.p('{G}%s{W}' % 'IGN'.ljust(9))
Color.pl('')

def to_dict(self):
with suppress_stdout_stderr():
print('@@@ to dict', self.__dict__)
return {
'type': self.result_type,
'date': self.date,
'essid': self.essid,
'bssid': self.bssid,
}


if __name__ == '__main__':
crw = CrackResultIgnored('AA:BB:CC:DD:EE:FF', 'Test Router')
crw.dump()
crw.save()
79 changes: 67 additions & 12 deletions wifite/model/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,31 +61,39 @@ def save(self):
self.essid, Configuration.cracked_file))
return

Color.pl('{+} {C}%s{O} is now ignored in {G}%s{O}.' % (
self.essid, Configuration.cracked_file))

saved_results.append(self.to_dict())
with open(name, 'w') as fid:
fid.write(dumps(saved_results, indent=2))
Color.pl('{+} saved crack result to {C}%s{W} ({G}%d total{W})'
Color.pl('{+} saved result to {C}%s{W} ({G}%d total{W})'
% (name, len(saved_results)))

@classmethod
def display(cls):
""" Show cracked targets from cracked file """
def display(cls, result_type):
""" Show targets from results file """
name = cls.cracked_file
if not os.path.exists(name):
Color.pl('{!} {O}file {C}%s{O} not found{W}' % name)
return

with open(name, 'r') as fid:
cracked_targets = loads(fid.read())
targets = cls.load_all()
only_cracked = result_type == 'cracked'

if only_cracked:
targets = [item for item in targets if item.get('type') != 'IGN']
else:
targets = [item for item in targets if item.get('type') == 'IGN']

if len(cracked_targets) == 0:
if len(targets) == 0:
Color.pl('{!} {R}no results found in {O}%s{W}' % name)
return

Color.pl('\n{+} Displaying {G}%d{W} cracked target(s) from {C}%s{W}\n' % (
len(cracked_targets), name))
Color.pl('\n{+} Displaying {G}%d{W} cracked or ignored target(s) from {C}%s{W}\n' % (
len(targets), cls.cracked_file))

results = sorted([cls.load(item) for item in cracked_targets], key=lambda x: x.date, reverse=True)
results = sorted([cls.load(item) for item in targets], key=lambda x: x.date, reverse=True)
longest_essid = max(len(result.essid or 'ESSID') for result in results)

# Header
Expand All @@ -98,9 +106,10 @@ def display(cls):
Color.p(' ')
Color.p('TYPE'.ljust(5))
Color.p(' ')
Color.p('KEY')
Color.pl('{D}')
Color.p(' ' + '-' * (longest_essid + 17 + 19 + 5 + 11 + 12))
if only_cracked:
Color.p('KEY')
Color.pl('{D}')
Color.p(' ' + '-' * (longest_essid + 17 + 19 + 5 + 11 + 12))
Color.pl('{W}')
# Results
for result in results:
Expand All @@ -118,6 +127,24 @@ def load_all(cls):
return []
return json

@classmethod
def load_ignored_bssids(cls, ignore_cracked = False):
json = cls.load_all()
ignored_bssids = [
item.get('bssid', '')
for item in json
if item.get('result_type') == 'IGN'
]

if not ignore_cracked:
return ignored_bssids

return ignored_bssids + [
item.get('bssid', '')
for item in json
if item.get('result_type') != 'IGN'
]

@staticmethod
def load(json):
""" Returns an instance of the appropriate object given a json instance """
Expand Down Expand Up @@ -149,10 +176,30 @@ def load(json):
essid=json['essid'],
pmkid_file=json['pmkid_file'],
key=json['key'])

else:
from .ignored_result import CrackResultIgnored
result = CrackResultIgnored(bssid=json['bssid'],
essid=json['essid'])

result.date = json['date']
result.readable_date = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(result.date))
return result

@classmethod
def ignore_target(cls, target):
ignored_targets = cls.load_all()

for ignored_target in ignored_targets:
is_ignored = ignored_target == 'IGN'
bssid_match = target.bssid == ignored_target.get('bssid')
essid_match = target.essid == ignored_target.get('essid')
if is_ignored and bssid_match and essid_match:
return

from .ignored_result import CrackResultIgnored
ignored_target = CrackResultIgnored(target.bssid, target.essid)
ignored_target.save()

if __name__ == '__main__':
# Deserialize WPA object
Expand All @@ -178,3 +225,11 @@ def load(json):
'"date": 1433403278, "type": "WPS"}')
obj = CrackResult.load(json)
obj.dump()

# Deserialize Ignored object
Color.pl('\nIgnored:')
json = loads(
'{"bssid": "AA:BB:CC:DD:EE:FF", "essid": "Test Router", '
'"date": 1433403278, "type": "IGN"}')
obj = CrackResult.load(json)
obj.dump()

0 comments on commit 61b4f34

Please sign in to comment.