#!/bin/bash
# Skynet - An automated WEP Cracking tool
# Copyright (C) 2008  Adam & Vyrus of DC949
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
#
# Description:
#      This is a script which will work with skynet.  Its purpose is
# to figure out what networks are nearby, and what's WEP encrypted, 
# and then let the user choose which one they'd like to crack.  Once
# they make the choice, it'll launch skynet.sh if it's in the $PATH.
# If not in the $PATH, it'll just echo the command so the user can run it.
#
# Feel free to report any bugs to the authors:
# adam@dc949.org and/or vyrus@dc949.org
#
# Or just drop by the site and hit up our forums at http://www.dc949.org
#
tmpDir=/tmp
ENABLE_COLORS="true"

function isInPath() {
  which $1 &> /dev/null
  if [[ $? -ne 0 ]]; then
    if [[ "$programsNotInPath" == "" ]]; then
      programsNotInPath=$1
    else
      programsNotInPath="${programsNotInPath}, $1"
    fi
  fi
}

function echoMessage() {
  if [[ "$ENABLE_COLORS" == "true" ]]; then
    tput setaf 2; tput setab 0;
  fi
  echo $*
  if [[ "$ENABLE_COLORS" == "true" ]]; then
    tput sgr0
  fi
}

function echoError() {
  if [[ "$ENABLE_COLORS" == "true" ]]; then
    tput setaf 1; tput setab 0;
  fi
  echo $*
  if [[ "$ENABLE_COLORS" == "true" ]]; then
    tput sgr0
  fi
}

function echoWarning() {
  if [[ "$ENABLE_COLORS" == "true" ]]; then
    tput setaf 3; tput setab 0;
  fi
  echo $*
  if [[ "$ENABLE_COLORS" == "true" ]]; then
    tput sgr0
  fi
}

function echoPrompt() {
  if [[ "$ENABLE_COLORS" == "true" ]]; then
    tput setaf 4; tput setab 0;
  fi
  echo $*
  if [[ "$ENABLE_COLORS" == "true" ]]; then
    tput sgr0
  fi
}

# loop through command line args
for arg in $*; do
  if [[ "${arg}" == "--interface="* ]]; then
    INTERFACE=${arg##--interface=}
  fi
  if [[ "${arg}" == "--help" ]]; then
    echo "Usage: $0 [--interface=<interface>] [--help] [--no-color]"
    echo
    echo "    --no-color will disable colors, which is necessary for devices like the N900"
    exit 1
  fi
  if [[ "${arg}" == "--no-color" ]]; then
    ENABLE_COLORS="false"
  fi
done

isInPath ls;
isInPath rm;
isInPath echo;
isInPath grep;
isInPath awk;
isInPath cut;
isInPath sed;
isInPath yes;
isInPath tee;
isInPath sleep;
isInPath ifconfig;
isInPath iwconfig;

if [[ "$programsNotInPath" != "" ]]; then
  echoError "***ERROR: Programs not in path: $programsNotInPath";
  exit
fi

# If the interface is specified, we make sure it's in managed mode, as some cards
# can not scan when in monitor mode (yes, that's lame, but it is what it is...)
if [[ "$INTERFACE" != "" ]]; then
	ifconfig $INTERFACE down
	iwconfig $INTERFACE mode managed
	ifconfig $INTERFACE up
fi

iwlist $INTERFACE scanning 2> /dev/null | grep -v Mode | grep -v 'Mb/s' | grep -v Extra | \
awk '
$1 ~ /ESSID/ { print "ESSID|" $0 }
$0 ~ /Address/ { print "\nBSSID|" $5 }
$1 ~ /Frequency/ { print "Channel|" $4 }
$0 ~ /Encryption/ { print $1 $2 }
$1 ~ /Quality/ { print $1 }
$0 ~ /(WPA)|(TKIP)|(PSK)/ { print $1 $2 $3 $4 $5 }
' | sed 's/[ ]*ESSID://g' | sed 's/)$//g' | sed 's/"//g' | sed 's/Channel=/Channel /g' | \
sed 's/Quality=/Quality|/g' | sed 's/Encryptionkey:/Encryption|/g' \
| \
awk -F '|' 'BEGIN {
  #print "ESSID|BSSID|CHANNEL|QUALITY|ENCRYPTION"
}
{
  if($1 == "BSSID")
    bssid=$2;
  if($1 == "ESSID")
    essid=$2
  if($1 == "Channel")
    channel=$2
  if($1 == "Encryption")
    encryption=$2
  if($1 == "Quality")
    quality=$2

  # this should be true every time we have all our data,
  # however we do not know if the next line is a new record or a message about WPA
  if(bssid != previous && encryption != "") {
    # save this record, and make sure we do not move on to the next one until all data is captured
    previous_record=essid "|" bssid "|" channel "|" quality "|" encryption;

    # if this is the second time in a row we hit this loop, we should either print or ignore
    if(second_time == "true") {
      # if the line after we have all the info is IE, it is WPA so we skip it; else print it
      if($1 !~ /^IE:/ && encryption == "on")
        print previous_record;
      else
        previous_record="";

      # make sure we do not come into the "maybe we need to print something" block again
      previous=bssid;
      encryption="";
      second_time="";
    } else {
      second_time="true";
    }
  }
}
END {
  if(previous_record != "")
    print previous_record;
}' | awk -F '|' -v "arguments=$*" \
'BEGIN {
  interface=substr(arguments,1,index(arguments,";")-1);
  enable_colors=substr(arguments,index(arguments,";")+1);
}
{
  print $4 "\tskynet.sh --essid=" $1 " --bssid=" $2 " --channel=" $3 " " arguments
}' \
| sort -n -r -t '/' | uniq | awk '{print NR ".) " $0}' > ${tmpDir}/skynetHelper.menu

if [[ ! -s ${tmpDir}/skynetHelper.menu ]]; then
  # nothing found, tell the user and exit
  echo "No APs found"
  rm -f ${tmpDir}/skynetHelper.menu
  exit
fi

cat ${tmpDir}/skynetHelper.menu
echo ""
echoPrompt -n "Enter the number corresponding to the AP you'd like to audit: "
read choice

if [ ${choice} -eq ${choice} 2> /dev/null ]; then
  if [[ ${choice} != "" ]]; then
    line=`head -n ${choice} ${tmpDir}/skynetHelper.menu | tail -n 1`
    cmd=`echo ${line} | sed 's/.*\(skynet\.sh\)/\1/g'`
    echo "Running command: ${cmd}"
    ${cmd}
  else
    echoError ""
    echoError "***ERROR: Why would you do that?"
    echoError ""
  fi
else
  echoError "***ERROR: ${choice} is not a number.  Exiting..."
fi

rm -f ${tmpDir}/skynetHelper.menu

