diff --git a/wifite/__main__.py b/wifite/__main__.py index 3b2bdf2..53457cf 100755 --- a/wifite/__main__.py +++ b/wifite/__main__.py @@ -56,11 +56,11 @@ class Wifite(object): def print_banner(self): '''Displays ASCII art of the highest caliber.''' - Color.pl(r'{G} . {GR}{D} {W}{G} . {W}') - Color.pl(r'{G}.´ · .{GR}{D} {W}{G}. · `. {G}wifite {D}%s{W}' % Configuration.version) - Color.pl(r'{G}: : : {GR}{D} (¯) {W}{G} : : : {W}{D}automated wireless auditor{W}') - Color.pl(r'{G}`. · `{GR}{D} /¯\ {W}{G}´ · .´ {C}{D}https://github.com/derv82/wifite2{W}') - Color.pl(r'{G} ` {GR}{D}/¯¯¯\{W}{G} ´ {W}') + Color.pl(r' {G} . {GR}{D} {W}{G} . {W}') + Color.pl(r' {G}.´ · .{GR}{D} {W}{G}. · `. {G}wifite {D}%s{W}' % Configuration.version) + Color.pl(r' {G}: : : {GR}{D} (¯) {W}{G} : : : {W}{D}automated wireless auditor{W}') + Color.pl(r' {G}`. · `{GR}{D} /¯\ {W}{G}´ · .´ {C}{D}https://github.com/derv82/wifite2{W}') + Color.pl(r' {G} ` {GR}{D}/¯¯¯\{W}{G} ´ {W}') Color.pl('') diff --git a/wifite/model/result.py b/wifite/model/result.py index d1926f9..7dd6084 100755 --- a/wifite/model/result.py +++ b/wifite/model/result.py @@ -39,19 +39,31 @@ class CrackResult(object): def save(self): ''' Adds this crack result to the cracked file and saves it. ''' name = CrackResult.cracked_file - json = [] + saved_results = [] if os.path.exists(name): with open(name, 'r') as fid: text = fid.read() try: - json = loads(text) + saved_results = loads(text) except Exception as e: Color.pl('{!} error while loading %s: %s' % (name, str(e))) - json.append(self.to_dict()) + + # Check for duplicates + this_dict = self.to_dict() + this_dict.pop('date') + for entry in saved_results: + this_dict['date'] = entry.get('date') + if entry == this_dict: + # Skip if we already saved this BSSID+ESSID+TYPE+KEY + Color.pl('{+} {C}%s{O} already exists in {G}cracked.txt{O}, skipping.' % ( + self.essid)) + return + + saved_results.append(self.to_dict()) with open(name, 'w') as fid: - fid.write(dumps(json, indent=2)) + fid.write(dumps(saved_results, indent=2)) Color.pl('{+} saved crack result to {C}%s{W} ({G}%d total{W})' - % (name, len(json))) + % (name, len(saved_results))) @classmethod def display(cls): diff --git a/wifite/tools/john.py b/wifite/tools/john.py index d61f8c3..2fcdc96 100644 --- a/wifite/tools/john.py +++ b/wifite/tools/john.py @@ -21,27 +21,39 @@ class John(Dependency): def crack_handshake(handshake, show_command=False): john_file = HcxPcapTool.generate_john_file(handshake, show_command=show_command) + # Use `john --list=formats` to find if OpenCL or CUDA is supported. + formats_stdout = Process(['john', '--list=formats']).stdout() + if 'wpapsk-opencl' in formats_stdout: + john_format = 'wpapsk-opencl' + elif 'wpapsk-cuda' in formats_stdout: + john_format = 'wpapsk-cuda' + else: + john_format = 'wpapsk' + # Crack john file command = [ 'john', - '--format=wpapsk', # wpapsk-cuda or wpapsk-opencl + '--format', john_format, '--wordlist', Configuration.wordlist, john_file ] + if show_command: Color.pl('{+} {D}{C}Running %s{W}' % ' '.join(command)) process = Process(command) process.wait() - # Show the password (if found) + # Run again with --show to consistently get the password command = ['john', '--show', john_file] if show_command: Color.pl('{+} {D}{C}Running %s{W}' % ' '.join(command)) process = Process(command) stdout, stderr = process.get_output() - key = None - if not '0 password hashes cracked' in stdout: + # Parse password (regex doesn't work for some reason) + if '0 password hashes cracked' in stdout: + key = None + else: for line in stdout.split('\n'): if handshake.capfile in line: key = line.split(':')[1] diff --git a/wifite/util/crack.py b/wifite/util/crack.py index c30bf84..de25220 100755 --- a/wifite/util/crack.py +++ b/wifite/util/crack.py @@ -22,6 +22,8 @@ import os # TODO: Do not show handshake files that are in cracked.txt with a key (match on filename). +# TODO: --no-crack option while attacking targets (implies user will run --crack later) + class CrackHelper: '''Manages handshake retrieval, selection, and running the cracking commands.''' @@ -52,20 +54,35 @@ class CrackHelper: hs_to_crack = cls.get_user_selection(handshakes) - # Get tool - available_tools = ['aircrack', 'hashcat', 'john', 'cowpatty'] - if not Process.exists(HcxPcapTool.dependency_name): - Color.pl('{!} {R}Unable to use hashcat: {O}missing required hcxpcaptool{W}') - available_tools.remove('hashcat') - if not Process.exists(John.dependency_name): - Color.pl('{!} {R}Unable to use john: {O}missing required "john" program{W}') - available_tools.remove('john') + # Tools for cracking & their dependencies. + available_tools = { + 'aircrack': [Aircrack], + 'hashcat': [Hashcat, HcxPcapTool], + 'john': [John, HcxPcapTool], + 'cowpatty': [Cowpatty] + } + # Identify missing tools + missing_tools = [] + for tool, dependencies in available_tools.items(): + missing = [ + dep for dep in dependencies + if not Process.exists(dep.dependency_name) + ] + if len(missing) > 0: + available_tools.pop(tool) + missing_tools.append( (tool, missing) ) - Color.p('{+} Enter the {C}cracking tool{W} to use ({C}%s{W}): {G}' % ( - '{W}, {C}'.join(available_tools))) + if len(missing_tools) > 0: + Color.pl('\n{!} {O}Unavailable tools (install to enable):{W}') + for tool, deps in missing_tools: + dep_list = ', '.join([dep.dependency_name for dep in deps]) + Color.pl(' {R}* {R}%s {W}({O}%s{W})' % (tool, dep_list)) + + Color.p('\n{+} Enter the {C}cracking tool{W} to use ({C}%s{W}): {G}' % ( + '{W}, {C}'.join(available_tools.keys()))) tool_name = raw_input() if tool_name not in available_tools: - Color.pl('{!} {O}%s not found, defaulting to aircrack' % tool_name) + Color.pl('{!} {R}"%s"{O} tool not found, defaulting to {C}aircrack{W}' % tool_name) tool_name = 'aircrack' try: @@ -85,7 +102,7 @@ class CrackHelper: Color.pl('\n{!} {O}directory not found: {R}%s{W}' % hs_dir) return [] - Color.pl('\n{+} Listing captured handshakes from {C}%s{W} ...\n' % os.path.abspath(hs_dir)) + Color.pl('\n{+} Listing captured handshakes from {C}%s{W}:\n' % os.path.abspath(hs_dir)) for hs_file in os.listdir(hs_dir): if hs_file.count('_') != 3: continue @@ -146,7 +163,7 @@ class CrackHelper: Color.p(' ---') Color.p(' ' + ('-' * max_essid_len)) Color.p(' ' + ('-' * 17)) - Color.p(' ' + ('-' * 6)) + Color.p(' ' + ('-' * 5)) Color.p(' ' + ('-' * 19) + '{W}\n') # Handshakes for index, handshake in enumerate(handshakes, start=1): diff --git a/wifite/wifite.py b/wifite/wifite.py deleted file mode 100755 index 8713a7d..0000000 --- a/wifite/wifite.py +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -try: - from .config import Configuration -except (ValueError, ImportError) as e: - raise Exception('You may need to run wifite from the root directory (which includes README.md)', e) - -from .util.color import Color - -import os -import sys - - -class Wifite(object): - - def __init__(self): - ''' - Initializes Wifite. Checks for root permissions and ensures dependencies are installed. - ''' - - self.print_banner() - - Configuration.initialize(load_interface=False) - - if os.getuid() != 0: - Color.pl('{!} {R}error: {O}wifite{R} must be run as {O}root{W}') - Color.pl('{!} {R}re-run with {O}sudo{W}') - Configuration.exit_gracefully(0) - - from .tools.dependency import Dependency - Dependency.run_dependency_check() - - - def start(self): - ''' - Starts target-scan + attack loop, or launches utilities dpeending on user input. - ''' - from .model.result import CrackResult - from .model.handshake import Handshake - from .util.crack import CrackHelper - - if Configuration.show_cracked: - CrackResult.display() - - elif Configuration.check_handshake: - Handshake.check() - - elif Configuration.crack_handshake: - CrackHelper.run() - - else: - Configuration.get_monitor_mode_interface() - self.scan_and_attack() - - - def print_banner(self): - '''Displays ASCII art of the highest caliber.''' - Color.pl(r'{G} . {GR}{D} {W}{G} . {W}') - Color.pl(r'{G}.´ · .{GR}{D} {W}{G}. · `. {G}wifite {D}%s{W}' % Configuration.version) - Color.pl(r'{G}: : : {GR}{D} (¯) {W}{G} : : : {W}{D}automated wireless auditor{W}') - Color.pl(r'{G}`. · `{GR}{D} /¯\ {W}{G}´ · .´ {C}{D}https://github.com/derv82/wifite2{W}') - Color.pl(r'{G} ` {GR}{D}/¯¯¯\{W}{G} ´ {W}') - Color.pl('') - - - def scan_and_attack(self): - ''' - 1) Scans for targets, asks user to select targets - 2) Attacks each target - ''' - from .util.scanner import Scanner - from .attack.all import AttackAll - - Color.pl('') - - # Scan - s = Scanner() - targets = s.select_targets() - - # Attack - attacked_targets = AttackAll.attack_multiple(targets) - - Color.pl('\n{+} Finished attacking {C}%d{W} target(s), exiting' % attacked_targets) - - -############################################################## - - -def entry_point(): - try: - wifite = Wifite() - wifite.start() - except Exception as e: - Color.pexception(e) - Color.pl('\n{!} {R}Exiting{W}\n') - - except KeyboardInterrupt: - Color.pl('\n{!} {O}interrupted, shutting down...{W}') - - Configuration.exit_gracefully(0) - - -if __name__ == '__main__': - entry_point()