diff --git a/wifite/config.py b/wifite/config.py index 47a4c8f..0d38830 100755 --- a/wifite/config.py +++ b/wifite/config.py @@ -82,6 +82,7 @@ class Configuration(object): cls.pmkid_timeout = 30 # Time to wait for PMKID capture # Default dictionary for cracking + cls.cracked_file = 'cracked.txt' cls.wordlist = None wordlists = [ './wordlist-top4800-probable.txt', # Local file (ran from cloned repo) diff --git a/wifite/model/result.py b/wifite/model/result.py index 7dd6084..dcb4089 100755 --- a/wifite/model/result.py +++ b/wifite/model/result.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- from ..util.color import Color +from ..config import Configuration import os import time @@ -11,7 +12,7 @@ class CrackResult(object): ''' Abstract class containing results from a crack session ''' # File to save cracks to, in PWD - cracked_file = 'cracked.txt' + cracked_file = Configuration.cracked_file def __init__(self): self.date = int(time.time()) @@ -55,8 +56,8 @@ class CrackResult(object): 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)) + Color.pl('{+} {C}%s{O} already exists in {G}%s{O}, skipping.' % ( + self.essid, Configuration.cracked_file)) return saved_results.append(self.to_dict()) @@ -67,7 +68,7 @@ class CrackResult(object): @classmethod def display(cls): - ''' Show cracked targets from cracked.txt ''' + ''' Show cracked targets from cracked file ''' name = cls.cracked_file if not os.path.exists(name): Color.pl('{!} {O}file {C}%s{O} not found{W}' % name) diff --git a/wifite/util/crack.py b/wifite/util/crack.py index 5a5b6a0..b28f008 100755 --- a/wifite/util/crack.py +++ b/wifite/util/crack.py @@ -13,15 +13,13 @@ from ..tools.cowpatty import Cowpatty from ..tools.hashcat import Hashcat, HcxPcapTool from ..tools.john import John -from datetime import datetime +from json import loads import os # TODO: Bring back the 'print' option, for easy copy/pasting. Just one-liners people can paste into terminal. -# 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: @@ -32,7 +30,6 @@ class CrackHelper: 'PMKID': 'PMKID Hash' } - @classmethod def run(cls): Configuration.initialize(False) @@ -53,7 +50,7 @@ class CrackHelper: return hs_to_crack = cls.get_user_selection(handshakes) - any_pmkid = any([hs['type'] == 'PMKID' for hs in hs_to_crack]) + all_pmkid = all([hs['type'] == 'PMKID' for hs in hs_to_crack]) # Tools for cracking & their dependencies. available_tools = { @@ -79,26 +76,48 @@ class CrackHelper: 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('{!} {R}"%s"{O} tool not found, defaulting to {C}aircrack{W}' % tool_name) - tool_name = 'aircrack' - elif any_pmkid and tool_name != 'hashcat': + if all_pmkid: Color.pl('{!} {O}Note: PMKID hashes will be cracked using {C}hashcat{W}') + tool_name = 'hashcat' + else: + 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('{!} {R}"%s"{O} tool not found, defaulting to {C}aircrack{W}' % tool_name) + tool_name = 'aircrack' try: for hs in hs_to_crack: + if tool_name != 'hashcat' and hs['type'] == 'PMKID': + if 'hashcat' in missing_tools: + Color.pl('{!} {O}Hashcat is missing, therefore we cannot crack PMKID hash{W}') + else: + cls.crack(hs, 'hashcat') cls.crack(hs, tool_name) except KeyboardInterrupt: Color.pl('\n{!} {O}Interrupted{W}') + @classmethod + def is_cracked(cls, file): + if not os.path.exists(Configuration.cracked_file): + return False + with open(Configuration.cracked_file) as f: + json = loads(f.read()) + if json is None: + return False + for result in json: + for k in result.keys(): + v = result[k] + if 'file' in k and os.path.basename(v) == file: + return True + return False + @classmethod def get_handshakes(cls): handshakes = [] - skipped_pmkid_files = 0 + skipped_pmkid_files = skipped_cracked_files = 0 hs_dir = Configuration.wpa_handshake_dir if not os.path.exists(hs_dir) or not os.path.isdir(hs_dir): @@ -110,6 +129,10 @@ class CrackHelper: if hs_file.count('_') != 3: continue + if cls.is_cracked(hs_file): + skipped_cracked_files += 1 + continue + if hs_file.endswith('.cap'): # WPA Handshake hs_type = '4-WAY' @@ -148,7 +171,9 @@ class CrackHelper: handshakes.append(handshake) if skipped_pmkid_files > 0: - Color.pl('{!} {O}Skipping %d {R}*.16800{O} files because {R}hashcat{O} is missing.' % skipped_pmkid_files) + Color.pl('{!} {O}Skipping %d {R}*.16800{O} files because {R}hashcat{O} is missing.\n' % skipped_pmkid_files) + if skipped_cracked_files > 0: + Color.pl('{!} {O}Skipping %d already cracked files.\n' % skipped_cracked_files) # Sort by Date (Descending) return sorted(handshakes, key=lambda x: x.get('date'), reverse=True) @@ -170,8 +195,6 @@ class CrackHelper: Color.p(' ' + ('-' * 19) + '{W}\n') # Handshakes for index, handshake in enumerate(handshakes, start=1): - bssid = handshake['bssid'] - date = handshake['date'] Color.p(' {G}%s{W}' % str(index).rjust(3)) Color.p(' {C}%s{W}' % handshake['essid'].ljust(max_essid_len)) Color.p(' {O}%s{W}' % handshake['bssid'].ljust(17)) @@ -208,7 +231,7 @@ class CrackHelper: cls.TYPES[hs['type']], hs['essid'], hs['bssid'])) if hs['type'] == 'PMKID': - crack_result = cls.crack_pmkid(hs, tool) + crack_result = cls.crack_pmkid(hs) elif hs['type'] == '4-WAY': crack_result = cls.crack_4way(hs, tool) else: @@ -253,7 +276,7 @@ class CrackHelper: @classmethod - def crack_pmkid(cls, hs, tool_name): + def crack_pmkid(cls, hs): key = Hashcat.crack_pmkid(hs['filename'], verbose=True) if key is not None: