From e17da1c74714d66928caf539ab81563e782b4939 Mon Sep 17 00:00:00 2001 From: s0lst1c3 Date: Tue, 28 Mar 2017 07:34:23 -0400 Subject: [PATCH 1/4] Fixed indentation caused by mixing tabs and spaces. Project now uses spaces only. Fixed import statements to work with modern versions of Scapy. Removed unused imports. Psyco is no longer maintained and does not support Python 2.7. Removed from project in favor of PyPy. Code cleanup and optimizations. Project now uses the newer argparse module instead of getopt to parse command line arguments. Input validation is now done through argparse as much as possible. Added utils.py file containing commonly used utility functions. Added include guard to all files. Added pip requirements file. Updated README. --- AUTHORS | 1 + Changelog | 13 ++ README | 154 ------------------ README.md | 158 +++++++++++++++++++ pip.req | 0 utils.py | 49 ++++++ wifiarp.py | 357 +++++++++++++++++++---------------------- wifidns.py | 404 +++++++++++++++++++++-------------------------- wifiping.py | 383 +++++++++++++++++++++----------------------- wifitap.py | 446 ++++++++++++++++++++++++---------------------------- 10 files changed, 951 insertions(+), 1014 deletions(-) delete mode 100644 README create mode 100644 README.md create mode 100644 pip.req create mode 100644 utils.py diff --git a/AUTHORS b/AUTHORS index a22d0e7..6cdcc4a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,2 +1,3 @@ Cedric Blancher Oliver Lavery +Gabriel Ryan diff --git a/Changelog b/Changelog index 34e9e78..cd2f78a 100644 --- a/Changelog +++ b/Changelog @@ -44,3 +44,16 @@ 0.4.1 - Updated to use modern scapy and work with Linux radiotap headers Oliver Lavery, Gotham Digital Science (olavery@gdssecurity.com) + +0.4.2 - Gabriel Ryan, Gotham Digital Science (gryan@gdssecurity.com), March 28th 2017 + Fixed indentation caused by mixing tabs and spaces. Project now uses spaces only. + Fixed import statements to work with modern versions of Scapy. + Removed unused imports. + Psyco is no longer maintained and does not support Python 2.7. Removed from project in favor of PyPy. + Code cleanup and optimizations. + Project now uses the newer argparse module instead of getopt to parse command line arguments. + Input validation is now done through argparse as much as possible. + Added utils.py file containing commonly used utility functions. + Added include guard to all files. + Added pip requirements file. + Updated README. diff --git a/README b/README deleted file mode 100644 index 75a2307..0000000 --- a/README +++ /dev/null @@ -1,154 +0,0 @@ -######################################### -# -# wifitap.py --- WiFi injection tool through tun/tap device -# Cedric Blancher -# -# http://sid.rstack.org/index.php/Wifitap (french) -# http://sid.rstack.org/index.php/Wifitap_EN (english) -# -######################################### - -This program is a proof of concept tool allowing WiFi communications using -traffic injection. -You'll need: - - . Python >= 2.2 - . Psyco Python optimizer (optional) - . Philippe Biondi's Scapy - . Injection ready wireless adapter - -It's been tested on GNU/Linux using Atheros chipset based adapter with patched -Madwifi driver and Intersil Prism GT Full MACchipset with Prism54 driver. It -should as well work with Prism2/2.5/3 chipset hostap driver or wlan-ng driver, -Ralink rt2500/2750 chipset using rt2500 driver and Realtek RTL8180 chipset -using rtl8180-sa2400 driver. - -I didn't take time to test Prism2/2.5/3 support and don't have Ralink or Realtek -based hardware for testing. By the way, I would be glad to have feedback for -Wifitap attempts with thoses chipsets. - -Drivers patches are written by Christophe Devine and updated by Aircrack-ng -people. For details about drivers patch and installation, see PATCHING file. - - -To get wifitap work on other Unix operating systems than GNU/Linux, you have to -install pcap or dnet wrappers for Python so Scapy can work (see -http://www.secdev.org/projects/scapy/portability.html). Then, and it's the most -important part, you have to find a wireless adapter driver that supports raw -wireless traffic injection if any. - - -NB : Python is so slow... - - -o Getting Wifitap ;) - - Wifitap is available at: - - http://sid.rstack.org/index.php/Wifitap (french) - http://sid.rstack.org/index.php/Wifitap_EN (english) - - Lastest version is downloadable at: - - http://sid.rstack.org/code/wifitap.tgz - - Repository available at: - - http://sid.rstack.org/code/wifitap/ - - -o Getting Scapy - - A working Scapy version is attached, so Wifitap is ready to work. - However, you can get a more featured version of the tool at: - - http://www.secdev.org/projects/scapy/ - - Download "work-in-progress" version or (better) use provided version... - - -o Preparing WiFi adapter - - Download, patch and install driver (see PATCHING). - - Supposing channel is 11: - - ~# iwconfig $IFACE mode monitor channel 11 - ~# ifconfig $IFACE up promisc - - NB: Atheros driver Madwifi requires specific configuration to get driver - in promisc mode and/or activate traffic injection. See website - (http://www.madwifi.org/) for details if you use madwifi-ng or - madwifi-old. - -o Launching Wifitap - - ~# ./wifitap.py -b - - A wj0 interface will be created that needs to be configured as a - regular interface, with optional MAC address specification: - - ~# ifconfig wj0 [hw ether ] 192.168.1.1 [mtu ] - - -o Using Wifitap - - Now, you can us wj0 interface just as a usual interface to communicate - with your prefered applications and tools, according to system routing - table :) - - -o Wifitap command line arguments - - Usage : wifitap -b [-o ] [-i [-s ] - [-w [-k ]] [-d [-v]] [-h] - - -b Specifies BSSID in ususal 6 hex digits MAC address format: - . 00:01:02:03:04:05 - - -o Specifies output WiFi interface for frames injection - - -i Specifies input WiFi interface for frames sniffing - - -s Specifies source MAC address - . 00:01:02:03:04:05 - - -w Activates WEP encryption/decryption with specified WEP key - Key can be given using following formats: - . 0102030405 or 0102030405060708090a0b0c0d - . 01:02:03:04:05 or - 01:02:03:04:05:06:07:08:09:0a:0b:0c:0d - . 0102-0304-05 or 0102-0304-0506-0708-090a-0b0c-0d - - -k Specifies WEP key id, from 0 to 3 - - -d Activates debugging - - -v Increases debugging verbosity - - -h Help screen - -o Latest libpcap fully supports Wi-Fi specific headers, typically Prism Headers. - However, if your system uses old libpcap, you will need to apply provided - patch: - - patch -p0 < prismheaders.patch - - It will add a flag (-p) to tell Wifitap to shift 144 bits of Prism Headers to - access 802.11 frame. - - -######################################### -# -# Copyright (C) 2005 Cedric Blancher -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation; version 2. -# -# 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. -# -######################################### diff --git a/README.md b/README.md new file mode 100644 index 0000000..f88240f --- /dev/null +++ b/README.md @@ -0,0 +1,158 @@ +Wifitap +======= + + ######################################### + # + # wifitap.py --- WiFi injection tool through tun/tap device + # Cedric Blancher + # + # http://sid.rstack.org/index.php/Wifitap (french) + # http://sid.rstack.org/index.php/Wifitap_EN (english) + # + ######################################### + +This program is a proof of concept tool allowing WiFi communications using +traffic injection. + +You'll need: + + . Python >= 2.2 + . Philippe Biondi's Scapy + . Injection ready wireless adapter + +It's been tested on GNU/Linux using Atheros chipset based adapter with patched +Madwifi driver and Intersil Prism GT Full MACchipset with Prism54 driver. It +should as well work with Prism2/2.5/3 chipset hostap driver or wlan-ng driver, +Ralink rt2500/2750 chipset using rt2500 driver and Realtek RTL8180 chipset +using rtl8180-sa2400 driver. + +I didn't take time to test Prism2/2.5/3 support and don't have Ralink or Realtek +based hardware for testing. By the way, I would be glad to have feedback for +Wifitap attempts with thoses chipsets. + +Drivers patches are written by Christophe Devine and updated by Aircrack-ng +people. For details about drivers patch and installation, see PATCHING file. + +To get wifitap work on other Unix operating systems than GNU/Linux, you have to +install pcap or dnet wrappers for Python so Scapy can work (see +http://www.secdev.org/projects/scapy/portability.html). Then, and it's the most +important part, you have to find a wireless adapter driver that supports raw +wireless traffic injection if any. + + * [Setup Guide](#setup-guide) + * [Getting Wifitap ;)](#getting-wifitap-) + * [Installing Dependencies](#installing-dependencies) + * [Usage Guide](#usage-guide) + * [Launching Wifitap](#launching-wifitap) + * [Wifitap Command Line Arguments](#wifitap-command-line-arguments) + +Setup Guide +=========== + +Getting Wifitap ;) +------------------ + +The latest Wifitap can be obtained from this Git repo. + +Older versions of Wifitap are available at the following locations: + +- [http://sid.rstack.org/index.php/Wifitap (french)](http://sid.rstack.org/index.php/Wifitap) +- [http://sid.rstack.org/index.php/Wifitap\_EN (english)](http://sid.rstack.org/index.php/Wifitap_EN) + + + +Installing Dependencies +----------------------- + +Python dependencies are enumerated in `pip.req`, can be installed using the pip as shown below. + + pip install -r pip.req + +Wifitap's most important dependency is Scapy, which you should check out because it's totally awesome: + + - [http://www.secdev.org/projects/scapy/](http://www.secdev.org/projects/scapy/) + + + +o Preparing WiFi adapter + + Download, patch and install driver (see PATCHING). + + Supposing channel is 11: + + ~# iwconfig $IFACE mode monitor channel 11 + ~# ifconfig $IFACE up promisc + + NB: Atheros driver Madwifi requires specific configuration to get driver + in promisc mode and/or activate traffic injection. See website + (http://www.madwifi.org/) for details if you use madwifi-ng or + madwifi-old. + +Usage Guide +=========== + +Launching Wifitap +----------------- + +Before you start, make sure your wireless interface is in monitor mode. In the commands shown below, substitute "wlan0" for the name of your wireless interface. + + ~# ifconfig wlan0 down + ~# iw dev wlan0 set monitor none + ~# ifconfig wlan0 up promisc + +To launch Wifitap with basic options, use the following command: + + ~# ./wifitap.py -b + +This will create a wj0 interface. Next, you'll need to configure this new interface using the following shown below. Note that you can optionally specify the MAC in the following command. + + ~# ifconfig wj0 [hw ether ] 192.168.1.1 [mtu ] + +You'll now be able to use your newly created wj0 interface as if it were normal network interface, according to your system routing tabl, according to your system routing table. :) + + +Wifitap Command Line Arguments +------------------------------ + + Usage : wifitap -b [-o ] [-i [-s ] + [-w [-k ]] [-d [-v]] [-h] + + -b Specifies BSSID in ususal 6 hex digits MAC address format: + . 00:01:02:03:04:05 + + -o Specifies output WiFi interface for frames injection + + -i Specifies input WiFi interface for frames sniffing + + -s Specifies source MAC address + . 00:01:02:03:04:05 + + -w Activates WEP encryption/decryption with specified WEP key + Key can be given using following formats: + . 0102030405 or 0102030405060708090a0b0c0d + . 01:02:03:04:05 or + 01:02:03:04:05:06:07:08:09:0a:0b:0c:0d + . 0102-0304-05 or 0102-0304-0506-0708-090a-0b0c-0d + + -k Specifies WEP key id, from 0 to 3 + + -d Activates debugging + + -v Increases debugging verbosity + + -h Help screen + + ######################################### + # + # Copyright (C) 2005 Cedric Blancher + # + # This program is free software; you can redistribute it and/or modify it + # under the terms of the GNU General Public License version 2 as + # published by the Free Software Foundation; version 2. + # + # 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. + # + ######################################### diff --git a/pip.req b/pip.req new file mode 100644 index 0000000..e69de29 diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..c5b47b2 --- /dev/null +++ b/utils.py @@ -0,0 +1,49 @@ +import re +import argparse + +def parse_wep_key(wepkey, keyid): + + print wepkey + + # Match and parse WEP key + tmp_key = "" + if re.match('^([0-9a-fA-F]{2}){5}$', wepkey) or re.match ('^([0-9a-fA-F]{2}){13}$', wepkey): + tmp_key = wepkey + elif re.match('^([0-9a-fA-F]{2}[:]){4}[0-9a-fA-F]{2}$', wepkey) or re.match('^([0-9a-fA-F]{2}[:]){12}[0-9a-fA-F]{2}$', wepkey): + tmp_key = re.sub(':', '', wepkey) + elif re.match ('^([0-9a-fA-F]{4}[-]){2}[0-9a-fA-F]{2}$', wepkey) or re.match ('^([0-9a-fA-F]{4}[-]){6}[0-9a-fA-F]{2}$', wepkey): + tmp_key = re.sub('-', '', wepkey) + else: + return None + g = lambda x: chr(int(tmp_key[::2][x],16)*16+int(tmp_key[1::2][x],16)) + + conf_wepkey = '' + for i in range(len(tmp_key)/2): + conf_wepkey += g(i) + + return conf_wepkey + +def sanitize_bssid(bssid): + + # Match and parse BSSID + if re.match('^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$', bssid): + return bssid.lower() + + msg = 'Invalid bssid.' + raise argparse.ArgumentTypeError(msg) + +def sanitize_smac(smac): + + if type(smac) == str and re.match('^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$', smac): + return smac.lower() + + msg = 'Invalid SMAC.' + raise argparse.ArgumentTypeError(msg) + +def sanitize_ipdns(ipdns): + + if re.match('^(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])$', ipdns): + return ipdns + + msg = 'Error: Wrong IP address' + raise argparse.ArgumentTypeError(msg) diff --git a/wifiarp.py b/wifiarp.py index a4ceac1..17c88c2 100755 --- a/wifiarp.py +++ b/wifiarp.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python +#!/usr/bin/env python ######################################## # @@ -17,200 +17,173 @@ # ######################################### -import os,sys,getopt,struct,re,string, logging - -# Import Psyco if available to speed up execution -try: - import psyco - psyco.full() -except ImportError: - print "Psyco optimizer not installed, running anyway..." - pass +import os +import sys +import argparse +import struct +import logging +import utils from socket import * from fcntl import ioctl from select import select logging.getLogger("scapy").setLevel(1) -from scapy.all import Raw,Ether,PrismHeader,Dot11,Dot11WEP,LLC,SNAP,sendp,conf - -# We want to build an ICMP Echo Request answering machine - -from scapy import ARP - -IN_IFACE = "wlan0" -OUT_IFACE = "wlan0" -WEP = 0 -KEYID = 0 -DEBUG = 0 -VERB = 0 -BSSID = "" -WEPKEY = "" -HWSRC = "" - - -def usage(status=0): - print "Usage: wifitap -b -s [-o ] [-i ]" - print " [-w [-k ]] [-d [-v]]" - print " [-h]" - print " -b specify BSSID for injection" - print " -s specify source MAC address for 802.11 and ARP headers" - print " -o specify interface for injection (default: wlan0)" - print " -w WEP mode and key" - print " -k WEP key id (default: 0)" - print " -d activate debug" - print " -v verbose debugging" - print " -h this so helpful output" - sys.exit(status) - -opts = getopt.getopt(sys.argv[1:],"b:o:i:s:w:k:dvh") - -for opt,optarg in opts[0]: - if opt == "-b": - BSSID = optarg - elif opt == "-o": - OUT_IFACE = optarg - elif opt == "-i": - IN_IFACE = optarg - elif opt == "-s": - HWSRC = optarg - elif opt == "-w": - WEP = 1 - WEPKEY = optarg - elif opt == "-k": - KEYID = int(optarg) - elif opt == "-d": - DEBUG = 1 - elif opt == "-v": - VERB = 1 - elif opt == "-h": - usage() - -if not BSSID: - print "\nError: BSSID not defined\n" - usage() - -# Match and parse BSSID -if re.match('^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$', BSSID): - BSSID = BSSID.lower() -else: - print "\nError: Wrong format for BSSID\n" - usage () - -if not HWSRC: - print "\nError: HWSRC not defined\n" - usage() - -# Match and parse HWSRC -if re.match('^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$', HWSRC): - HWSRC = HWSRC.lower() -else: - print "\nError: Wrong format for HWSRC\n" - usage () - -print "IN_IFACE: %s" % IN_IFACE -print "OUT_IFACE: %s" % OUT_IFACE -print "BSSID: %s" % BSSID -print "HWSRC: %s" % HWSRC - -if WEP: - # Match and parse WEP key - tmp_key = "" - if re.match('^([0-9a-fA-F]{2}){5}$', WEPKEY) or re.match ('^([0-9a-fA-F]{2}){13}$', WEPKEY): - tmp_key = WEPKEY - elif re.match('^([0-9a-fA-F]{2}[:]){4}[0-9a-fA-F]{2}$', WEPKEY) or re.match('^([0-9a-fA-F]{2}[:]){12}[0-9a-fA-F]{2}$', WEPKEY): - tmp_key = re.sub(':', '', WEPKEY) - elif re.match ('^([0-9a-fA-F]{4}[-]){2}[0-9a-fA-F]{2}$', WEPKEY) or re.match ('^([0-9a-fA-F]{4}[-]){6}[0-9a-fA-F]{2}$', WEPKEY): - tmp_key = re.sub('-', '', WEPKEY) - else: - print "\nError : Wrong format for WEP key\n" - usage() - g = lambda x: chr(int(tmp_key[::2][x],16)*16+int(tmp_key[1::2][x],16)) - for i in range(len(tmp_key)/2): - conf.wepkey += g(i) - print "WEP key: %s (%dbits)" % (WEPKEY, len(tmp_key)*4) - if KEYID > 3 or KEYID < 0: - print "Key id: %s (defaulted to 0 due to wrong -k argument)" % KEYID - KEYID = 0 - else: - print "Key id: %s" % KEYID -else: - if KEYID != 0: - print "WEP not activated, key id ignored" - -if not DEBUG: - if VERB: - print "DEBUG not activated, verbosity ignored" -else: - print "DEBUG activated" - if VERB: - print "Verbose debugging" - -conf.iface = OUT_IFACE - -# Here we put a BPF filter so only 802.11 Data/to-DS frames are captured -s = conf.L2listen(iface = IN_IFACE, - filter = "link[0]&0xc == 8 and link[1]&0xf == 1") - -# Speed optimization si Scapy does not have to parse payloads -ARP.payload_guess=[] - -try: - while 1: - dot11_frame = s.recv(2346) - - # WEP handling is automagicly done by Scapy if conf.wepkey is set - # Nothing to do to decrypt (although not yet tested) - # WEP frames have Dot11WEP layer, others don't - if DEBUG and VERB: - if dot11_frame.haslayer(Dot11WEP): # WEP frame - os.write(1,"Received WEP from %s\n" % IN_IFACE) - else: # Cleartext frame - os.write(1,"Received from %s\n" % IN_IFACE) - os.write(1,"%s\n" % dot11_frame.summary()) - - if dot11_frame.getlayer(Dot11).addr1 != BSSID: - continue - - # Identifying ARP Requests - if dot11_frame.haslayer(ARP) and dot11_frame.getlayer(ARP).op == 1: - if DEBUG: - os.write(1,"Received ARP Request on %s\n" % IN_IFACE) - if VERB: - os.write(1,"%s\n" % dot11_frame.summary()) - - # Building ARP Reply answer for injection - dot11_answer = RadioTap()/Dot11( - type = "Data", - FCfield = "from-DS", - addr1 = dot11_frame.getlayer(Dot11).addr2, - addr2 = BSSID) - dot11_answer.addr3 = HWSRC - if WEP: - dot11_answer.FCfield |= 0x40 - dot11_answer /= Dot11WEP( - iv = "111", - keyid = KEYID) - dot11_answer /= LLC(ctrl=3)/SNAP()/ARP( - op = "is-at", - hwsrc = HWSRC, - psrc = dot11_frame.getlayer(ARP).pdst, - hwdst = dot11_frame.getlayer(ARP).hwsrc, - pdst = dot11_frame.getlayer(ARP).psrc) - dot11_answer /= dot11_frame.getlayer(ARP).payload - - if DEBUG: - os.write(1,"Sending ARP Reply on %s\n" % OUT_IFACE) - if VERB: - os.write(1,"%s\n" % dot11_answer.summary()) - - # Frame injection : - sendp(dot11_answer,verbose=0) # Send frame - -# Program killed -except KeyboardInterrupt: - print "Stopped by user." - -s.close() - -sys.exit() +from scapy.all import Raw,Ether,PrismHeader,Dot11,Dot11WEP,LLC,SNAP,sendp,conf,ARP + +def setup(): + + global conf + + parser = argparse.ArgumentParser() + parser.add_argument('-b', + dest='bssid', + type=utils.sanitize_bssid, + required=True, + help='Specify BSSID for injection') + + parser.add_argument('-i', + dest='in_iface', + default='wlan0', + type=str, + help='Specify iface for injection (default: wlan0)') + + parser.add_argument('-o', + dest='out_iface', + default='wlan0', + type=str, + help='Specify iface for injection (default: wlan0)') + + parser.add_argument('-s', + dest='smac', + type=utils.sanitize_smac, + help='Specify source MAC address for injected frames.') + + parser.add_argument('-w', + dest='wepkey', + type=str, + help='WEP mode and key') + + parser.add_argument('-k', + dest='keyid', + type=int, + choices=xrange(0,4), + default=0, + help='WEP key id (default: 0)') + + parser.add_argument('-d', + dest='debug', + action='store_true', + help='Activate debug mode.') + + parser.add_argument('-v', + dest='verb', + action='store_true', + help='Use verbose debugging.') + + args = parser.parse_args() + + # validate wepkey if WEP in use + if args.wepkey is not None: + wepkey = utils.parse_wep_key(args.wepkey, args.keyid) + if wepkey is None: + parser.print_usage() + print + print '[!] Invalid WEP key' + sys.exit() + + conf.iface = args.out_iface + conf.wepkey = args.wepkey + + return args + +def print_options(options): + + print "out_iface: %s" % options.out_iface + print "bssid: %s" % options.bssid + if options.smac is not None: + + print "smac: %s" % options.smac + + if options.wepkey is not None: + + print "WEP key: %s (%dbits)" % (options.wepkey, len(options.wepkey)*4) + + print 'DEBUG mode:', options.debug + +if __name__ == '__main__': + + options = setup() + + # Here we put a BPF filter so only 802.11 Data/to-DS frames are captured + s = conf.L2listen(iface = options.in_iface, + filter = "link[0]&0xc == 8 and link[1]&0xf == 1") + + # Speed optimization si Scapy does not have to parse payloads + ARP.payload_guess=[] + + try: + while True: + dot11_frame = s.recv(2346) + + # WEP handling is automagicly done by Scapy if conf.wepkey is set + # Nothing to do to decrypt (although not yet tested) + # WEP frames have Dot11WEP layer, others don't + if options.debug and options.verb: + if dot11_frame.haslayer(Dot11WEP): # WEP frame + os.write(1,"Received WEP from %s\n" % options.in_iface) + else: # Cleartext frame + os.write(1,"Received from %s\n" % options.in_iface) + os.write(1,"%s\n" % dot11_frame.summary()) + + if dot11_frame.getlayer(Dot11).addr1 != options.bssid: + continue + + # Identifying ARP Requests + if dot11_frame.haslayer(ARP) and dot11_frame.getlayer(ARP).op == 1: + + if options.debug: + + os.write(1,"Received ARP Request on %s\n" % options.in_iface) + + if optios.verb: + os.write(1,"%s\n" % dot11_frame.summary()) + + # Building ARP Reply answer for injection + dot11_answer = RadioTap()/Dot11( + type = "Data", + FCfield = "from-DS", + addr1 = dot11_frame.getlayer(Dot11).addr2, + addr2 = options.bssid) + dot11_answer.addr3 = options.smac + + if options.wepkey is not None: + dot11_answer.FCfield |= 0x40 + dot11_answer /= Dot11WEP( + iv = "111", + keyid = options.keyid) + + dot11_answer /= LLC(ctrl=3)/SNAP()/ARP( + op="is-at", + hwsrc=options.smac, + psrc=dot11_frame.getlayer(ARP).pdst, + hwdst=dot11_frame.getlayer(ARP).hwsrc, + pdst=dot11_frame.getlayer(ARP).psrc) + + dot11_answer /= dot11_frame.getlayer(ARP).payload + + if options.debug: + os.write(1,"Sending ARP Reply on %s\n" % optios.out_iface) + if options.verb: + os.write(1,"%s\n" % dot11_answer.summary()) + + # Frame injection : + sendp(dot11_answer,verbose=0) # Send frame + + # Program killed + except KeyboardInterrupt: + print "Stopped by user." + + s.close() + + sys.exit() diff --git a/wifidns.py b/wifidns.py index 4b00094..8344a78 100755 --- a/wifidns.py +++ b/wifidns.py @@ -17,237 +17,193 @@ # ######################################### -import os,sys,getopt,struct,re,string,logging - -# Import Psyco if available to speed up execution -try: - import psyco - psyco.full() -except ImportError: - print "Psyco optimizer not installed, running anyway..." - pass +import os +import sys +import argparse +import struct +import logging +import utils from socket import * from fcntl import ioctl from select import select logging.getLogger("scapy").setLevel(1) + #from scapy import Raw,Ether,PrismHeader,Dot11,Dot11WEP,LLC,SNAP,sendp,conf from scapy.all import Raw,Ether,PrismHeader,Dot11,Dot11WEP,LLC,SNAP,sendp,conf,RadioTap - -# We want to build a DNS Query answering machine - from scapy.all import IP,UDP,DNS,DNSRR -IN_IFACE = "wlan0" -OUT_IFACE = "wlan0" -HAS_SMAC = 0 -SMAC = "" -WEP = 0 -KEYID = 0 -DEBUG = 0 -VERB = 0 -TTL = 64 -BSSID = "" -IPDNS = "" -WEPKEY = "" - - -def usage(status=0): - print "Usage: wifidns -b -a [-o ] [-i ]" - print " [-s ] [-t ] [-w ]" - print " [-k ]] [-d [-v]] [-h]" - print " -b specify BSSID for injection" - print " -a specify IP address for DNS answers" - print " -t Set TTL (default: 64)" - print " -o specify interface for injection (default: wlan0)" - print " -i specify interface for listening (default: wlan0)" - print " -s specify source MAC address for injected frames" - print " -w WEP mode and key" - print " -k WEP key id (default: 0)" - print " -d activate debug" - print " -v verbose debugging" - print " -h this so helpful output" - sys.exit(status) - -opts = getopt.getopt(sys.argv[1:],"b:a:o:i:s:t:w:k:dvh") - -for opt,optarg in opts[0]: - if opt == "-b": - BSSID = optarg - elif opt == "-a": - IPDNS = optarg - elif opt == "-o": - OUT_IFACE = optarg - elif opt == "-i": - IN_IFACE = optarg - elif opt == "-s": - HAS_SMAC += 1 - SMAC = optarg - elif opt == "-w": - WEP += 1 - WEPKEY = optarg - elif opt == "-k": - KEYID = int(optarg) - elif opt == "-t": - TTL = int(optarg) - elif opt == "-d": - DEBUG += 1 - elif opt == "-v": - VERB += 1 - elif opt == "-h": - usage() - -if not BSSID: - print "\nError: BSSID not defined\n" - usage() - -if not IPDNS: - print "\nError: IP not defined\n" - usage() - -# Match and parse BSSID -if re.match('^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$', BSSID): - BSSID = BSSID.lower() -else: - print "\nError: Wrong format for BSSID\n" - usage() - -if HAS_SMAC: - if not SMAC: - print "\nError: SMAC not defined\n" - usage() - # Match and parse SMAC - elif re.match('^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$', SMAC): - SMAC = SMAC.lower() - else: - print "\nError: Wrong format for SMAC\n" - usage() - -# Match and parse IP -if not re.match('^(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])$', IPDNS): - print "\nError: Wrong IP address\n" - usage() - -print "IN_IFACE: %s" % IN_IFACE -print "OUT_IFACE: %s" % OUT_IFACE -print "BSSID: %s" % BSSID -if HAS_SMAC: - print "SMAC: %s" % SMAC -print "IP: %s" % IPDNS - -if WEP: - # Match and parse WEP key - tmp_key = "" - if re.match('^([0-9a-fA-F]{2}){5}$', WEPKEY) or re.match ('^([0-9a-fA-F]{2}){13}$', WEPKEY): - tmp_key = WEPKEY - elif re.match('^([0-9a-fA-F]{2}[:]){4}[0-9a-fA-F]{2}$', WEPKEY) or re.match('^([0-9a-fA-F]{2}[:]){12}[0-9a-fA-F]{2}$', WEPKEY): - tmp_key = re.sub(':', '', WEPKEY) - elif re.match ('^([0-9a-fA-F]{4}[-]){2}[0-9a-fA-F]{2}$', WEPKEY) or re.match ('^([0-9a-fA-F]{4}[-]){6}[0-9a-fA-F]{2}$', WEPKEY): - tmp_key = re.sub('-', '', WEPKEY) - else: - print "\nError : Wrong format for WEP key\n" - usage() - g = lambda x: chr(int(tmp_key[::2][x],16)*16+int(tmp_key[1::2][x],16)) - for i in range(len(tmp_key)/2): - conf.wepkey += g(i) - print "WEP key: %s (%dbits)" % (WEPKEY, len(tmp_key)*4) - if KEYID > 3 or KEYID < 0: - print "Key id: %s (defaulted to 0 due to wrong -k argument)" % KEYID - KEYID = 0 - else: - print "Key id: %s" % KEYID -else: - if KEYID != 0: - print "WEP not activated, key id ignored" - -print "TTL: %s" % TTL - -if not DEBUG: - if VERB: - print "DEBUG not activated, verbosity ignored" -else: - print "DEBUG activated" - if VERB: - print "Verbose debugging" - -conf.iface = OUT_IFACE - -# Here we put a BPF filter so only 802.11 Data/to-DS frames are captured -s = conf.L2listen(iface = IN_IFACE, - filter = "link[0]&0xc == 8 and link[1]&0xf == 1") - -# Speed optimization si Scapy does not have to parse payloads -DNS.payload_guess=[] - -try: - while 1: - dot11_frame = s.recv(2346) - - # WEP handling is automagicly done by Scapy if conf.wepkey is set - # Nothing to do to decrypt - # WEP frames have Dot11WEP layer, others don't - if DEBUG and VERB: - if dot11_frame.haslayer(Dot11WEP): # WEP frame - os.write(1,"Received WEP from %s\n" % IN_IFACE) - else: # Cleartext frame - os.write(1,"Received from %s\n" % IN_IFACE) - os.write(1,"%s\n" % dot11_frame.summary()) - - if dot11_frame.getlayer(Dot11).addr1 != BSSID: - continue - - # Identifying DNS Queries - if dot11_frame.haslayer(DNS) and dot11_frame.getlayer(DNS).qr == 0: - if DEBUG: - os.write(1,"Received DNS Query on %s\n" % IN_IFACE) - if VERB: - os.write(1,"%s\n" % dot11_frame.summary()) - - # Building DNS Reply answer for injection - dot11_answer = RadioTap()/Dot11( - type = "Data", - FCfield = "from-DS", - addr1 = dot11_frame.getlayer(Dot11).addr2, - addr2 = BSSID) - if not HAS_SMAC: - dot11_answer.addr3 = dot11_frame.getlayer(Dot11).addr1 - else: - dot11_answer.addr3 = SMAC - if WEP: - dot11_answer.FCfield |= 0x40 - dot11_answer /= Dot11WEP( - iv = "111", - keyid = KEYID) - dot11_answer /= LLC(ctrl = 3)/SNAP()/IP( - src = dot11_frame.getlayer(IP).dst, - dst = dot11_frame.getlayer(IP).src, - ttl = TTL) - dot11_answer /= UDP( - sport = dot11_frame.getlayer(UDP).dport, - dport = dot11_frame.getlayer(UDP).sport) - dot11_answer /= DNS( - id = dot11_frame.getlayer(DNS).id, - qr = 1, - qd = dot11_frame.getlayer(DNS).qd, - an = DNSRR( - rrname = dot11_frame.getlayer(DNS).qd.qname, - ttl = 10, - rdata = IPDNS) - ) - - if DEBUG: - os.write(1,"Sending DNS Reply on %s\n" % OUT_IFACE) - if VERB: - os.write(1,"%s\n" % dot11_frame.summary()) - - # Frame injection : - sendp(dot11_answer,verbose=0) # Send frame - -# Program killed -except KeyboardInterrupt: - print "Stopped by user." - -s.close() - -sys.exit() +def setup(): + + global conf + + parser = argparse.ArgumentParser() + + parser.add_argument('-b', + dest='bssid', + type=utils.sanitize_bssid, + required=True, + help='Specify BSSID for injection') + + parser.add_argument('-i', + dest='in_iface', + default='wlan0', + type=str, + help='Specify iface for injection (default: wlan0)') + + parser.add_argument('-o', + dest='out_iface', + default='wlan0', + type=str, + help='Specify iface for injection (default: wlan0)') + + parser.add_argument('-a', + dest='ipdns', + required=True, + type=utils.sanitize_ipdns, + help="Specify IP address for DNS answers.") + + parser.add_argument('-s', + dest='smac', + type=utils.sanitize_smac, + help='Specify source MAC address for injected frames.') + + parser.add_argument('-w', + dest='wepkey', + type=str, + help='WEP mode and key') + + parser.add_argument('-k', + dest='keyid', + type=int, + choices=xrange(0,4), + default=0, + help='WEP key id (default: 0)') + + parser.add_argument('-d', + dest='debug', + action='store_true', + help='Activate debug mode.') + + parser.add_argument('-v', + dest='verbe', + action='store_true', + help='Use verbose debugging.') + + parser.add_argument('-t', + dest='ttl', + type=int, + default=64, + help='Set TTL (default: 64)') + + args = parser.parse_args() + + # validate wepkey if WEP in use + if args.wepkey is not None: + wepkey = utils.parse_wep_key(args.wepkey, args.keyid) + if wepkey is None: + parser.print_usage() + print + print '[!] Invalid WEP key' + sys.exit() + + conf.iface = args.out_iface + conf.wepkey = args.wepkey + + return args + +def print_options(options): + + print "out_iface: %s" % options.out_iface + print "bssid: %s" % options.bssid + print "ttl: %s" % options.ttl + print "ipdns: %s" % options.ipdns + if options.smac is not None: + + print "smac: %s" % options.smac + + if options.wepkey is not None: + + print "WEP key: %s (%dbits)" % (options.wepkey, len(options.wepkey)*4) + + print 'DEBUG mode:', options.debug + +if __name__ == '__main__': + + options = setup() + + # Here we put a BPF filter so only 802.11 Data/to-DS frames are captured + s = conf.L2listen(iface=options.in_iface, + filter="link[0]&0xc == 8 and link[1]&0xf == 1") + + # Speed optimization si Scapy does not have to parse payloads + DNS.payload_guess=[] + + try: + while True: + dot11_frame = s.recv(2346) + + # WEP handling is automagicly done by Scapy if conf.wepkey is set + # Nothing to do to decrypt + # WEP frames have Dot11WEP layer, others don't + if options.debug and options.verb: + if dot11_frame.haslayer(Dot11WEP): # WEP frame + os.write(1,"Received WEP from %s\n" % options.in_iface) + else: # Cleartext frame + os.write(1,"Received from %s\n" % options.in_iface) + os.write(1,"%s\n" % dot11_frame.summary()) + + if dot11_frame.getlayer(Dot11).addr1 != options.bssid: + continue + + # Identifying DNS Queries + if dot11_frame.haslayer(DNS) and dot11_frame.getlayer(DNS).qr == 0: + if options.debug: + os.write(1,"Received DNS Query on %s\n" % options.in_iface) + if options.verb: + os.write(1,"%s\n" % dot11_frame.summary()) + + # Building DNS Reply answer for injection + dot11_answer = RadioTap()/Dot11(type="Data", + FCfield="from-DS", + addr1=dot11_frame.getlayer(Dot11).addr2, + addr2=options.bssid) + + if options.smac is not None: + dot11_answer.addr3 = dot11_frame.getlayer(Dot11).addr1 + else: + dot11_answer.addr3 = options.smac + + if options.wepkey is not None: + dot11_answer.FCfield |= 0x40 + dot11_answer /= Dot11WEP(iv="111", keyid=options.keyid) + + dot11_answer /= LLC(ctrl = 3)/SNAP()/IP(src=dot11_frame.getlayer(IP).dst, + dst=dot11_frame.getlayer(IP).src, + ttl=options.ttl) + + dot11_answer /= UDP(sport=dot11_frame.getlayer(UDP).dport, + dport=dot11_frame.getlayer(UDP).sport) + + dot11_answer /= DNS(id=dot11_frame.getlayer(DNS).id, + qr=1, + qd=dot11_frame.getlayer(DNS).qd, + an=DNSRR(rrname=dot11_frame.getlayer(DNS).qd.qname, + ttl=10, + rdata=options.ipdns)) + + if options.debug: + os.write(1,"Sending DNS Reply on %s\n" % options.out_iface) + if options.verb: + os.write(1,"%s\n" % dot11_frame.summary()) + + # Frame injection : + sendp(dot11_answer,verbose=0) # Send frame + + # Program killed + except KeyboardInterrupt: + print "\nStopped by user." + + s.close() + sys.exit() diff --git a/wifiping.py b/wifiping.py index 87c0ee8..b6b2828 100755 --- a/wifiping.py +++ b/wifiping.py @@ -17,215 +17,186 @@ # ######################################### -import os,sys,getopt,struct,re,string, logging - -# Import Psyco if available to speed up execution -try: - import psyco - psyco.full() -except ImportError: - print "Psyco optimizer not installed, running anyway..." - pass +import os +import sys +import getopt +import struct +import logging +import utils +import argparse from socket import * from fcntl import ioctl from select import select logging.getLogger("scapy").setLevel(1) -from scapy.all import Raw,Ether,PrismHeader,Dot11,Dot11WEP,LLC,SNAP,sendp,conf - -# We want to build an ICMP Echo Request answering machine - -from scapy import IP,ICMP - -IN_IFACE = "wlan0" -OUT_IFACE = "wlan0" -HAS_SMAC = 0 -SMAC = "" -WEP = 0 -KEYID = 0 -DEBUG = 0 -VERB = 0 -TTL = 64 -BSSID = "" -WEPKEY = "" - - -def usage(status=0): - print "Usage: wifitap -b [-t ] [-o ] [-i ]" - print " [-s ] [-w [-k ]]" - print " [-d [-v]] [-h]" - print " -b specify BSSID for injection" - print " -t Set TTL (default: 64)" - print " -o specify interface for injection (default: wlan0)" - print " -i specify interface for listening (default: wlan0)" - print " -s specify source MAC address for injected frames" - print " -w WEP mode and key" - print " -k WEP key id (default: 0)" - print " -d activate debug" - print " -v verbose debugging" - print " -h this so helpful output" - sys.exit(status) - -opts = getopt.getopt(sys.argv[1:],"b:o:i:s:w:k:t:dvh") - -for opt,optarg in opts[0]: - if opt == "-b": - BSSID = optarg - elif opt == "-o": - OUT_IFACE = optarg - elif opt == "-i": - IN_IFACE = optarg - elif opt == "-s": - HAS_SMAC += 1 - SMAC = optarg - elif opt == "-w": - WEP += 1 - WEPKEY = optarg - elif opt == "-k": - KEYID = int(optarg) - elif opt == "-t": - TTL = int(optarg) - elif opt == "-d": - DEBUG += 1 - elif opt == "-v": - VERB += 1 - elif opt == "-h": - usage() - -if not BSSID: - print "\nError: BSSID not defined\n" - usage() - -# Match and parse BSSID -if re.match('^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$', BSSID): - BSSID = BSSID.lower() -else: - print "\nError: Wrong format for BSSID\n" - usage () - -if HAS_SMAC: - if not SMAC: - print "\nError: SMAC not defined\n" - usage() - # Match and parse SMAC - elif re.match('^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$', SMAC): - SMAC = SMAC.lower() - else: - print "\nError: Wrong format for SMAC\n" - usage() - -print "IN_IFACE: %s" % IN_IFACE -print "OUT_IFACE: %s" % OUT_IFACE -print "BSSID: %s" % BSSID -if HAS_SMAC: - print "SMAC: %s" % SMAC - -if WEP: - # Match and parse WEP key - tmp_key = "" - if re.match('^([0-9a-fA-F]{2}){5}$', WEPKEY) or re.match ('^([0-9a-fA-F]{2}){13}$', WEPKEY): - tmp_key = WEPKEY - elif re.match('^([0-9a-fA-F]{2}[:]){4}[0-9a-fA-F]{2}$', WEPKEY) or re.match('^([0-9a-fA-F]{2}[:]){12}[0-9a-fA-F]{2}$', WEPKEY): - tmp_key = re.sub(':', '', WEPKEY) - elif re.match ('^([0-9a-fA-F]{4}[-]){2}[0-9a-fA-F]{2}$', WEPKEY) or re.match ('^([0-9a-fA-F]{4}[-]){6}[0-9a-fA-F]{2}$', WEPKEY): - tmp_key = re.sub('-', '', WEPKEY) - else: - print "\nError : Wrong format for WEP key\n" - usage() - g = lambda x: chr(int(tmp_key[::2][x],16)*16+int(tmp_key[1::2][x],16)) - for i in range(len(tmp_key)/2): - conf.wepkey += g(i) - print "WEP key: %s (%dbits)" % (WEPKEY, len(tmp_key)*4) - if KEYID > 3 or KEYID < 0: - print "Key id: %s (defaulted to 0 due to wrong -k argument)" % KEYID - KEYID = 0 - else: - print "Key id: %s" % KEYID -else: - if KEYID != 0: - print "WEP not activated, key id ignored" - -print "TTL: %s" % TTL - -if not DEBUG: - if VERB: - print "DEBUG not activated, verbosity ignored" -else: - print "DEBUG activated" - if VERB: - print "Verbose debugging" - -conf.iface = OUT_IFACE - -# Here we put a BPF filter so only 802.11 Data/to-DS frames are captured -s = conf.L2listen(iface = IN_IFACE, - filter = "link[0]&0xc == 8 and link[1]&0xf == 1") - -# Speed optimization si Scapy does not have to parse payloads -ICMP.payload_guess=[] - -try: - while 1: - dot11_frame = s.recv(2346) - - # WEP handling is automagicly done by Scapy if conf.wepkey is set - # Nothing to do to decrypt (although not yet tested) - # WEP frames have Dot11WEP layer, others don't - if DEBUG and VERB: - if dot11_frame.haslayer(Dot11WEP): # WEP frame - os.write(1,"Received WEP from %s\n" % IN_IFACE) - else: # Cleartext frame - os.write(1,"Received from %s\n" % IN_IFACE) - # os.write(1,"%s\n" % dot11_frame.summary()) - - if dot11_frame.getlayer(Dot11).addr1 != BSSID: - continue - - # Identifying ICMP Echo Requests - if dot11_frame.haslayer(ICMP) and dot11_frame.getlayer(ICMP).type == 8: - if DEBUG: - os.write(1,"Received ICMP Echo Request on %s\n" % IN_IFACE) - if VERB: - os.write(1,"%s\n" % dot11_frame.summary()) - - # Building ICMP Echo Reply answer for injection - dot11_answer = RadioTap()/Dot11( - type = "Data", - FCfield = "from-DS", - addr1 = dot11_frame.getlayer(Dot11).addr2, - addr2 = BSSID) - if not HAS_SMAC: - dot11_answer.addr3 = dot11_frame.getlayer(Dot11).addr1 - else: - dot11_answer.addr3 = SMAC - if WEP: - dot11_answer.FCfield |= 0x40 - dot11_answer /= Dot11WEP( - iv = "111", - keyid = KEYID) - dot11_answer /= LLC(ctrl=3)/SNAP()/IP( - src = dot11_frame.getlayer(IP).dst, - dst = dot11_frame.getlayer(IP).src, - ttl = TTL) - dot11_answer /= ICMP( - type = "echo-reply", - id = dot11_frame.getlayer(ICMP).id, - seq = dot11_frame.getlayer(ICMP).seq) - dot11_answer /= dot11_frame.getlayer(ICMP).payload - - if DEBUG: - os.write(1,"Sending ICMP Echo Reply on %s\n" % OUT_IFACE) - if VERB: - os.write(1,"%s\n" % dot11_answer.summary()) - - # Frame injection : - sendp(dot11_answer,verbose=0) # Send frame - -# Program killed -except KeyboardInterrupt: - print "Stopped by user." - -s.close() - -sys.exit() +from scapy.all import Raw,Ether,PrismHeader,Dot11,Dot11WEP,LLC,SNAP,sendp,conf,IP,ICMP + +def setup(): + + global conf + + parser = argparse.ArgumentParser() + + parser.add_argument('-b', + dest='bssid', + type=utils.sanitize_bssid, + required=True, + help='Specify BSSID for injection') + + parser.add_argument('-i', + dest='in_iface', + default='wlan0', + type=str, + help='Specify iface for injection (default: wlan0)') + + parser.add_argument('-o', + dest='out_iface', + default='wlan0', + type=str, + help='Specify iface for injection (default: wlan0)') + + parser.add_argument('-s', + dest='smac', + type=utils.sanitize_smac, + help='Specify source MAC address for injected frames.') + + parser.add_argument('-w', + dest='wepkey', + type=str, + help='WEP mode and key') + + parser.add_argument('-k', + dest='keyid', + type=int, + choices=xrange(0,4), + default=0, + help='WEP key id (default: 0)') + + parser.add_argument('-d', + dest='debug', + action='store_true', + help='Activate debug mode.') + + parser.add_argument('-v', + dest='verb', + action='store_true', + help='Use verbose debugging.') + + parser.add_argument('-t', + dest='ttl', + type=int, + default=64, + help='Set TTL (default: 64)') + + args = parser.parse_args() + + # validate wepkey if WEP in use + if args.wepkey is not None: + wepkey = utils.parse_wep_key(args.wepkey, args.keyid) + if wepkey is None: + parser.print_usage() + print + print '[!] Invalid WEP key' + sys.exit() + + conf.iface = args.out_iface + conf.wepkey = args.wepkey + + return args + +def print_options(options): + + print "out_iface: %s" % options.out_iface + print "bssid: %s" % options.bssid + print "ttl: %s" % options.ttl + if options.smac is not None: + + print "smac: %s" % options.smac + + if options.wepkey is not None: + + print "WEP key: %s (%dbits)" % (options.wepkey, len(options.wepkey)*4) + + print 'DEBUG mode:', options.debug + +if __name__ == '__main__': + + options = setup() + + # Here we put a BPF filter so only 802.11 Data/to-DS frames are captured + s = conf.L2listen(iface = options.in_iface, + filter="link[0]&0xc == 8 and link[1]&0xf == 1") + + # Speed optimization si Scapy does not have to parse payloads + ICMP.payload_guess=[] + + try: + + while True: + dot11_frame = s.recv(2346) + + # WEP handling is automagicly done by Scapy if conf.wepkey is set + # Nothing to do to decrypt (although not yet tested) + # WEP frames have Dot11WEP layer, others don't + if options.debug and options.verb: + if dot11_frame.haslayer(Dot11WEP): # WEP frame + os.write(1,"Received WEP from %s\n" % options.in_iface) + else: # Cleartext frame + os.write(1,"Received from %s\n" % options.in_iface) + #os.write(1,"%s\n" % dot11_frame.summary()) + + if dot11_frame.getlayer(Dot11).addr1 != options.bssid: + continue + + # Identifying ICMP Echo Requests + if dot11_frame.haslayer(ICMP) and dot11_frame.getlayer(ICMP).type == 8: + + if options.debug: + os.write(1,"Received ICMP Echo Request on %s\n" % options.in_iface) + if options.verb: + os.write(1,"%s\n" % dot11_frame.summary()) + + # Building ICMP Echo Reply answer for injection + dot11_answer = RadioTap()/Dot11( + type = "Data", + FCfield = "from-DS", + addr1 = dot11_frame.getlayer(Dot11).addr2, + addr2 = options.bssid) + + if options.smac is None: + dot11_answer.addr3 = dot11_frame.getlayer(Dot11).addr1 + else: + dot11_answer.addr3 = options.smac + + if options.wepkey is not None: + + dot11_answer.FCfield |= 0x40 + + dot11_answer /= Dot11WEP(iv="111", + keyid=options.keyid) + + dot11_answer /= LLC(ctrl=3)/SNAP()/IP(src=dot11_frame.getlayer(IP).dst, + dst=dot11_frame.getlayer(IP).src, + ttl=options.ttl) + + dot11_answer /= ICMP(type="echo-reply", + id=dot11_frame.getlayer(ICMP).id, + seq=dot11_frame.getlayer(ICMP).seq) + + dot11_answer /= dot11_frame.getlayer(ICMP).payload + + if options.debug: + os.write(1,"Sending ICMP Echo Reply on %s\n" % options.out_iface) + if options.verb: + os.write(1,"%s\n" % dot11_answer.summary()) + + # Frame injection : + sendp(dot11_answer,verbose=0) # Send frame + + # Program killed + except KeyboardInterrupt: + print "Stopped by user." + + s.close() + sys.exit() diff --git a/wifitap.py b/wifitap.py index d0935c6..79a1d2a 100755 --- a/wifitap.py +++ b/wifitap.py @@ -17,14 +17,12 @@ # ######################################### -import os,sys,getopt,struct,re,string,logging - -# Import Psyco if available to speed up execution -try: - import psyco - psyco.full() -except ImportError: - print "Psyco optimizer not installed, running anyway..." +import os +import sys +import struct +import logging +import argparse +import utils from socket import * from fcntl import ioctl @@ -33,237 +31,209 @@ logging.getLogger("scapy").setLevel(1) #from scapy import Raw,Ether,PrismHeader,Dot11,Dot11WEP,LLC,SNAP,sendp,conf from scapy.all import Raw,Ether,PrismHeader,Dot11,Dot11WEP,LLC,SNAP,sendp,conf,RadioTap + TUNSETIFF = 0x400454ca IFF_TAP = 0x0002 TUNMODE = IFF_TAP -IN_IFACE = "wlan0" -OUT_IFACE = "wlan0" -HAS_SMAC = 0 -SMAC = "" -WEP = 0 -KEYID = 0 -DEBUG = 0 -VERB = 0 -BSSID = "" -WEPKEY = "" - - -def usage(status=0): - print "Usage: wifitap -b [-o ] [-i ] [-s ]" - print " [-w [-k ]] [-d [-v]] [-h]" - print " -b specify BSSID for injection" - print " -o specify interface for injection (default: wlan0)" - print " -i specify interface for listening (default: wlan0)" - print " -s specify source MAC address for injected frames" - print " -w WEP mode and key" - print " -k WEP key id (default: 0)" - print " -d activate debug" - print " -v verbose debugging" - print " -h this so helpful output" - sys.exit(status) - -opts = getopt.getopt(sys.argv[1:],"b:o:i:s:w:k:dvh") - -for opt,optarg in opts[0]: - if opt == "-b": - BSSID = optarg - elif opt == "-o": - OUT_IFACE = optarg - elif opt == "-i": - IN_IFACE = optarg - elif opt == "-s": - HAS_SMAC += 1 - SMAC = optarg - elif opt == "-w": - WEP += 1 - WEPKEY = optarg - elif opt == "-k": - KEYID = int(optarg) - elif opt == "-d": - DEBUG += 1 - elif opt == "-v": - VERB += 1 - elif opt == "-h": - usage() - -if not BSSID: - print "\nError: BSSID not defined\n" - usage() - -# Match and parse BSSID -if re.match('^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$', BSSID): - BSSID = BSSID.lower() -else: - print "\nError: Wrong format for BSSID\n" - usage () - -# Support for source MAC spoofing for adhoc support -if HAS_SMAC: - if not SMAC: - print "\nError: SMAC not defined\n" - usage() - # Match and parse SMAC - elif re.match('^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$', SMAC): - SMAC = SMAC.lower() - else: - print "\nError: Wrong format for SMAC\n" - usage() - -print "IN_IFACE: %s" % IN_IFACE -print "OUT_IFACE: %s" % OUT_IFACE -print "BSSID: %s" % BSSID -if HAS_SMAC: - print "SMAC: %s" % SMAC - -if WEP: - # Match and parse WEP key - tmp_key = "" - if re.match('^([0-9a-fA-F]{2}){5}$', WEPKEY) or re.match ('^([0-9a-fA-F]{2}){13}$', WEPKEY): - tmp_key = WEPKEY - elif re.match('^([0-9a-fA-F]{2}[:]){4}[0-9a-fA-F]{2}$', WEPKEY) or re.match('^([0-9a-fA-F]{2}[:]){12}[0-9a-fA-F]{2}$', WEPKEY): - tmp_key = re.sub(':', '', WEPKEY) - elif re.match ('^([0-9a-fA-F]{4}[-]){2}[0-9a-fA-F]{2}$', WEPKEY) or re.match ('^([0-9a-fA-F]{4}[-]){6}[0-9a-fA-F]{2}$', WEPKEY): - tmp_key = re.sub('-', '', WEPKEY) - else: - print "\nError : Wrong format for WEP key\n" - usage() - g = lambda x: chr(int(tmp_key[::2][x],16)*16+int(tmp_key[1::2][x],16)) - for i in range(len(tmp_key)/2): - conf.wepkey += g(i) - print "WEP key: %s (%dbits)" % (WEPKEY, len(tmp_key)*4) - if KEYID > 3 or KEYID < 0: - print "Key id: %s (defaulted to 0 due to wrong -k argument)" % KEYID - KEYID = 0 - else: - print "Key id: %s" % KEYID -else: - if KEYID != 0: - print "WEP not activated, key id ignored" - -if not DEBUG: - if VERB: - print "DEBUG not activated, verbosity ignored" -else: - print "DEBUG activated" - if VERB: - print "Verbose debugging" - -conf.iface = OUT_IFACE - -# Here we put a BPF filter so only 802.11 Data/to-DS frames are captured -s = conf.L2listen(iface = IN_IFACE, - filter = "link[0]&0xc == 8 and link[1]&0xf == 1") -#s = conf.L2listen(iface = IN_IFACE) - -# Open /dev/net/tun in TAP (ether) mode -f = os.open("/dev/net/tun", os.O_RDWR) -ifs = ioctl(f, TUNSETIFF, struct.pack("16sH", "wj%d", TUNMODE)) -ifname = ifs[:16].strip("\x00") -print "Interface %s created. Configure it and use it" % ifname - -# Speed optimization si Scapy does not have to parse payloads -Ether.payload_guess=[] -SNAP.payload_guess=[] - -try: - while 1: - r = select([f,s],[],[])[0] - - # frame from /dev/net/tun - if f in r: - - # tuntap frame max. size is 1522 (ethernet, see RFC3580) + 4 - buf = os.read(f,1526) - eth_rcvd_frame=Ether(buf[4:]) - - if DEBUG: - os.write(1,"Received from %s\n" % ifname) - if VERB: - os.write(1,"%s\n" % eth_rcvd_frame.summary()) - - # Prepare Dot11 frame for injection - dot11_sent_frame = RadioTap()/Dot11( - type = "Data", - FCfield = "from-DS", - addr1 = eth_rcvd_frame.getlayer(Ether).dst, - addr2 = BSSID) - # It doesn't seem possible to set tuntap interface MAC address - # when we create it, so we set source MAC here - if not HAS_SMAC: - dot11_sent_frame.addr3 = eth_rcvd_frame.getlayer(Ether).src - else: - dot11_sent_frame.addr3 = SMAC - if WEP: - dot11_sent_frame.FCfield |= 0x40 - dot11_sent_frame /= Dot11WEP( - iv = "111", - keyid = KEYID) - dot11_sent_frame /= LLC(ctrl = 3)/SNAP(code=eth_rcvd_frame.getlayer(Ether).type)/eth_rcvd_frame.getlayer(Ether).payload - - if DEBUG: - os.write(1,"Sending from-DS to %s\n" % OUT_IFACE) - if VERB: - os.write(1,"%s\n" % dot11_sent_frame.summary()) - - # Frame injection : - sendp(dot11_sent_frame,verbose=0) # Send from-DS frame - - # Frame from WiFi network - if s in r: - - # 802.11 maximum frame size is 2346 bytes (cf. RFC3580) - # However, WiFi interfaces are always MTUed to 1500 - dot11_rcvd_frame = s.recv(2346) - - # WEP handling is automagicly done by Scapy if conf.wepkey is set - # Nothing to do to decrypt (although not yet tested) - # WEP frames have Dot11WEP layer, others don't - - if DEBUG: - if dot11_rcvd_frame.haslayer(Dot11WEP): # WEP frame - os.write(1,"Received WEP from %s\n" % IN_IFACE) - else: # Cleartext frame - os.write(1,"Received from %s\n" % IN_IFACE) - if VERB: - os.write(1,"%s\n" % dot11_rcvd_frame.summary()) - - # if dot11_frame.getlayer(Dot11).FCfield & 1: # Frame is to-DS - # For now, we only take care of to-DS frames... - - if dot11_rcvd_frame.getlayer(Dot11).addr1 != BSSID: - if VERB: - os.write(1,"Frame not to/from BSSID\n") - continue - - # One day, we'll try to take care of AP to DS trafic (cf. TODO) - # else: # Frame is from-DS - # if dot11_frame.getlayer(Dot11).addr2 != BSSID: - # continue - # eth_frame = Ether(dst=dot11_frame.getlayer(Dot11).addr1, - # src=dot11_frame.getlayer(Dot11).addr3) - - if dot11_rcvd_frame.haslayer(SNAP): - eth_sent_frame = Ether( - dst=dot11_rcvd_frame.getlayer(Dot11).addr3, - src=dot11_rcvd_frame.getlayer(Dot11).addr2, - type=dot11_rcvd_frame.getlayer(SNAP).code) - eth_sent_frame.payload = dot11_rcvd_frame.getlayer(SNAP).payload - - if DEBUG: - os.write(1, "Sending to %s\n" % ifname) - if VERB: - os.write(1, "%s\n" % eth_sent_frame.summary()) - - # Add Tun/Tap header to frame, convert to string and send - buf = "\x00\x00" + struct.pack("!H",eth_sent_frame.type) + str(eth_sent_frame) - os.write(f, buf) - -# Program killed -except KeyboardInterrupt: - print "Stopped by user." - -s.close() -os.close(f) - -sys.exit() +def setup(): + + global conf + + parser = argparse.ArgumentParser() + parser.add_argument('-b', + dest='bssid', + type=utils.sanitize_bssid, + required=True, + help='Specify BSSID for injection') + + parser.add_argument('-o', + dest='out_iface', + default='wlan0', + type=str, + help='Specify iface for injection (default: wlan0)') + + parser.add_argument('-i', + dest='in_iface', + default='wlan0', + type=str, + help='Specify iface for listening (default: wlan0)') + + parser.add_argument('-s', + dest='smac', + type=utils.sanitize_smac, + help='Specify source MAC address for injected frames.') + + parser.add_argument('-w', + dest='wepkey', + type=str, + help='WEP mode and key') + + parser.add_argument('-k', + dest='keyid', + type=int, + choices=xrange(0,4), + default=0, + help='WEP key id (default: 0)') + + parser.add_argument('-d', + dest='debug', + action='store_true', + help='Activate debug mode.') + + parser.add_argument('-v', + dest='verb', + action='store_true', + help='Use verbose debugging.') + + args = parser.parse_args() + + # validate wepkey if WEP in use + if args.wepkey is not None: + wepkey = utils.parse_wep_key(args.wepkey, args.keyid) + if wepkey is None: + parser.print_usage() + print + print '[!] Invalid WEP key' + sys.exit() + + conf.iface = args.out_iface + conf.wepkey = args.wepkey + + return args + +def print_options(options): + + print "in_iface: %s" % options.in_iface + print "out_iface: %s" % options.out_iface + print "bssid: %s" % options.bssid + if options.smac is not None: + + print "smac: %s" % options.smac + + if options.wepkey is not None: + + print "WEP key: %s (%dbits)" % (options.wepkey, len(options.wepkey)*4) + + print 'DEBUG mode:', options.debug + +if __name__ == '__main__': + + options = setup() + print_options(options) + + # Here we put a BPF filter so only 802.11 Data/to-DS frames are captured + s = conf.L2listen(iface = options.in_iface, + filter = "link[0]&0xc == 8 and link[1]&0xf == 1") + #s = conf.L2listen(iface = options.in_iface) + + # Open /dev/net/tun in TAP (ether) mode + f = os.open("/dev/net/tun", os.O_RDWR) + ifs = ioctl(f, TUNSETIFF, struct.pack("16sH", "wj%d", TUNMODE)) + ifname = ifs[:16].strip("\x00") + print "Interface %s created. Configure it and use it" % ifname + + # Speed optimization si Scapy does not have to parse payloads + Ether.payload_guess=[] + SNAP.payload_guess=[] + + try: + + while True: + + r = select([f,s],[],[])[0] + + # frame from /dev/net/tun + if f in r: + + # tuntap frame max. size is 1522 (ethernet, see RFC3580) + 4 + buf = os.read(f,1526) + eth_rcvd_frame=Ether(buf[4:]) + + if options.debug: + os.write(1,"Received from %s\n" % ifname) + if options.verb: + os.write(1,"%s\n" % eth_rcvd_frame.summary()) + + # Prepare Dot11 frame for injection + dot11_sent_frame = RadioTap()/Dot11( + type = "Data", + FCfield = "from-DS", + addr1 = eth_rcvd_frame.getlayer(Ether).dst, + addr2 = options.bssid) + # It doesn't seem possible to set tuntap interface MAC address + # when we create it, so we set source MAC here + if options.smac is None: + dot11_sent_frame.addr3 = eth_rcvd_frame.getlayer(Ether).src + else: + dot11_sent_frame.addr3 = options.smac + if options.wepkey is not None: + dot11_sent_frame.FCfield |= 0x40 + dot11_sent_frame /= Dot11WEP(iv = "111", keyid = options.keyid) + + dot11_sent_frame /= LLC(ctrl = 3)/SNAP(code=eth_rcvd_frame.getlayer(Ether).type)/eth_rcvd_frame.getlayer(Ether).payload + + if options.debug: + os.write(1,"Sending from-DS to %s\n" % options.out_iface) + if options.verb: + os.write(1,"%s\n" % dot11_sent_frame.summary()) + + # Frame injection : + sendp(dot11_sent_frame,verbose=0) # Send from-DS frame + + # Frame from WiFi network + if s in r: + + # 802.11 maximum frame size is 2346 bytes (cf. RFC3580) + # However, WiFi interfaces are always MTUed to 1500 + dot11_rcvd_frame = s.recv(2346) + + # WEP handling is automagicly done by Scapy if conf.wepkey is set + # Nothing to do to decrypt (although not yet tested) + # WEP frames have Dot11WEP layer, others don't + + if options.debug: + if dot11_rcvd_frame.haslayer(Dot11WEP): # WEP frame + os.write(1,"Received WEP from %s\n" % options.in_iface) + else: # Cleartext frame + os.write(1,"Received from %s\n" % options.in_iface) + if options.verb: + os.write(1,"%s\n" % dot11_rcvd_frame.summary()) + + # if dot11_frame.getlayer(Dot11).FCfield & 1: # Frame is to-DS + # For now, we only take care of to-DS frames... + if dot11_rcvd_frame.getlayer(Dot11).addr1 != options.bssid: + if options.verb: + os.write(1,"Frame not to/from BSSID\n") + continue + + # One day, we'll try to take care of AP to DS trafic (cf. TODO) + # else: # Frame is from-DS + # if dot11_frame.getlayer(Dot11).addr2 != options.bssid: + # continue + # eth_frame = Ether(dst=dot11_frame.getlayer(Dot11).addr1, + # src=dot11_frame.getlayer(Dot11).addr3) + + if dot11_rcvd_frame.haslayer(SNAP): + eth_sent_frame = Ether(dst=dot11_rcvd_frame.getlayer(Dot11).addr3, + src=dot11_rcvd_frame.getlayer(Dot11).addr2, + type=dot11_rcvd_frame.getlayer(SNAP).code) + eth_sent_frame.payload = dot11_rcvd_frame.getlayer(SNAP).payload + + if options.debug: + os.write(1, "Sending to %s\n" % ifname) + if options.verb: + os.write(1, "%s\n" % eth_sent_frame.summary()) + + # Add Tun/Tap header to frame, convert to string and send + buf = "\x00\x00" + struct.pack("!H",eth_sent_frame.type) + str(eth_sent_frame) + os.write(f, buf) + + # Program killed + except KeyboardInterrupt: + print "\nStopped by user." + + s.close() + os.close(f) + + sys.exit() From ed8d45616d9a30e8aad275d3e1670596b7cfdf4f Mon Sep 17 00:00:00 2001 From: s0lst1c3 Date: Tue, 28 Mar 2017 07:37:08 -0400 Subject: [PATCH 2/4] Updating README.md --- README.md | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/README.md b/README.md index f88240f..a5c783a 100644 --- a/README.md +++ b/README.md @@ -68,26 +68,11 @@ Python dependencies are enumerated in `pip.req`, can be installed using the pip pip install -r pip.req -Wifitap's most important dependency is Scapy, which you should check out because it's totally awesome: +Wifitap's most important dependency is Scapy, which you should check out because it's totally awesome. - [http://www.secdev.org/projects/scapy/](http://www.secdev.org/projects/scapy/) - -o Preparing WiFi adapter - - Download, patch and install driver (see PATCHING). - - Supposing channel is 11: - - ~# iwconfig $IFACE mode monitor channel 11 - ~# ifconfig $IFACE up promisc - - NB: Atheros driver Madwifi requires specific configuration to get driver - in promisc mode and/or activate traffic injection. See website - (http://www.madwifi.org/) for details if you use madwifi-ng or - madwifi-old. - Usage Guide =========== From e705d66bee8afe261884ece52cb6fdae12cb1b34 Mon Sep 17 00:00:00 2001 From: s0lst1c3 Date: Tue, 28 Mar 2017 07:38:00 -0400 Subject: [PATCH 3/4] Updating README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a5c783a..b082096 100644 --- a/README.md +++ b/README.md @@ -81,17 +81,17 @@ Launching Wifitap Before you start, make sure your wireless interface is in monitor mode. In the commands shown below, substitute "wlan0" for the name of your wireless interface. - ~# ifconfig wlan0 down - ~# iw dev wlan0 set monitor none - ~# ifconfig wlan0 up promisc + ifconfig wlan0 down + iw dev wlan0 set monitor none + ifconfig wlan0 up promisc To launch Wifitap with basic options, use the following command: - ~# ./wifitap.py -b + ./wifitap.py -b This will create a wj0 interface. Next, you'll need to configure this new interface using the following shown below. Note that you can optionally specify the MAC in the following command. - ~# ifconfig wj0 [hw ether ] 192.168.1.1 [mtu ] + ifconfig wj0 [hw ether ] 192.168.1.1 [mtu ] You'll now be able to use your newly created wj0 interface as if it were normal network interface, according to your system routing tabl, according to your system routing table. :) From f7ac906855cadb1c5a0a619d1e9e924802a9d6c6 Mon Sep 17 00:00:00 2001 From: s0lst1c3 Date: Tue, 28 Mar 2017 07:40:02 -0400 Subject: [PATCH 4/4] Updating README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b082096..18f4712 100644 --- a/README.md +++ b/README.md @@ -89,11 +89,11 @@ To launch Wifitap with basic options, use the following command: ./wifitap.py -b -This will create a wj0 interface. Next, you'll need to configure this new interface using the following shown below. Note that you can optionally specify the MAC in the following command. +This will create a wj0 interface. Next, you'll need to configure this new interface using syntax shown below. Note that you can optionally specify the MAC in the following command. ifconfig wj0 [hw ether ] 192.168.1.1 [mtu ] -You'll now be able to use your newly created wj0 interface as if it were normal network interface, according to your system routing tabl, according to your system routing table. :) +You'll now be able to use your newly created wj0 interface as if it were normal network interface, according to your system routing table. :) Wifitap Command Line Arguments