2.1.2: Quiet decloak. Support ESSIDs with commas and trailing spaces
Decloaked ESSIDs will have a "*" next to their name. For #78 While testing, I found that Wifite did not parse Airodump's CSV correctly. Specifically, ESSIDs with commas or trailing spaces. Fixed in this commit. Also fixed hidden ESSID detection introduced by the new CSV parsing logic.
This commit is contained in:
13
tests/files/airodump-weird-ssids.csv
Normal file
13
tests/files/airodump-weird-ssids.csv
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
BSSID, First time seen, Last time seen, channel, Speed, Privacy, Cipher, Authentication, Power, # beacons, # IV, LAN IP, ID-length, ESSID, Key
|
||||||
|
AA:BB:CC:DD:EE:FF, 2018-04-06 18:21:23, 2018-04-06 18:21:24, 10, 54, WPA2, CCMP,PSK, -34, 5, 0, 0. 0. 0. 0, 24, Comma\, no trailing space,
|
||||||
|
AA:BB:CC:DD:EE:FF, 2018-04-06 18:19:17, 2018-04-06 18:19:19, 10, 54, WPA2, CCMP,PSK, -35, 18, 0, 0. 0. 0. 0, 20, \"Quoted ESSID\, Comma\, no trailing spaces. \",
|
||||||
|
AA:BB:CC:DD:EE:FF, 2018-04-06 18:35:29, 2018-04-06 18:35:30, 10, 54, WPA2, CCMP,PSK, -31, 12, 0, 0. 0. 0. 0, 22, "Comma\, Trailing space ",
|
||||||
|
AA:BB:CC:DD:EE:FF, 2018-04-06 18:22:45, 2018-04-06 18:22:46, 10, 54, WPA2, CCMP,PSK, -29, 15, 0, 0. 0. 0. 0, 30, "\"quote\" comma\, trailing space ",
|
||||||
|
AA:BB:CC:DD:EE:FF, 2018-04-06 18:50:11, 2018-04-06 18:50:17, 10, 54, WPA2, CCMP,PSK, -20, 43, 0, 0. 0. 0. 0, 19, \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Station MAC, First time seen, Last time seen, Power, # packets, BSSID, Probed ESSIDs
|
||||||
|
|
||||||
|
Can't render this file because it contains an unexpected character in line 4 and column 135.
|
52
tests/test_Airodump.py
Normal file
52
tests/test_Airodump.py
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#!/usr/bin/python2.7
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import sys
|
||||||
|
sys.path.insert(0, '..')
|
||||||
|
|
||||||
|
from wifite.tools.airodump import Airodump
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
class TestAirodump(unittest.TestCase):
|
||||||
|
''' Test suite for Wifite's interaction with the Airodump tool '''
|
||||||
|
|
||||||
|
|
||||||
|
def test_airodump_weird_characters(self):
|
||||||
|
csv_filename = self.getFile('airodump-weird-ssids.csv')
|
||||||
|
targets = Airodump.get_targets_from_csv(csv_filename)
|
||||||
|
|
||||||
|
target = targets[0]
|
||||||
|
expected = 'Comma, no trailing space'
|
||||||
|
assert target.essid == expected, 'Expected ESSID (%s) but got (%s)' % (expected, target.essid)
|
||||||
|
|
||||||
|
target = targets[1]
|
||||||
|
expected = '"Quoted ESSID, Comma, no trailing spaces. "'
|
||||||
|
assert target.essid == expected, 'Expected ESSID (%s) but got (%s)' % (expected, target.essid)
|
||||||
|
|
||||||
|
target = targets[2]
|
||||||
|
expected = 'Comma, Trailing space '
|
||||||
|
assert target.essid == expected, 'Expected ESSID (%s) but got (%s)' % (expected, target.essid)
|
||||||
|
|
||||||
|
target = targets[3]
|
||||||
|
expected = '"quote" comma, trailing space '
|
||||||
|
assert target.essid == expected, 'Expected ESSID (%s) but got (%s)' % (expected, target.essid)
|
||||||
|
|
||||||
|
# Hidden access point
|
||||||
|
target = targets[4]
|
||||||
|
assert target.essid_known == False, 'ESSID full of null characters should not be known'
|
||||||
|
expected = None
|
||||||
|
assert target.essid == expected, 'Expected ESSID (%s) but got (%s)' % (expected, target.essid)
|
||||||
|
assert target.essid_len == 19, 'ESSID length shold be 19, but got %s' % target.essid_len
|
||||||
|
|
||||||
|
|
||||||
|
def getFile(self, filename):
|
||||||
|
''' Helper method to parse targets from filename '''
|
||||||
|
import os, inspect
|
||||||
|
this_file = os.path.abspath(inspect.getsourcefile(self.getFile))
|
||||||
|
this_dir = os.path.dirname(this_file)
|
||||||
|
return os.path.join(this_dir, 'files', filename)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
@@ -12,7 +12,7 @@ class Configuration(object):
|
|||||||
|
|
||||||
initialized = False # Flag indicating config has been initialized
|
initialized = False # Flag indicating config has been initialized
|
||||||
temp_dir = None # Temporary directory
|
temp_dir = None # Temporary directory
|
||||||
version = '2.1.1'
|
version = '2.1.2'
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def initialize(load_interface=True):
|
def initialize(load_interface=True):
|
||||||
|
|||||||
@@ -52,14 +52,18 @@ class Target(object):
|
|||||||
|
|
||||||
self.essid_known = True
|
self.essid_known = True
|
||||||
self.essid_len = int(fields[12].strip())
|
self.essid_len = int(fields[12].strip())
|
||||||
self.essid = fields[13].strip()
|
self.essid = fields[13]
|
||||||
if self.essid == '\\x00' * self.essid_len or self.essid.strip() == '':
|
if self.essid == '\\x00' * self.essid_len or \
|
||||||
|
self.essid == 'x00' * self.essid_len or \
|
||||||
|
self.essid.strip() == '':
|
||||||
# Don't display "\x00..." for hidden ESSIDs
|
# Don't display "\x00..." for hidden ESSIDs
|
||||||
self.essid = None # '(%s)' % self.bssid
|
self.essid = None # '(%s)' % self.bssid
|
||||||
self.essid_known = False
|
self.essid_known = False
|
||||||
|
|
||||||
self.wps = None
|
self.wps = None
|
||||||
|
|
||||||
|
self.decloaked = False # If ESSID was hidden but we decloaked it.
|
||||||
|
|
||||||
self.clients = []
|
self.clients = []
|
||||||
|
|
||||||
self.validate()
|
self.validate()
|
||||||
@@ -84,7 +88,7 @@ class Target(object):
|
|||||||
Specifically formatted for the "scanning" table view.
|
Specifically formatted for the "scanning" table view.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
max_essid_len = 25
|
max_essid_len = 24
|
||||||
essid = self.essid if self.essid_known else "(%s)" % self.bssid
|
essid = self.essid if self.essid_known else "(%s)" % self.bssid
|
||||||
# Trim ESSID (router name) if needed
|
# Trim ESSID (router name) if needed
|
||||||
if len(essid) > max_essid_len:
|
if len(essid) > max_essid_len:
|
||||||
@@ -99,6 +103,10 @@ class Target(object):
|
|||||||
# Unknown ESSID
|
# Unknown ESSID
|
||||||
essid = Color.s("{O}%s" % essid)
|
essid = Color.s("{O}%s" % essid)
|
||||||
|
|
||||||
|
# Add a "*" if we decloaked the ESSID
|
||||||
|
decloaked_char = '*' if self.decloaked else ' '
|
||||||
|
essid += Color.s("{P}%s" % decloaked_char)
|
||||||
|
|
||||||
if show_bssid:
|
if show_bssid:
|
||||||
bssid = Color.s('{O}%s ' % self.bssid)
|
bssid = Color.s('{O}%s ' % self.bssid)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class Airodump(object):
|
|||||||
|
|
||||||
# For tracking decloaked APs (previously were hidden)
|
# For tracking decloaked APs (previously were hidden)
|
||||||
self.decloaking = False
|
self.decloaking = False
|
||||||
self.decloaked_targets = []
|
self.decloaked_bssids = set()
|
||||||
self.decloaked_times = {} # Map of BSSID(str) -> epoch(int) of last deauth
|
self.decloaked_times = {} # Map of BSSID(str) -> epoch(int) of last deauth
|
||||||
|
|
||||||
|
|
||||||
@@ -161,7 +161,8 @@ class Airodump(object):
|
|||||||
if old_target.bssid != new_target.bssid: continue
|
if old_target.bssid != new_target.bssid: continue
|
||||||
if new_target.essid_known and not old_target.essid_known:
|
if new_target.essid_known and not old_target.essid_known:
|
||||||
# We decloaked a target!
|
# We decloaked a target!
|
||||||
self.decloaked_targets.append(new_target)
|
new_target.decloaked = True
|
||||||
|
self.decloaked_bssids.add(new_target.bssid)
|
||||||
|
|
||||||
if self.pid.poll() is not None:
|
if self.pid.poll() is not None:
|
||||||
raise Exception('Airodump has stopped')
|
raise Exception('Airodump has stopped')
|
||||||
@@ -185,7 +186,11 @@ class Airodump(object):
|
|||||||
if type(line) is bytes: line = line.decode('utf-8')
|
if type(line) is bytes: line = line.decode('utf-8')
|
||||||
line = line.replace('\0', '')
|
line = line.replace('\0', '')
|
||||||
lines.append(line)
|
lines.append(line)
|
||||||
csv_reader = csv.reader(lines, delimiter=',')
|
csv_reader = csv.reader(lines,
|
||||||
|
delimiter=',',
|
||||||
|
quoting=csv.QUOTE_ALL,
|
||||||
|
skipinitialspace=True,
|
||||||
|
escapechar='\\')
|
||||||
|
|
||||||
hit_clients = False
|
hit_clients = False
|
||||||
for row in csv_reader:
|
for row in csv_reader:
|
||||||
@@ -317,4 +322,3 @@ if __name__ == '__main__':
|
|||||||
Color.pl(' {G}%s %s' % (str(idx).rjust(3), target.to_str()))
|
Color.pl(' {G}%s %s' % (str(idx).rjust(3), target.to_str()))
|
||||||
|
|
||||||
Configuration.delete_temp()
|
Configuration.delete_temp()
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,10 @@ class Scanner(object):
|
|||||||
# We found the target we want
|
# We found the target we want
|
||||||
return
|
return
|
||||||
|
|
||||||
|
for target in self.targets:
|
||||||
|
if target.bssid in airodump.decloaked_bssids:
|
||||||
|
target.decloaked = True
|
||||||
|
|
||||||
self.print_targets()
|
self.print_targets()
|
||||||
|
|
||||||
target_count = len(self.targets)
|
target_count = len(self.targets)
|
||||||
@@ -61,11 +65,6 @@ class Scanner(object):
|
|||||||
outline += " {G}%d{W} target(s)," % target_count
|
outline += " {G}%d{W} target(s)," % target_count
|
||||||
outline += " {G}%d{W} client(s)." % client_count
|
outline += " {G}%d{W} client(s)." % client_count
|
||||||
outline += " {O}Ctrl+C{W} when ready "
|
outline += " {O}Ctrl+C{W} when ready "
|
||||||
decloaked = airodump.decloaked_targets
|
|
||||||
if len(decloaked) > 0:
|
|
||||||
outline += "(decloaked"
|
|
||||||
outline += " {C}%d{W} ESSIDs:" % len(decloaked)
|
|
||||||
outline += " {G}%s{W}) " % ", ".join([x.essid for x in decloaked])
|
|
||||||
Color.clear_entire_line()
|
Color.clear_entire_line()
|
||||||
Color.p(outline)
|
Color.p(outline)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user