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:
derv82
2018-04-06 18:44:46 -04:00
parent cef4c451fe
commit 20ea673a3d
6 changed files with 89 additions and 13 deletions

View 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
View 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()

View File

@@ -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):

View File

@@ -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:

View File

@@ -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()

View File

@@ -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)