Skip to content
Open
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
16 changes: 14 additions & 2 deletions wifite/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,26 @@ def scan_and_attack(self):
from .util.scanner import Scanner
from .attack.all import AttackAll

attacked_targets = 0

Color.pl('')

# Scan
s = Scanner()
do_continue = s.find_targets()
targets = s.select_targets()

# Attack
attacked_targets = AttackAll.attack_multiple(targets)
if Configuration.infinite_mode:
while do_continue:
AttackAll.attack_multiple(targets)
do_continue = s.update_targets()
if not do_continue:
break
targets = s.select_targets()
attacked_targets = s.get_num_attacked()
else:
# Attack
attacked_targets = AttackAll.attack_multiple(targets)

Color.pl('{+} Finished attacking {C}%d{W} target(s), exiting' % attacked_targets)

Expand Down
14 changes: 14 additions & 0 deletions wifite/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ def _add_global_args(self, glob):
dest='five_ghz',
help=self._verbose('Include 5Ghz channels (default: {G}off{W})'))

glob.add_argument('-inf',
'--infinite',
action='store_true',
dest='infinite_mode',
help=Color.s('Enable infinite attack mode. Modify scanning time with '
'{C}-p{W} (default: {G}off{W})'))

glob.add_argument('-mac',
'--random-mac',
Expand All @@ -95,6 +101,14 @@ def _add_global_args(self, glob):
help=Color.s('Kill processes that conflict with Airmon/Airodump ' +
'(default: {G}off{W})'))

glob.add_argument('-pow',
'--power',
action='store',
dest='min_power',
metavar='[min_power]',
type=int,
help=Color.s('Attacks any targets with at least {C}min_power{W} signal strength'))

glob.add_argument('-b',
action='store',
dest='target_bssid',
Expand Down
23 changes: 16 additions & 7 deletions wifite/attack/all.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ def attack_single(cls, target, targets_remaining):
return True # Keep attacking other targets (skip)

while len(attacks) > 0:
# Needed by infinite attack mode in order to count how many targets were attacked
target.attacked = True
attack = attacks.pop(0)
try:
result = attack.run()
Expand Down Expand Up @@ -110,7 +112,9 @@ def user_wants_to_continue(cls, targets_remaining, attacks_remaining=0):
'''
Asks user if attacks should continue onto other targets
Returns:
True if user wants to continue, False otherwise.
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
'''
if attacks_remaining == 0 and targets_remaining == 0:
return # No targets or attacksleft, drop out
Expand All @@ -128,22 +132,27 @@ def user_wants_to_continue(cls, targets_remaining, attacks_remaining=0):

if attacks_remaining > 0:
prompt += ' {G}continue{W} attacking,'
options += '{G}C{W}{D}, {W}'
options += '{G}c{W}{D}, {W}'

if targets_remaining > 0:
prompt += ' {O}skip{W} to the next target,'
options += '{O}s{W}{D}, {W}'

options += '{R}e{W})'
prompt += ' or {R}exit{W} %s? {C}' % options
if Configuration.infinite_mode:
options += '{R}r{W})'
prompt += ' or {R}return{W} to scanning %s? {C}' % options
else:
options += '{R}e{W})'
prompt += ' or {R}exit{W} %s? {C}' % options

from ..util.input import raw_input
answer = raw_input(Color.s(prompt)).lower()
Color.p(prompt)
answer = raw_input().lower()

if answer.startswith('s'):
return None # Skip
elif answer.startswith('e'):
return False # Exit
elif answer.startswith('e') or answer.startswith('r'):
return False # Exit/Return
else:
return True # Continue

3 changes: 2 additions & 1 deletion wifite/attack/wep.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,8 @@ def user_wants_to_stop(self, current_attack, attacks_remaining, target):
attack_index += 1
Color.pl(' {G}%d{W}: {R}Stop attacking, {O}Move onto next target{W}' % attack_index)
while True:
answer = raw_input(Color.s('{?} Select an option ({G}1-%d{W}): ' % attack_index))
Color.p('{?} Select an option ({G}1-%d{W}): ' % attack_index)
answer = raw_input()
if not answer.isdigit() or int(answer) < 1 or int(answer) > attack_index:
Color.pl('{!} {R}Invalid input: {O}Must enter a number between {G}1-%d{W}' % attack_index)
continue
Expand Down
8 changes: 4 additions & 4 deletions wifite/attack/wps.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ def run(self):
return False

if not Configuration.wps_pixie and self.pixie_dust:
Color.pl('\r{!} {O}--no-pixie{R} was given, ignoring WPS PIN Attack on ' +
'{O}%s{W}' % self.target.essid)
Color.pl('\r{!} {O}--no-pixie{R} was given, ignoring WPS Pixie-Dust Attack ' +
'on {O}%s{W}' % self.target.essid)
self.success = False
return False

if not Configuration.wps_pin and not self.pixie_dust:
Color.pl('\r{!} {O}--no-pin{R} was given, ignoring WPS Pixie-Dust Attack ' +
'on {O}%s{W}' % self.target.essid)
Color.pl('\r{!} {O}--pixie{R} was given, ignoring WPS PIN Attack on ' +
'{O}%s{W}' % self.target.essid)
self.success = False
return False

Expand Down
19 changes: 18 additions & 1 deletion wifite/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

class Configuration(object):
''' Stores configuration variables and functions for Wifite. '''
version = '2.2.5'
version = '2.2.6'

initialized = False # Flag indicating config has been initialized
temp_dir = None # Temporary directory
Expand Down Expand Up @@ -38,12 +38,15 @@ def initialize(cls, load_interface=True):

cls.tx_power = 0 # Wifi transmit power (0 is default)
cls.interface = None
cls.min_power = 0 # Minimum power for an access point to be considered a target. Default is 0
cls.target_channel = None # User-defined channel to scan
cls.target_essid = None # User-defined AP name
cls.target_bssid = None # User-defined AP BSSID
cls.ignore_essid = None # ESSIDs to ignore
cls.clients_only = False # Only show targets that have associated clients
cls.five_ghz = False # Scan 5Ghz channels
cls.infinite_mode = False # Attack targets continuously
cls.inf_wait_time = 60
cls.show_bssids = False # Show BSSIDs in targets list
cls.random_mac = False # Should generate a random Mac address at startup.
cls.no_deauth = False # Deauth hidden networks & WPA handshake targets
Expand Down Expand Up @@ -197,6 +200,15 @@ def parse_settings_args(cls, args):
cls.five_ghz = True
Color.pl('{+} {C}option:{W} including {G}5Ghz networks{W} in scans')

if args.infinite_mode:
cls.infinite_mode = True
Color.p('{+} {C}option:{W} ({G}infinite{W}) attack all neighbors forever')
if not args.scan_time:
Color.p('; {O}pillage time not selected{W}, '
'using default {G}%d{W}s' % cls.inf_wait_time)
args.scan_time = cls.inf_wait_time
Color.pl('')

if args.show_bssids == True:
cls.show_bssids = True
Color.pl('{+} {C}option:{W} showing {G}bssids{W} of targets during scan')
Expand All @@ -211,6 +223,11 @@ def parse_settings_args(cls, args):
Color.pl('{+} {C}option:{W} send {G}%d{W} deauth packets when deauthing' % (
cls.num_deauths))

if args.min_power and args.min_power > 0:
cls.min_power = args.min_power
Color.pl('{+} {C}option:{W} Minimum power {G}%d{W} for target to be shown' %
cls.min_power)

if args.target_essid:
cls.target_essid = args.target_essid
Color.pl('{+} {C}option:{W} targeting ESSID {G}%s{W}' % args.target_essid)
Expand Down
73 changes: 73 additions & 0 deletions wifite/model/target.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-

from ..util.color import Color
from ..config import Configuration

import re

Expand All @@ -10,6 +11,43 @@ class WPSState:
NONE, UNLOCKED, LOCKED, UNKNOWN = range(0, 4)


class ArchivedTarget(object):
'''
Holds information between scans from a previously found target
'''
def __init__(self, target):
self.bssid = target.bssid
self.channel = target.channel
self.decloaked = target.decloaked
self.attacked = target.attacked
self.essid = target.essid
self.essid_known = target.essid_known
self.essid_len = target.essid_len

def transfer_info(self, other):
'''
Helper function to transfer relevant fields into another Target or ArchivedTarget
'''
other.attacked = self.attacked

# If both targets know the essid, keep decloacked value
if self.essid_known and other.essid_known:
other.decloaked = self.decloaked

# The destination target does not know the essid but the source
# does, copy that information
if self.essid_known and not other.essid_known:
other.decloaked = self.decloaked
other.essid = self.essid
other.essid_known = self.essid_known
other.essid_len = self.essid_len

def __eq__(self, other):
# Check if the other class type is either ArchivedTarget or Target
return (isinstance(other, self.__class__) or isinstance(other, Target)) \
and self.bssid == other.bssid


class Target(object):
'''
Holds details for a 'Target' aka Access Point (e.g. router).
Expand Down Expand Up @@ -51,6 +89,7 @@ def __init__(self, fields):
self.power = int(fields[8].strip())
if self.power < 0:
self.power += 100
self.max_power = self.power

self.beacons = int(fields[9].strip())
self.ivs = int(fields[10].strip())
Expand All @@ -69,10 +108,42 @@ def __init__(self, fields):

self.decloaked = False # If ESSID was hidden but we decloaked it.

# Will be set to true once this target will be attacked
# Needed to count targets in infinite attack mode
self.attacked = False

self.clients = []

self.validate()

def __eq__(self, other):
# Check if the other class type is either ArchivedTarget or Target
return (isinstance(other, self.__class__) or isinstance(other, ArchivedTarget)) \
and self.bssid == other.bssid

def transfer_info(self, other):
'''
Helper function to transfer relevant fields into another Target or ArchivedTarget
'''
other.wps = self.wps
other.attacked = self.attacked

if other.max_power < self.max_power:
other.max_power = self.max_power

# If both targets know the essid, keep decloacked value
if self.essid_known and other.essid_known:
other.decloaked = self.decloaked

# The destination target does not know the essid but the source
# does, copy that information
if self.essid_known and not other.essid_known:
other.decloaked = self.decloaked
other.essid = self.essid
other.essid_known = self.essid_known
other.essid_len = self.essid_len


def validate(self):
''' Checks that the target is valid. '''
if self.channel == '-1':
Expand Down Expand Up @@ -145,6 +216,8 @@ def to_str(self, show_bssid=False):
wps = Color.s('{R}lock')
elif self.wps == WPSState.UNKNOWN:
wps = Color.s('{O} n/a')
else:
wps = ' ERR'

clients = ' '
if len(self.clients) > 0:
Expand Down
19 changes: 17 additions & 2 deletions wifite/tools/airmon.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ class Airmon(Dependency):
dependency_name = 'airmon-ng'
dependency_url = 'https://www.aircrack-ng.org/install.html'

chipset_table = 'https://wikidevi.com/wiki/Wireless_adapters/Chipset_table'

base_interface = None
killed_network_manager = False

Expand Down Expand Up @@ -107,6 +109,19 @@ def get_interfaces():

return interfaces

@staticmethod
def get_iface_info(interface_name):
'''
Get interface info (driver, chipset), based on interface name.
Returns an AirmonIface if interface name is found by airmon-ng or None
'''
for iface in Airmon.get_interfaces():
if iface.interface == interface_name:
return iface

return None


@staticmethod
def start_bad_driver(iface):
'''
Expand Down Expand Up @@ -308,8 +323,8 @@ def ask():
choice = 1
else:
# Multiple interfaces found
question = Color.s('{+} Select wireless interface ({G}1-%d{W}): ' % (count))
choice = raw_input(question)
Color.p('{+} Select wireless interface ({G}1-%d{W}): ' % (count))
choice = raw_input()

iface = a.get(choice)

Expand Down
Loading