Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/analyze/apply_pot.rb
19612 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Auxiliary
7
include Msf::Auxiliary::PasswordCracker
8
9
def initialize
10
super(
11
'Name' => 'Apply Pot File To Hashes',
12
'Description' => %(
13
This module uses a John the Ripper or Hashcat .pot file to crack any password
14
hashes in the creds database instantly. JtR's --show functionality is used to
15
help combine all the passwords into an easy to use format.
16
),
17
'Author' => ['h00die'],
18
'License' => MSF_LICENSE,
19
'Actions' => [
20
['john', { 'Description' => 'Use John the Ripper' }],
21
# ['hashcat', 'Description' => 'Use Hashcat'], # removed for simplicity
22
],
23
'DefaultAction' => 'john',
24
'Notes' => {
25
'Stability' => [CRASH_SAFE],
26
'SideEffects' => [],
27
'Reliability' => []
28
}
29
)
30
deregister_options('ITERATION_TIMEOUT')
31
deregister_options('CUSTOM_WORDLIST')
32
deregister_options('KORELOGIC')
33
deregister_options('MUTATE')
34
deregister_options('USE_CREDS')
35
deregister_options('USE_DB_INFO')
36
deregister_options('USE_DEFAULT_WORDLIST')
37
deregister_options('USE_ROOT_WORDS')
38
deregister_options('USE_HOSTNAMES')
39
end
40
41
# Not all hash formats include an 'id' field, which corresponds which db entry
42
# an item is to its hash. This can be problematic, especially when a username
43
# is used as a salt. Due to all the variations, we make a small HashLookup
44
# class to handle all the fields for easier lookup later.
45
class HashLookup
46
attr_accessor :db_hash, :jtr_hash, :username, :id
47
48
def initialize(db_hash, jtr_hash, username, id)
49
@db_hash = db_hash
50
@jtr_hash = jtr_hash
51
@username = username
52
@id = id
53
end
54
end
55
56
def show_run_command(cracker_instance)
57
return unless datastore['ShowCommand']
58
59
cmd = cracker_instance.show_command
60
print_status(" Cracking Command: #{cmd.join(' ')}")
61
end
62
63
def run
64
cracker = new_password_cracker(action.name)
65
66
lookups = []
67
68
# create one massive hash file with all the hashes
69
hashlist = Rex::Quickfile.new('hashes_tmp')
70
framework.db.creds(workspace: myworkspace).each do |core|
71
next if core.private.type == 'Metasploit::Credential::Password'
72
73
jtr_hash = Metasploit::Framework::PasswordCracker::JtR::Formatter.hash_to_jtr(core)
74
hashlist.puts jtr_hash
75
lookups << HashLookup.new(core.private.data, jtr_hash, core.public, core.id)
76
end
77
hashlist.close
78
cracker.hash_path = hashlist.path
79
print_status "Hashes Written out to #{hashlist.path}"
80
cleanup_files = [cracker.hash_path]
81
82
# cycle through all hash types we dump asking jtr to show us
83
# cracked passwords. The advantage to this vs just comparing
84
# john.pot to the hashes directly is we use jtr to recombine
85
# lanman, and other assorted nuances
86
[
87
'bcrypt', 'bsdicrypt', 'descrypt', 'lm',
88
'mscash', 'mscash2', 'netntlm', 'netntlmv2',
89
'md5crypt', 'mysql', 'mysql-sha1', 'mssql', 'mssql05', 'mssql12',
90
'oracle', 'oracle11', 'oracle12c', 'dynamic_1506', # oracles
91
'dynamic_1034', # postgres
92
# 'android-sha1', 'android-samsung-sha1', 'android-md5', # mobile is done with hashcat, so skip these
93
'PBKDF2-HMAC-SHA1', 'phpass', 'mediawiki', 'pbkdf2-sha256', # webapps
94
'xsha', 'xsha512', 'PBKDF2-HMAC-SHA512', # osx
95
'nt', # nt needs to be 2nd to last because it can hit on android hashes
96
'crypt' # crypt NEEDS TO BE LAST so it doesn't accidentally read in other compatible hashes
97
].each do |format|
98
print_status("Checking #{format} hashes against pot file")
99
cracker.format = format
100
show_run_command(cracker)
101
cracker.each_cracked_password.each do |password_line|
102
password_line.chomp!
103
next if password_line.blank? || password_line.nil?
104
105
fields = password_line.split(':')
106
core_id = nil
107
case format
108
when 'descrypt'
109
next unless fields.count >= 3
110
111
username = fields.shift
112
core_id = fields.pop
113
4.times { fields.pop } # Get rid of extra :
114
when 'netntlm', 'netntlmv2'
115
next unless fields.count >= 7
116
117
username = fields.shift
118
core_id = fields.pop
119
9.times { fields.pop }
120
when 'md5crypt', 'bsdicrypt', 'crypt', 'bcrypt', 'xsha', 'xsha512'
121
next unless fields.count >= 7
122
123
username = fields.shift
124
core_id = fields.pop
125
4.times { fields.pop }
126
when 'PBKDF2-HMAC-SHA512'
127
next unless fields.count >= 2
128
129
username = fields.shift
130
core_id = fields.pop
131
when 'mssql', 'mssql05', 'mssql12', 'mysql', 'mysql-sha1',
132
'oracle', 'dynamic_1506', 'oracle11', 'oracle12c',
133
'PBKDF2-HMAC-SHA1', 'phpass', 'mediawiki', 'pbkdf2-sha256',
134
'mscash', 'mscash2'
135
next unless fields.count >= 3
136
137
username = fields.shift
138
core_id = fields.pop
139
when 'dynamic_1034' # postgres
140
next unless fields.count >= 2
141
142
username = fields.shift
143
fields.join(':')
144
# unfortunately to match up all the fields we need to pull the hash
145
# field as well, and it is only available in the pot file.
146
pot = cracker.pot || cracker.john_pot_file
147
148
File.open(pot, 'rb').each do |line|
149
next unless line.start_with?('$dynamic_1034$') # postgres format
150
151
lookups.each do |l|
152
pot_hash = line.split(':')[0]
153
raw_pot_hash = pot_hash.split('$')[2]
154
next unless l.username.to_s == username &&
155
l.jtr_hash == "#{username}:$dynamic_1034$#{raw_pot_hash}" &&
156
l.db_hash == raw_pot_hash
157
158
core_id = l.id
159
break
160
end
161
end
162
when 'lm', 'nt'
163
next unless fields.count >= 7
164
165
username = fields.shift
166
core_id = fields.pop
167
2.times { fields.pop }
168
# get the NT and LM hashes
169
nt_hash = fields.pop
170
fields.pop
171
core_id = fields.pop
172
password = fields.join(':')
173
if format == 'lm'
174
if password.blank?
175
if nt_hash == Metasploit::Credential::NTLMHash::BLANK_NT_HASH
176
password = ''
177
else
178
next
179
end
180
end
181
password = john_lm_upper_to_ntlm(password, nt_hash)
182
next if password.nil?
183
end
184
fields = password.split(':') # for consistency on the following join out of the case
185
end
186
next if core_id.nil?
187
188
password = fields.join(':')
189
print_good "#{username}:#{password}"
190
# android hashes will also crack here, but the output fields are in a different order
191
# check if core_id is an int or not, for android hashes it wont convert
192
core_id_int = begin
193
Integer(core_id)
194
rescue StandardError
195
nil
196
end
197
next if core_id_int.nil?
198
199
create_cracked_credential(username: username, password: password, core_id: core_id)
200
end
201
end
202
if datastore['DeleteTempFiles']
203
cleanup_files.each do |f|
204
File.delete(f)
205
end
206
end
207
end
208
end
209
210