Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
derv82
GitHub Repository: derv82/wifite2
Path: blob/master/wifite/model/handshake.py
412 views
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
4
from ..util.process import Process
5
from ..util.color import Color
6
from ..tools.tshark import Tshark
7
from ..tools.pyrit import Pyrit
8
9
import re, os
10
11
class Handshake(object):
12
13
def __init__(self, capfile, bssid=None, essid=None):
14
self.capfile = capfile
15
self.bssid = bssid
16
self.essid = essid
17
18
19
def divine_bssid_and_essid(self):
20
'''
21
Tries to find BSSID and ESSID from cap file.
22
Sets this instances 'bssid' and 'essid' instance fields.
23
'''
24
25
# We can get BSSID from the .cap filename if Wifite captured it.
26
# ESSID is stripped of non-printable characters, so we can't rely on that.
27
if self.bssid is None:
28
hs_regex = re.compile(r'^.*handshake_\w+_([0-9A-F\-]{17})_.*\.cap$', re.IGNORECASE)
29
match = hs_regex.match(self.capfile)
30
if match:
31
self.bssid = match.group(1).replace('-', ':')
32
33
# Get list of bssid/essid pairs from cap file
34
pairs = Tshark.bssid_essid_pairs(self.capfile, bssid=self.bssid)
35
36
if len(pairs) == 0:
37
pairs = self.pyrit_handshakes() # Find bssid/essid pairs that have handshakes in Pyrit
38
39
if len(pairs) == 0 and not self.bssid and not self.essid:
40
# Tshark and Pyrit failed us, nothing else we can do.
41
raise ValueError('Cannot find BSSID or ESSID in cap file %s' % self.capfile)
42
43
if not self.essid and not self.bssid:
44
# We do not know the bssid nor the essid
45
# TODO: Display menu for user to select from list
46
# HACK: Just use the first one we see
47
self.bssid = pairs[0][0]
48
self.essid = pairs[0][1]
49
Color.pl('{!} {O}Warning{W}: {O}Arbitrarily selected ' +
50
'{R}bssid{O} {C}%s{O} and {R}essid{O} "{C}%s{O}"{W}' % (self.bssid, self.essid))
51
52
elif not self.bssid:
53
# We already know essid
54
for (bssid, essid) in pairs:
55
if self.essid == essid:
56
Color.pl('{+} Discovered bssid {C}%s{W}' % bssid)
57
self.bssid = bssid
58
break
59
60
elif not self.essid:
61
# We already know bssid
62
for (bssid, essid) in pairs:
63
if self.bssid.lower() == bssid.lower():
64
Color.pl('{+} Discovered essid "{C}%s{W}"' % essid)
65
self.essid = essid
66
break
67
68
69
def has_handshake(self):
70
if not self.bssid or not self.essid:
71
self.divine_bssid_and_essid()
72
73
if len(self.tshark_handshakes()) > 0: return True
74
if len(self.pyrit_handshakes()) > 0: return True
75
76
# TODO: Can we trust cowpatty & aircrack?
77
#if len(self.cowpatty_handshakes()) > 0: return True
78
#if len(self.aircrack_handshakes()) > 0: return True
79
80
return False
81
82
83
def tshark_handshakes(self):
84
'''Returns list[tuple] of BSSID & ESSID pairs (ESSIDs are always `None`).'''
85
tshark_bssids = Tshark.bssids_with_handshakes(self.capfile, bssid=self.bssid)
86
return [(bssid, None) for bssid in tshark_bssids]
87
88
89
def cowpatty_handshakes(self):
90
'''Returns list[tuple] of BSSID & ESSID pairs (BSSIDs are always `None`).'''
91
if not Process.exists('cowpatty'):
92
return []
93
if not self.essid:
94
return [] # We need a essid for cowpatty :(
95
96
command = [
97
'cowpatty',
98
'-r', self.capfile,
99
'-s', self.essid,
100
'-c' # Check for handshake
101
]
102
103
proc = Process(command, devnull=False)
104
for line in proc.stdout().split('\n'):
105
if 'Collected all necessary data to mount crack against WPA' in line:
106
return [(None, self.essid)]
107
return []
108
109
110
def pyrit_handshakes(self):
111
'''Returns list[tuple] of BSSID & ESSID pairs.'''
112
return Pyrit.bssid_essid_with_handshakes(
113
self.capfile, bssid=self.bssid, essid=self.essid)
114
115
116
def aircrack_handshakes(self):
117
'''Returns tuple (BSSID,None) if aircrack thinks self.capfile contains a handshake / can be cracked'''
118
if not self.bssid:
119
return [] # Aircrack requires BSSID
120
121
command = 'echo "" | aircrack-ng -a 2 -w - -b %s "%s"' % (self.bssid, self.capfile)
122
(stdout, stderr) = Process.call(command)
123
124
if 'passphrase not in dictionary' in stdout.lower():
125
return [(self.bssid, None)]
126
else:
127
return []
128
129
130
def analyze(self):
131
'''Prints analysis of handshake capfile'''
132
self.divine_bssid_and_essid()
133
134
if Tshark.exists():
135
Handshake.print_pairs(self.tshark_handshakes(), self.capfile, 'tshark')
136
137
if Pyrit.exists():
138
Handshake.print_pairs(self.pyrit_handshakes(), self.capfile, 'pyrit')
139
140
if Process.exists('cowpatty'):
141
Handshake.print_pairs(self.cowpatty_handshakes(), self.capfile, 'cowpatty')
142
143
Handshake.print_pairs(self.aircrack_handshakes(), self.capfile, 'aircrack')
144
145
146
def strip(self, outfile=None):
147
# XXX: This method might break aircrack-ng, use at own risk.
148
'''
149
Strips out packets from handshake that aren't necessary to crack.
150
Leaves only handshake packets and SSID broadcast (for discovery).
151
Args:
152
outfile - Filename to save stripped handshake to.
153
If outfile==None, overwrite existing self.capfile.
154
'''
155
if not outfile:
156
outfile = self.capfile + '.temp'
157
replace_existing_file = True
158
else:
159
replace_existing_file = False
160
161
cmd = [
162
'tshark',
163
'-r', self.capfile, # input file
164
'-Y', 'wlan.fc.type_subtype == 0x08 || wlan.fc.type_subtype == 0x05 || eapol', # filter
165
'-w', outfile # output file
166
]
167
proc = Process(cmd)
168
proc.wait()
169
if replace_existing_file:
170
from shutil import copy
171
copy(outfile, self.capfile)
172
os.remove(outfile)
173
pass
174
175
176
@staticmethod
177
def print_pairs(pairs, capfile, tool=None):
178
'''
179
Prints out BSSID and/or ESSID given a list of tuples (bssid,essid)
180
'''
181
tool_str = ''
182
if tool is not None:
183
tool_str = '{C}%s{W}: ' % tool.rjust(8)
184
185
if len(pairs) == 0:
186
Color.pl('{!} %s.cap file {R}does not{O} contain a valid handshake{W}' % (tool_str))
187
return
188
189
for (bssid, essid) in pairs:
190
out_str = '{+} %s.cap file {G}contains a valid handshake{W} for' % tool_str
191
if bssid and essid:
192
Color.pl('%s {G}%s{W} ({G}%s{W})' % (out_str, bssid, essid))
193
elif bssid:
194
Color.pl('%s {G}%s{W}' % (out_str, bssid))
195
elif essid:
196
Color.pl('%s ({G}%s{W})' % (out_str, essid))
197
198
199
@staticmethod
200
def check():
201
''' Analyzes .cap file(s) for handshake '''
202
from ..config import Configuration
203
if Configuration.check_handshake == '<all>':
204
Color.pl('{+} checking all handshakes in {G}"./hs"{W} directory\n')
205
try:
206
capfiles = [os.path.join('hs', x) for x in os.listdir('hs') if x.endswith('.cap')]
207
except OSError as e:
208
capfiles = []
209
if len(capfiles) == 0:
210
Color.pl('{!} {R}no .cap files found in {O}"./hs"{W}\n')
211
else:
212
capfiles = [Configuration.check_handshake]
213
214
for capfile in capfiles:
215
Color.pl('{+} checking for handshake in .cap file {C}%s{W}' % capfile)
216
if not os.path.exists(capfile):
217
Color.pl('{!} {O}.cap file {C}%s{O} not found{W}' % capfile)
218
return
219
hs = Handshake(capfile, bssid=Configuration.target_bssid, essid=Configuration.target_essid)
220
hs.analyze()
221
Color.pl('')
222
223
224
if __name__ == '__main__':
225
print('With BSSID & ESSID specified:')
226
hs = Handshake('./tests/files/handshake_has_1234.cap', bssid='18:d6:c7:6d:6b:18', essid='YZWifi')
227
hs.analyze()
228
print('has_hanshake() =', hs.has_handshake())
229
230
print('\nWith BSSID, but no ESSID specified:')
231
hs = Handshake('./tests/files/handshake_has_1234.cap', bssid='18:d6:c7:6d:6b:18')
232
hs.analyze()
233
print('has_hanshake() =', hs.has_handshake())
234
235
print('\nWith ESSID, but no BSSID specified:')
236
hs = Handshake('./tests/files/handshake_has_1234.cap', essid='YZWifi')
237
hs.analyze()
238
print('has_hanshake() =', hs.has_handshake())
239
240
print('\nWith neither BSSID nor ESSID specified:')
241
hs = Handshake('./tests/files/handshake_has_1234.cap')
242
try:
243
hs.analyze()
244
print('has_hanshake() =', hs.has_handshake())
245
except Exception as e:
246
Color.pl('{O}Error during Handshake.analyze(): {R}%s{W}' % e)
247
248