* Still not "print" option for --crack. * Checks hashcat for devices, uses --force if no devices are found. * Interrupting --crack stops entire process, not just a single crack attempt * Changed wordlist location, hopefully completes #102.
174 lines
5.5 KiB
Python
Executable File
174 lines
5.5 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
from .dependency import Dependency
|
|
from ..util.process import Process
|
|
from ..util.input import xrange
|
|
from ..config import Configuration
|
|
|
|
import os
|
|
import re
|
|
|
|
class Aircrack(Dependency):
|
|
dependency_required = True
|
|
dependency_name = 'aircrack-ng'
|
|
dependency_url = 'https://www.aircrack-ng.org/install.html'
|
|
|
|
def __init__(self, ivs_file=None):
|
|
|
|
self.cracked_file = os.path.abspath(
|
|
os.path.join(
|
|
Configuration.temp(), 'wepkey.txt'))
|
|
|
|
# Delete previous cracked files
|
|
if os.path.exists(self.cracked_file):
|
|
os.remove(self.cracked_file)
|
|
|
|
command = [
|
|
'aircrack-ng',
|
|
'-a', '1',
|
|
'-l', self.cracked_file,
|
|
]
|
|
if type(ivs_file) is str:
|
|
ivs_file = [ivs_file]
|
|
|
|
command.extend(ivs_file)
|
|
|
|
self.pid = Process(command, devnull=True)
|
|
|
|
|
|
def is_running(self):
|
|
return self.pid.poll() is None
|
|
|
|
def is_cracked(self):
|
|
return os.path.exists(self.cracked_file)
|
|
|
|
def stop(self):
|
|
''' Stops aircrack process '''
|
|
if self.pid.poll() is None:
|
|
self.pid.interrupt()
|
|
|
|
def get_key_hex_ascii(self):
|
|
if not self.is_cracked():
|
|
raise Exception('Cracked file not found')
|
|
|
|
with open(self.cracked_file, 'r') as fid:
|
|
hex_raw = fid.read()
|
|
|
|
return self._hex_and_ascii_key(hex_raw)
|
|
|
|
@staticmethod
|
|
def _hex_and_ascii_key(hex_raw):
|
|
hex_chars = []
|
|
ascii_key = ''
|
|
for index in xrange(0, len(hex_raw), 2):
|
|
byt = hex_raw[index:index+2]
|
|
hex_chars.append(byt)
|
|
byt_int = int(byt, 16)
|
|
if byt_int < 32 or byt_int > 127 or ascii_key is None:
|
|
ascii_key = None # Not printable
|
|
else:
|
|
ascii_key += chr(byt_int)
|
|
|
|
hex_key = ':'.join(hex_chars)
|
|
|
|
return (hex_key, ascii_key)
|
|
|
|
def __del__(self):
|
|
if os.path.exists(self.cracked_file):
|
|
os.remove(self.cracked_file)
|
|
|
|
|
|
@staticmethod
|
|
def crack_handshake(handshake, show_command=False):
|
|
from ..util.color import Color
|
|
from ..util.timer import Timer
|
|
'''Tries to crack a handshake. Returns WPA key if found, otherwise None.'''
|
|
|
|
key_file = Configuration.temp('wpakey.txt')
|
|
command = [
|
|
'aircrack-ng',
|
|
'-a', '2',
|
|
'-w', Configuration.wordlist,
|
|
'--bssid', handshake.bssid,
|
|
'-l', key_file,
|
|
handshake.capfile
|
|
]
|
|
if show_command:
|
|
Color.pl('{+} {D}Running: {W}{P}%s{W}' % ' '.join(command))
|
|
crack_proc = Process(command)
|
|
|
|
# Report progress of cracking
|
|
aircrack_nums_re = re.compile(r'(\d+)/(\d+) keys tested.*\(([\d.]+)\s+k/s')
|
|
aircrack_key_re = re.compile(r'Current passphrase:\s*([^\s].*[^\s])\s*$')
|
|
num_tried = num_total = 0
|
|
percent = num_kps = 0.0
|
|
eta_str = 'unknown'
|
|
current_key = ''
|
|
while crack_proc.poll() is None:
|
|
line = crack_proc.pid.stdout.readline()
|
|
match_nums = aircrack_nums_re.search(line.decode('utf-8'))
|
|
match_keys = aircrack_key_re.search(line.decode('utf-8'))
|
|
if match_nums:
|
|
num_tried = int(match_nums.group(1))
|
|
num_total = int(match_nums.group(2))
|
|
num_kps = float(match_nums.group(3))
|
|
eta_seconds = (num_total - num_tried) / num_kps
|
|
eta_str = Timer.secs_to_str(eta_seconds)
|
|
percent = 100.0 * float(num_tried) / float(num_total)
|
|
elif match_keys:
|
|
current_key = match_keys.group(1)
|
|
else:
|
|
continue
|
|
|
|
status = '\r{+} {C}Cracking WPA Handshake: %0.2f%%{W}' % percent
|
|
status += ' ETA: {C}%s{W}' % eta_str
|
|
status += ' @ {C}%0.1fkps{W}' % num_kps
|
|
#status += ' ({C}%d{W}/{C}%d{W} keys)' % (num_tried, num_total)
|
|
status += ' (current key: {C}%s{W})' % current_key
|
|
Color.clear_entire_line()
|
|
Color.p(status)
|
|
|
|
Color.pl('')
|
|
|
|
# Check crack result
|
|
if os.path.exists(key_file):
|
|
with open(key_file, 'r') as fid:
|
|
key = fid.read().strip()
|
|
os.remove(key_file)
|
|
|
|
return key
|
|
else:
|
|
return None
|
|
|
|
|
|
if __name__ == '__main__':
|
|
(hexkey, asciikey) = Aircrack._hex_and_ascii_key('A1B1C1D1E1')
|
|
assert hexkey == 'A1:B1:C1:D1:E1', 'hexkey was "%s", expected "A1:B1:C1:D1:E1"' % hexkey
|
|
assert asciikey is None, 'asciikey was "%s", expected None' % asciikey
|
|
|
|
(hexkey, asciikey) = Aircrack._hex_and_ascii_key('6162636465')
|
|
assert hexkey == '61:62:63:64:65', 'hexkey was "%s", expected "61:62:63:64:65"' % hexkey
|
|
assert asciikey == 'abcde', 'asciikey was "%s", expected "abcde"' % asciikey
|
|
|
|
from time import sleep
|
|
|
|
Configuration.initialize(False)
|
|
|
|
ivs_file = 'tests/files/wep-crackable.ivs'
|
|
print('Running aircrack on %s ...' % ivs_file)
|
|
|
|
aircrack = Aircrack(ivs_file)
|
|
while aircrack.is_running():
|
|
sleep(1)
|
|
|
|
assert aircrack.is_cracked(), 'Aircrack should have cracked %s' % ivs_file
|
|
print('aircrack process completed.')
|
|
|
|
(hexkey, asciikey) = aircrack.get_key_hex_ascii()
|
|
print('aircrack found HEX key: (%s) and ASCII key: (%s)' % (hexkey, asciikey))
|
|
assert hexkey == '75:6E:63:6C:65', 'hexkey was "%s", expected "75:6E:63:6C:65"' % hexkey
|
|
assert asciikey == 'uncle', 'asciikey was "%s", expected "uncle"' % asciikey
|
|
|
|
Configuration.exit_gracefully(0)
|