diff --git a/py/Aireplay.py b/py/Aireplay.py index b1fdda0..b955d4b 100644 --- a/py/Aireplay.py +++ b/py/Aireplay.py @@ -108,7 +108,7 @@ class Aireplay(object): Configuration.initialize() if Configuration.interface == None: raise Exception("Wireless interface must be defined (-i)") - + cmd = ['aireplay-ng'] cmd.append('--ignore-negative-one') @@ -231,7 +231,7 @@ class Aireplay(object): if __name__ == '__main__': t = WEPAttackType(4) - print t.name, type(t.name), t.value + print t.name, type(t.name), t.value t = WEPAttackType('caffelatte') print t.name, type(t.name), t.value diff --git a/py/Airodump.py b/py/Airodump.py index d2a8205..fd39eb0 100644 --- a/py/Airodump.py +++ b/py/Airodump.py @@ -7,7 +7,7 @@ from Target import Target from Client import Client from Wash import Wash -import os +import os, time class Airodump(object): ''' Wrapper around airodump-ng program ''' @@ -42,6 +42,11 @@ class Airodump(object): self.ivs_only = ivs_only self.skip_wash = skip_wash + # For tracking decloaked APs (previously were hidden) + self.decloaking = False + self.decloaked_targets = [] + self.decloaked_times = {} # Map of BSSID(str) -> epoch(int) of last deauth + def __enter__(self): ''' @@ -146,7 +151,15 @@ class Airodump(object): # Sort by power targets.sort(key=lambda x: x.power, reverse=True) + for old_target in self.targets: + for new_target in targets: + if old_target.bssid != new_target.bssid: continue + if new_target.essid_known and not old_target.essid_known: + # We decloaked a target! + self.decloaked_targets.append(new_target) + self.targets = targets + self.deauth_hidden_targets() return self.targets @@ -240,6 +253,41 @@ class Airodump(object): i += 1 return result + def deauth_hidden_targets(self): + ''' + Sends deauths (to broadcast and to each client) for all + targets (APs) that have unknown ESSIDs (hidden router names). + ''' + self.decloaking = False + # Only deauth if channel is fixed. + if self.channel is None: return + + # Reusable deauth command + deauth_cmd = [ + 'aireplay-ng', + '-0', # Deauthentication + '1', # Number of deauths to perform. + '--ignore-negative-one' + ] + for target in self.targets: + if target.essid_known: continue + now = int(time.time()) + secs_since_decloak = now - self.decloaked_times.get(target.bssid, 0) + # Decloak every AP once every 30 seconds + if secs_since_decloak < 30: continue + self.decloaking = True + self.decloaked_times[target.bssid] = now + if Configuration.verbose > 1: + from Color import Color + verbout = " [?] Deauthing %s" % target.bssid + verbout += " (broadcast & %d clients)" % len(target.clients) + Color.pe("\n{C}" + verbout + "{W}") + # Deauth broadcast + iface = Configuration.interface + Process(deauth_cmd + ['-a', target.bssid, iface]) + # Deauth clients + for client in target.clients: + Process(deauth_cmd + ['-c', client.bssid, iface]) if __name__ == '__main__': ''' Example usage. wlan0mon should be in Monitor Mode ''' diff --git a/py/AttackWPA.py b/py/AttackWPA.py index 52256e6..d59239a 100644 --- a/py/AttackWPA.py +++ b/py/AttackWPA.py @@ -36,7 +36,7 @@ class AttackWPA(Attack): target_bssid=self.target.bssid, output_file_prefix='wpa') as airodump: - Color.clear_line() + Color.clear_entire_line() Color.pattack("WPA", self.target, "Handshake capture", "Waiting for target to appear...") airodump_target = self.wait_for_target(airodump) diff --git a/py/AttackWPS.py b/py/AttackWPS.py index 8c37c91..dcc15f0 100644 --- a/py/AttackWPS.py +++ b/py/AttackWPS.py @@ -302,7 +302,7 @@ class AttackWPS(Attack): state = '{R}rate-limited{W}' if Configuration.wps_skip_rate_limit: Color.pl(state) - Color.pl('{!} {R}hit rate limit, stopping{W}\n') + Color.pl('{!} {R}hit rate limit, stopping{W}') Color.pl('{!} {O}use {R}--ignore-ratelimit{O} to ignore' + ' this kind of failure in the future{W}') break diff --git a/py/Color.py b/py/Color.py index 9331389..2ea7b06 100644 --- a/py/Color.py +++ b/py/Color.py @@ -74,6 +74,12 @@ class Color(object): sys.stdout.flush() Color.last_sameline_length = 0 + @staticmethod + def clear_entire_line(): + import os + (rows, columns) = os.popen('stty size', 'r').read().split() + Color.p("\r" + (" " * int(columns)) + "\r") + @staticmethod def pattack(attack_type, target, attack_name, progress): ''' diff --git a/py/Scanner.py b/py/Scanner.py index 6543a05..79d4b73 100644 --- a/py/Scanner.py +++ b/py/Scanner.py @@ -49,11 +49,20 @@ class Scanner(object): client_count = sum( [len(t.clients) for t in self.targets]) - Color.p( - '\r{+} scanning, found' + - ' {G}%d{W} target(s),' % target_count + - ' {G}%d{W} client(s).' % client_count + - ' {O}Ctrl+C{W} when ready') + outline = "\r{+} Scanning" + if airodump.decloaking: + outline += " & decloaking" + outline += ". Found" + outline += " {G}%d{W} target(s)," % target_count + outline += " {G}%d{W} client(s)." % client_count + 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.p(outline) sleep(1) except KeyboardInterrupt: pass @@ -118,6 +127,7 @@ class Scanner(object): Target.print_header() for (index, target) in enumerate(self.targets): index += 1 + Color.clear_entire_line() Color.pl(' {G}%s %s' % (str(index).rjust(3), target)) @staticmethod @@ -126,6 +136,12 @@ class Scanner(object): (rows, columns) = os.popen('stty size', 'r').read().split() return int(rows) + @staticmethod + def get_terminal_width(): + import os + (rows, columns) = os.popen('stty size', 'r').read().split() + return int(columns) + def select_targets(self): ''' Asks user to select target(s) ''' @@ -139,6 +155,7 @@ class Scanner(object): + " or you may have issues with your wifi card") self.print_targets() + Color.clear_entire_line() input_str = '{+} select target(s)' input_str += ' ({G}1-%d{W})' % len(self.targets) input_str += ' separated by commas, dashes'