Skip to content

Commit

Permalink
Merge pull request #814 from wifiphisher/wps_attack
Browse files Browse the repository at this point in the history
Add wpspbc sniffing extension module
  • Loading branch information
sophron authored Dec 11, 2017
2 parents c75f1bd + dc60753 commit 1d83205
Showing 12 changed files with 513 additions and 52 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -115,6 +115,8 @@ Following are all the options along with their descriptions (also available with
||--logging| Enable logging. Output will be saved to wifiphisher.log file.|
|-cM|--channel-monitor|Monitor if the target access point changes the channel.|
||--payload-path| Enable the payload path. Intended for use with scenarios that serve payloads.|
|-wE|--wpspbc-exploit|Monitor if the button on a WPS-PBC Registrar side is pressed.|
|-wAI|--wpspbc-assoc-interface|The WLAN interface used for associating to the WPS AccessPoint.|


## Screenshots
4 changes: 4 additions & 0 deletions tests/test_interfaces.py
Original file line number Diff line number Diff line change
@@ -1166,6 +1166,7 @@ def test_is_add_vif_required_one_phy_one_vif_tuple_card_true(self, pyric):
"""
args = mock.Mock()
args.internetinterface = None
args.wpspbc_assoc_interface = None
card = mock.Mock()
card.phy = "phy0"
pyric.interfaces.return_value = ["wlan0"]
@@ -1185,6 +1186,7 @@ def test_is_add_vif_required_one_phy_two_vifs_tuple_none_true(self, pyric):

args = mock.Mock()
args.internetinterface = None
args.wpspbc_assoc_interface = None
card = mock.Mock()
card.phy = "phy0"
pyric.interfaces.return_value = ["wlan0", "wlan1"]
@@ -1208,6 +1210,8 @@ def test_is_add_vif_required_two_phy_two_vifs_tuple_card_true(self, pyric):
card1.phy = "phy1"
args = mock.Mock()
args.internetinterface = None
args.wpspbc_assoc_interface = None
card = mock.Mock()

pyric.interfaces.return_value = ["wlan0", "wlan1"]
pyric.iswireless.return_value = True
33 changes: 33 additions & 0 deletions wifiphisher/common/accesspoint.py
Original file line number Diff line number Diff line change
@@ -30,6 +30,7 @@ def __init__(self):
self.psk = None
# roguehostapd object
self.hostapd_object = None
self.deny_mac_addrs = []

def set_interface(self, interface):
"""
@@ -44,6 +45,35 @@ def set_interface(self, interface):

self.interface = interface

def add_deny_macs(self, deny_mac_addrs):
"""
Add the deny mac addresses
:param self: An AccessPoint object
:param deny_mac_addrs: list of deny mac addresses
:type self: AccessPoint
:type deny_mac_addrs: list
:return: None
:rtype: None
"""

self.deny_mac_addrs.extend(deny_mac_addrs)

def update_black_macs(self):
"""
Update the black mac addresses for hostapd
:param self: A HostapdConfig object
:type self: HostapdConfig
:return: None
:rtype: None
"""
with open(hostapd_constants.HOSTAPD_CONF_PATH, 'a') as output_fp:
output_fp.write('macaddr_acl=0\n')
output_fp.write('deny_mac_file='+constants.DENY_MACS_PATH+'\n')
with open(constants.DENY_MACS_PATH, 'w') as writer:
for mac_addr in self.deny_mac_addrs:
writer.write(mac_addr+'\n')

def set_internet_interface(self, interface):
"""
Set the internet interface
@@ -184,6 +214,7 @@ def start(self):
hostapd_options = {}
hostapd_config_obj = hostapd_controller.HostapdConfig()
hostapd_config_obj.write_configs(hostapd_config, hostapd_options)
self.update_black_macs()

# handle exception if hostapd is not installed in system
try:
@@ -219,6 +250,8 @@ def on_exit(self):
subprocess.call('pkill hostapd', shell=True)
if os.path.isfile(hostapd_constants.HOSTAPD_CONF_PATH):
os.remove(hostapd_constants.HOSTAPD_CONF_PATH)
if os.path.isfile(constants.DENY_MACS_PATH):
os.remove(constants.DENY_MACS_PATH)

if os.path.isfile('/var/lib/misc/dnsmasq.leases'):
os.remove('/var/lib/misc/dnsmasq.leases')
13 changes: 13 additions & 0 deletions wifiphisher/common/constants.py
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@
DEV = 1
LURE10_EXTENSION = "lure10"
HANDSHAKE_VALIDATE_EXTENSION = "handshakeverify"
WPSPBC = "wpspbc"
DEFAULT_EXTENSIONS = ["deauth"]
EXTENSIONS_LOADPATH = "wifiphisher.extensions."
PORT = 8080
@@ -77,6 +78,15 @@
# 2 cards, 3 interfaces
# i) AP, ii) Extensions, iii) Internet
OP_MODE6 = 0x6
# Advanced and WPS association 0x7
# 3 cards, 3 interfaces
# i) AP, ii) Extensions, iii) Extensions (Managed)
OP_MODE7 = 0x7

# Advanced and WPS association w/ 1 vif support AP/Monitor 0x8
# 2 cards, 3 interfaces
# i) AP, ii) Extensions, iii) Extensions (Managed)
OP_MODE8 = 0x8

AP_RATES = "\x0c\x12\x18\x24\x30\x48\x60\x6c"

@@ -139,3 +149,6 @@

# Fourway handshake extension
CONST_A = "Pairwise key expansion"

# RogueAp related
DENY_MACS_PATH = '/tmp/hostapd.deny'
17 changes: 12 additions & 5 deletions wifiphisher/common/extensions.py
Original file line number Diff line number Diff line change
@@ -11,8 +11,10 @@
import scapy.layers.dot11 as dot11
import scapy.arch.linux as linux
import wifiphisher.common.constants as constants
import wifiphisher.extensions.deauth as deauth_extension

logger = logging.getLogger(__name__)
is_deauth_cont = True


def register_backend_funcs(func):
@@ -54,6 +56,8 @@ class ExtensionManager(object):
* send_output(self): Method that returns in a list
of strings the entry logs that we need to output.
* on_exit(self): Method that frees all the used resources
* each extension can define the backend method as follows:
ex:
@@ -268,6 +272,9 @@ def on_exit(self):
self._socket.close()
except AttributeError:
pass
# Clean resources used by extension modules
for extension in self._extensions:
extension.on_exit()

def get_channels(self):
"""
@@ -378,11 +385,11 @@ def _send(self):
for pkt in self._packets_to_send[self._current_channel] + \
self._packets_to_send["*"]:
try:
logger.debug(
"Send pkt with addr1:%s addr3:%s subtype:%s in channel:%s",
pkt.addr1, pkt.addr2, pkt.subtype,
self._current_channel)
self._socket.send(pkt)
if is_deauth_cont or not deauth_extension.is_deauth_frame(pkt):
logger.debug("Send pkt with A1:%s A2:%s subtype:%s in channel:%s",
pkt.addr1, pkt.addr2, pkt.subtype,
self._current_channel)
self._socket.send(pkt)
except BaseException:
continue
time.sleep(1)
14 changes: 9 additions & 5 deletions wifiphisher/common/interfaces.py
Original file line number Diff line number Diff line change
@@ -403,7 +403,7 @@ def is_interface_valid(self, interface_name, mode=None):
has been chosen in the set _active
:raises InterfaceManagedByNetworkManagerError: If the card is managed and
is being used as deauth/ap mode
.. note: The available modes are monitor, AP and internet
.. note: The available modes are monitor, AP, WPS and internet
The internet adapter should be put in the _exclude_shutdown set
so that it will not be shutdown after the program exits.
"""
@@ -418,7 +418,7 @@ def is_interface_valid(self, interface_name, mode=None):
raise InvalidInterfaceError(interface_name)

# add to _exclude_shutdown set if the card is internet adapter
if mode == "internet":
if mode == "internet" or mode == "WPS":
self._exclude_shutdown.add(interface_name)
# raise an error if interface doesn't support the mode
if mode != "internet" and interface_adapter.is_managed_by_nm\
@@ -786,11 +786,15 @@ def get_perfect_card(phy_map_vifs, vif_score_tups):
# i.e. phy0 to wlan0
phy_to_vifs = defaultdict(list)
# store the phy number for the internet access
invalid_phy_number = None
invalid_phy_number = list()
# record the invalid_phy_number when it is wireless card
if args.internetinterface and pyw.iswireless(args.internetinterface):
card = pyw.getcard(args.internetinterface)
invalid_phy_number = card.phy
invalid_phy_number.append(card.phy)

if args.wpspbc_assoc_interface:
card = pyw.getcard(args.wpspbc_assoc_interface)
invalid_phy_number.append(card.phy)

# map the phy# to the virtual interface tuples
for vif in [vif for vif in pyw.interfaces() if pyw.iswireless(vif)]:
@@ -799,7 +803,7 @@ def get_perfect_card(phy_map_vifs, vif_score_tups):
score = 0
card = pyw.getcard(vif)
phy_number = card.phy
if phy_number == invalid_phy_number:
if phy_number in invalid_phy_number:
continue

supported_modes = pyw.devmodes(card)
82 changes: 58 additions & 24 deletions wifiphisher/common/opmode.py
Original file line number Diff line number Diff line change
@@ -24,8 +24,8 @@ class OpMode(object):
def __init__(self):
"""
Construct the class
:param self: An OpModeManager object
:type self: OpModeManager
:param self: An OpMode object
:type self: OpMode
:return: None
:rtype: None
"""
@@ -39,9 +39,9 @@ def __init__(self):
def initialize(self, args):
"""
Initialize the opmode manager
:param self: An OpModeManager object
:param self: An OpMode object
:param args: An argparse.Namespace object
:type self: OpModeManager
:type self: OpMode
:type args: argparse.Namespace
:return: None
:rtype: None
@@ -54,9 +54,9 @@ def initialize(self, args):
def _check_args(self, args):
"""
Checks the given arguments for logic errors.
:param self: An OpModeManager object
:param self: An OpMode object
:param args: An argparse.Namespace object
:type self: OpModeManager
:type self: OpMode
:type args: argparse.Namespace
:return: None
:rtype: None
@@ -115,14 +115,21 @@ def _check_args(self, args):
'] Only one card was found. Wifiphisher will deauth only '
'on the target AP channel')

# args.wAI should be used with args.wE
if args.wpspbc_assoc_interface and not args.wpspbc_exploit:
sys.exit(
'[' + constants.R + '!' + constants.W +
'] --wpspbc-assoc-interface (-wAI) requires --wpspbc-exploit (-wE) option.'
)

def set_opmode(self, args, network_manager):
"""
Sets the operation mode.
:param self: An OpModeManager object
:param self: An OpMode object
:param args: An argparse.Namespace object
:param network_manager: A NetworkManager object
:type self: OpModeManager
:type self: OpMode
:type args: argparse.Namespace
:type network_manager: NetworkManager
:return: None
@@ -150,17 +157,33 @@ def set_opmode(self, args, network_manager):
6) Advanced and Internet w/ 1 vif support AP/Monitor 0x6
2 cards, 3 interfaces
i) AP, ii) Extensions, iii) Internet
7) Advanced and WPS association 0x7
3 cards, 3 interfaces
i) AP, ii) Extensions (Monitor), iii) Extensions (Managed)
8) Advanced and WPS association w/ 1 vif support AP/Monitor 0x8
2 cards, 3 interfaces
i) AP, ii) Extensions (Monitor), iii) Extensions (Managed)
"""

if not args.internetinterface and not args.nojamming:
if not self._is_one_phy_interface:
self.op_mode = constants.OP_MODE1
logger.info("Starting OP_MODE1 (0x1)")
# check if there is WPS association interface
if args.wpspbc_assoc_interface:
self.op_mode = constants.OP_MODE7
logger.info("Starting OP_MODE7 (0x7)")
else:
self.op_mode = constants.OP_MODE1
logger.info("Starting OP_MODE1 (0x1)")
else:
if self._perfect_card is not None:
network_manager.add_virtual_interface(self._perfect_card)
self.op_mode = constants.OP_MODE5
logger.info("Starting OP_MODE5 (0x5)")
# check if there is WPS association interface
if args.wpspbc_assoc_interface:
self.op_mode = constants.OP_MODE8
logger.info("Starting OP_MODE8 (0x8)")
else:
self.op_mode = constants.OP_MODE5
logger.info("Starting OP_MODE5 (0x5)")
if args.internetinterface and not args.nojamming:
if not self._is_one_phy_interface:
self.op_mode = constants.OP_MODE2
@@ -180,8 +203,8 @@ def set_opmode(self, args, network_manager):

def internet_sharing_enabled(self):
"""
:param self: An OpModeManager object
:type self: OpModeManager
:param self: An OpMode object
:type self: OpMode
:return: True if we are operating in a mode that shares Internet
access.
:rtype: bool
@@ -191,44 +214,55 @@ def internet_sharing_enabled(self):

def advanced_enabled(self):
"""
:param self: An OpModeManager object
:type self: OpModeManager
:param self: An OpMode object
:type self: OpMode
:return: True if we are operating in an advanced
mode (a mode that leverages two network cards)
:rtype: bool
"""

return self.op_mode in [
constants.OP_MODE1, constants.OP_MODE2, constants.OP_MODE5,
constants.OP_MODE6
constants.OP_MODE6, constants.OP_MODE7, constants.OP_MODE8
]

def deauth_enabled(self):
"""
:param self: An OpModeManager object
:type self: OpModeManager
:param self: An OpMode object
:type self: OpMode
:return: True if we are operating in a mode
that deauth is enabled.
:rtype: bool
"""

return self.op_mode in [
constants.OP_MODE1, constants.OP_MODE2, constants.OP_MODE5,
constants.OP_MODE6
constants.OP_MODE6, constants.OP_MODE7, constants.OP_MODE8
]

def freq_hopping_enabled(self):
"""
:param self: An OpModeManager object
:type self: OpModeManager
:param self: An OpMode object
:type self: OpMode
:return: True if we are separating the wireless cards
for jamming and lunching AP.
:rtype: bool
..note: MODE5 and MODE6 only use one card to do deauth and
lunch ap so it is not allowed to do frequency hopping.
"""

return self.op_mode in [constants.OP_MODE1, constants.OP_MODE2]
return self.op_mode in [
constants.OP_MODE1, constants.OP_MODE2, constants.OP_MODE7
]

def assoc_enabled(self):
"""
:param self: An OpMode object
:type self: OpMode
:return: True if we are using managed Extensions(that associate to WLANs)
:rtype: bool
"""
return self.op_mode in [constants.OP_MODE7, constants.OP_MODE8]


def validate_ap_interface(interface):
@@ -241,7 +275,7 @@ def validate_ap_interface(interface):
:rtype: str
:raises: argparse.ArgumentTypeError in case of invalid interface
"""

if not(pyric.pyw.iswireless(interface) and \
pyric.pyw.isinterface(interface) and \
interfaces.does_have_mode(interface, "AP")):
Loading

0 comments on commit 1d83205

Please sign in to comment.