Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
derv82
GitHub Repository: derv82/wifite2
Path: blob/master/wifite/tools/airodump.py
412 views
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
4
from .dependency import Dependency
5
from .tshark import Tshark
6
from .wash import Wash
7
from ..util.process import Process
8
from ..config import Configuration
9
from ..model.target import Target, WPSState
10
from ..model.client import Client
11
12
import os, time
13
14
class Airodump(Dependency):
15
''' Wrapper around airodump-ng program '''
16
dependency_required = True
17
dependency_name = 'airodump-ng'
18
dependency_url = 'https://www.aircrack-ng.org/install.html'
19
20
def __init__(self, interface=None, channel=None, encryption=None,\
21
wps=WPSState.UNKNOWN, target_bssid=None,
22
output_file_prefix='airodump',\
23
ivs_only=False, skip_wps=False, delete_existing_files=True):
24
'''Sets up airodump arguments, doesn't start process yet.'''
25
26
Configuration.initialize()
27
28
if interface is None:
29
interface = Configuration.interface
30
if interface is None:
31
raise Exception('Wireless interface must be defined (-i)')
32
self.interface = interface
33
34
self.targets = []
35
36
if channel is None:
37
channel = Configuration.target_channel
38
self.channel = channel
39
self.five_ghz = Configuration.five_ghz
40
41
self.encryption = encryption
42
self.wps = wps
43
44
self.target_bssid = target_bssid
45
self.output_file_prefix = output_file_prefix
46
self.ivs_only = ivs_only
47
self.skip_wps = skip_wps
48
49
# For tracking decloaked APs (previously were hidden)
50
self.decloaking = False
51
self.decloaked_bssids = set()
52
self.decloaked_times = {} # Map of BSSID(str) -> epoch(int) of last deauth
53
54
self.delete_existing_files = delete_existing_files
55
56
57
def __enter__(self):
58
'''
59
Setting things up for this context.
60
Called at start of 'with Airodump(...) as x:'
61
Actually starts the airodump process.
62
'''
63
if self.delete_existing_files:
64
self.delete_airodump_temp_files(self.output_file_prefix)
65
66
self.csv_file_prefix = Configuration.temp() + self.output_file_prefix
67
68
# Build the command
69
command = [
70
'airodump-ng',
71
self.interface,
72
'-a', # Only show associated clients
73
'-w', self.csv_file_prefix, # Output file prefix
74
'--write-interval', '1' # Write every second
75
]
76
if self.channel: command.extend(['-c', str(self.channel)])
77
elif self.five_ghz: command.extend(['--band', 'a'])
78
79
if self.encryption: command.extend(['--enc', self.encryption])
80
if self.wps: command.extend(['--wps'])
81
if self.target_bssid: command.extend(['--bssid', self.target_bssid])
82
83
if self.ivs_only: command.extend(['--output-format', 'ivs,csv'])
84
else: command.extend(['--output-format', 'pcap,csv'])
85
86
# Start the process
87
self.pid = Process(command, devnull=True)
88
return self
89
90
91
def __exit__(self, type, value, traceback):
92
'''
93
Tearing things down since the context is being exited.
94
Called after 'with Airodump(...)' goes out of scope.
95
'''
96
# Kill the process
97
self.pid.interrupt()
98
99
if self.delete_existing_files:
100
self.delete_airodump_temp_files(self.output_file_prefix)
101
102
103
def find_files(self, endswith=None):
104
return self.find_files_by_output_prefix(self.output_file_prefix, endswith=endswith)
105
106
@classmethod
107
def find_files_by_output_prefix(cls, output_file_prefix, endswith=None):
108
''' Finds all files in the temp directory that start with the output_file_prefix '''
109
result = []
110
temp = Configuration.temp()
111
for fil in os.listdir(temp):
112
if not fil.startswith(output_file_prefix):
113
continue
114
115
if endswith is None or fil.endswith(endswith):
116
result.append(os.path.join(temp, fil))
117
118
return result
119
120
@classmethod
121
def delete_airodump_temp_files(cls, output_file_prefix):
122
'''
123
Deletes airodump* files in the temp directory.
124
Also deletes replay_*.cap and *.xor files in pwd.
125
'''
126
# Remove all temp files
127
for fil in cls.find_files_by_output_prefix(output_file_prefix):
128
os.remove(fil)
129
130
# Remove .cap and .xor files from pwd
131
for fil in os.listdir('.'):
132
if fil.startswith('replay_') and fil.endswith('.cap') or fil.endswith('.xor'):
133
os.remove(fil)
134
135
# Remove replay/cap/xor files from temp
136
temp_dir = Configuration.temp()
137
for fil in os.listdir(temp_dir):
138
if fil.startswith('replay_') and fil.endswith('.cap') or fil.endswith('.xor'):
139
os.remove(os.path.join(temp_dir, fil))
140
141
def get_targets(self, old_targets=[], apply_filter=True):
142
''' Parses airodump's CSV file, returns list of Targets '''
143
144
# Find the .CSV file
145
csv_filename = None
146
for fil in self.find_files(endswith='.csv'):
147
csv_filename = fil # Found the file
148
break
149
150
if csv_filename is None or not os.path.exists(csv_filename):
151
return self.targets # No file found
152
153
targets = Airodump.get_targets_from_csv(csv_filename)
154
for old_target in old_targets:
155
for target in targets:
156
if old_target.bssid == target.bssid:
157
target.wps = old_target.wps
158
159
# Check targets for WPS
160
if not self.skip_wps:
161
capfile = csv_filename[:-3] + 'cap'
162
try:
163
Tshark.check_for_wps_and_update_targets(capfile, targets)
164
except ValueError:
165
# No tshark, or it failed. Fall-back to wash
166
Wash.check_for_wps_and_update_targets(capfile, targets)
167
168
if apply_filter:
169
# Filter targets based on encryption & WPS capability
170
targets = Airodump.filter_targets(targets, skip_wps=self.skip_wps)
171
172
# Sort by power
173
targets.sort(key=lambda x: x.power, reverse=True)
174
175
# Identify decloaked targets
176
for old_target in self.targets:
177
for new_target in targets:
178
if old_target.bssid != new_target.bssid:
179
continue
180
181
if new_target.essid_known and not old_target.essid_known:
182
# We decloaked a target!
183
new_target.decloaked = True
184
self.decloaked_bssids.add(new_target.bssid)
185
186
self.targets = targets
187
self.deauth_hidden_targets()
188
189
return self.targets
190
191
192
@staticmethod
193
def get_targets_from_csv(csv_filename):
194
'''Returns list of Target objects parsed from CSV file.'''
195
targets = []
196
import csv
197
with open(csv_filename, 'r') as csvopen:
198
lines = []
199
for line in csvopen:
200
line = line.replace('\0', '')
201
lines.append(line)
202
csv_reader = csv.reader(lines,
203
delimiter=',',
204
quoting=csv.QUOTE_ALL,
205
skipinitialspace=True,
206
escapechar='\\')
207
208
hit_clients = False
209
for row in csv_reader:
210
# Each 'row' is a list of fields for a target/client
211
212
if len(row) == 0: continue
213
214
if row[0].strip() == 'BSSID':
215
# This is the 'header' for the list of Targets
216
hit_clients = False
217
continue
218
219
elif row[0].strip() == 'Station MAC':
220
# This is the 'header' for the list of Clients
221
hit_clients = True
222
continue
223
224
if hit_clients:
225
# The current row corresponds to a 'Client' (computer)
226
try:
227
client = Client(row)
228
except (IndexError, ValueError) as e:
229
# Skip if we can't parse the client row
230
continue
231
232
if 'not associated' in client.bssid:
233
# Ignore unassociated clients
234
continue
235
236
# Add this client to the appropriate Target
237
for t in targets:
238
if t.bssid == client.bssid:
239
t.clients.append(client)
240
break
241
242
else:
243
# The current row corresponds to a 'Target' (router)
244
try:
245
target = Target(row)
246
targets.append(target)
247
except Exception:
248
continue
249
250
return targets
251
252
@staticmethod
253
def filter_targets(targets, skip_wps=False):
254
''' Filters targets based on Configuration '''
255
result = []
256
# Filter based on Encryption
257
for target in targets:
258
if Configuration.clients_only and len(target.clients) == 0:
259
continue
260
if 'WEP' in Configuration.encryption_filter and 'WEP' in target.encryption:
261
result.append(target)
262
elif 'WPA' in Configuration.encryption_filter and 'WPA' in target.encryption:
263
result.append(target)
264
elif 'WPS' in Configuration.encryption_filter and target.wps in [WPSState.UNLOCKED, WPSState.LOCKED]:
265
result.append(target)
266
elif skip_wps:
267
result.append(target)
268
269
# Filter based on BSSID/ESSID
270
bssid = Configuration.target_bssid
271
essid = Configuration.target_essid
272
i = 0
273
while i < len(result):
274
if result[i].essid is not None and Configuration.ignore_essid is not None and Configuration.ignore_essid.lower() in result[i].essid.lower():
275
result.pop(i)
276
elif bssid and result[i].bssid.lower() != bssid.lower():
277
result.pop(i)
278
elif essid and result[i].essid and result[i].essid.lower() != essid.lower():
279
result.pop(i)
280
else:
281
i += 1
282
return result
283
284
def deauth_hidden_targets(self):
285
'''
286
Sends deauths (to broadcast and to each client) for all
287
targets (APs) that have unknown ESSIDs (hidden router names).
288
'''
289
self.decloaking = False
290
291
if Configuration.no_deauth:
292
return # Do not deauth if requested
293
294
if self.channel is None:
295
return # Do not deauth if channel is not fixed.
296
297
# Reusable deauth command
298
deauth_cmd = [
299
'aireplay-ng',
300
'-0', # Deauthentication
301
str(Configuration.num_deauths), # Number of deauth packets to send
302
'--ignore-negative-one'
303
]
304
305
for target in self.targets:
306
if target.essid_known:
307
continue
308
309
now = int(time.time())
310
secs_since_decloak = now - self.decloaked_times.get(target.bssid, 0)
311
312
if secs_since_decloak < 30:
313
continue # Decloak every AP once every 30 seconds
314
315
self.decloaking = True
316
self.decloaked_times[target.bssid] = now
317
if Configuration.verbose > 1:
318
from ..util.color import Color
319
Color.pe('{C} [?] Deauthing %s (broadcast & %d clients){W}' % (target.bssid, len(target.clients)))
320
321
# Deauth broadcast
322
iface = Configuration.interface
323
Process(deauth_cmd + ['-a', target.bssid, iface])
324
325
# Deauth clients
326
for client in target.clients:
327
Process(deauth_cmd + ['-a', target.bssid, '-c', client.bssid, iface])
328
329
if __name__ == '__main__':
330
''' Example usage. wlan0mon should be in Monitor Mode '''
331
with Airodump() as airodump:
332
333
from time import sleep
334
sleep(7)
335
336
from ..util.color import Color
337
338
targets = airodump.get_targets()
339
for idx, target in enumerate(targets, start=1):
340
Color.pl(' {G}%s %s' % (str(idx).rjust(3), target.to_str()))
341
342
Configuration.delete_temp()
343
344