CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/analyze/apply_pot.rb
Views: 1904
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
7
class MetasploitModule < Msf::Auxiliary
8
include Msf::Auxiliary::PasswordCracker
9
10
def initialize
11
super(
12
'Name' => 'Apply Pot File To Hashes',
13
'Description' => %Q{
14
This module uses a John the Ripper or Hashcat .pot file to crack any password
15
hashes in the creds database instantly. JtR's --show functionality is used to
16
help combine all the passwords into an easy to use format.
17
},
18
'Author' => ['h00die'],
19
'License' => MSF_LICENSE,
20
'Actions' =>
21
[
22
['john', 'Description' => 'Use John the Ripper'],
23
# ['hashcat', 'Description' => 'Use Hashcat'], # removed for simplicity
24
],
25
'DefaultAction' => 'john',
26
)
27
deregister_options('ITERATION_TIMEOUT')
28
deregister_options('CUSTOM_WORDLIST')
29
deregister_options('KORELOGIC')
30
deregister_options('MUTATE')
31
deregister_options('USE_CREDS')
32
deregister_options('USE_DB_INFO')
33
deregister_options('USE_DEFAULT_WORDLIST')
34
deregister_options('USE_ROOT_WORDS')
35
deregister_options('USE_HOSTNAMES')
36
37
end
38
39
# Not all hash formats include an 'id' field, which corresponds which db entry
40
# an item is to its hash. This can be problematic, especially when a username
41
# is used as a salt. Due to all the variations, we make a small HashLookup
42
# class to handle all the fields for easier lookup later.
43
class HashLookup
44
attr_accessor :db_hash
45
attr_accessor :jtr_hash
46
attr_accessor :username
47
attr_accessor :id
48
49
def initialize(db_hash, jtr_hash, username, id)
50
@db_hash = db_hash
51
@jtr_hash = jtr_hash
52
@username = username
53
@id = id
54
end
55
end
56
57
def show_run_command(cracker_instance)
58
return unless datastore['ShowCommand']
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
jtr_hash = Metasploit::Framework::PasswordCracker::JtR::Formatter.hash_to_jtr(core)
73
hashlist.puts jtr_hash
74
lookups << HashLookup.new(core.private.data, jtr_hash, core.public, core.id)
75
end
76
hashlist.close
77
cracker.hash_path = hashlist.path
78
print_status "Hashes Written out to #{hashlist.path}"
79
cleanup_files = [cracker.hash_path]
80
81
# cycle through all hash types we dump asking jtr to show us
82
# cracked passwords. The advantage to this vs just comparing
83
# john.pot to the hashes directly is we use jtr to recombine
84
# lanman, and other assorted nuances
85
['bcrypt', 'bsdicrypt', 'crypt', 'descrypt', 'lm', 'nt',
86
'md5crypt', 'mysql', 'mysql-sha1', 'mssql', 'mssql05', 'mssql12',
87
'oracle', 'oracle11', 'oracle12c', 'dynamic_1506', #oracles
88
'dynamic_1034' #postgres
89
].each do |format|
90
91
print_status("Checking #{format} hashes against pot file")
92
cracker.format = format
93
show_run_command(cracker)
94
cracker.each_cracked_password.each do |password_line|
95
password_line.chomp!
96
next if password_line.blank? || password_line.nil?
97
fields = password_line.split(":")
98
core_id = nil
99
case format
100
when 'descrypt'
101
next unless fields.count >=3
102
username = fields.shift
103
core_id = fields.pop
104
4.times { fields.pop } # Get rid of extra :
105
when 'md5crypt', 'descrypt', 'bsdicrypt', 'crypt', 'bcrypt'
106
next unless fields.count >=7
107
username = fields.shift
108
core_id = fields.pop
109
4.times { fields.pop }
110
when 'mssql', 'mssql05', 'mssql12', 'mysql', 'mysql-sha1',
111
'oracle', 'dynamic_1506', 'oracle11', 'oracle12c'
112
next unless fields.count >=3
113
username = fields.shift
114
core_id = fields.pop
115
when 'dynamic_1506' #oracle H code
116
next unless fields.count >=3
117
username = fields.shift
118
core_id = fields.pop
119
when 'dynamic_1034' #postgres
120
next unless fields.count >=2
121
username = fields.shift
122
password = fields.join(':')
123
# unfortunately to match up all the fields we need to pull the hash
124
# field as well, and it is only available in the pot file.
125
pot = cracker.pot || cracker.john_pot_file
126
127
File.open(pot, 'rb').each do |line|
128
if line.start_with?('$dynamic_1034$') #postgres format
129
lookups.each do |l|
130
pot_hash = line.split(":")[0]
131
raw_pot_hash = pot_hash.split('$')[2]
132
if l.username.to_s == username &&
133
l.jtr_hash == "#{username}:$dynamic_1034$#{raw_pot_hash}" &&
134
l.db_hash == raw_pot_hash
135
core_id = l.id
136
break
137
end
138
end
139
end
140
end
141
when 'lm', 'nt'
142
next unless fields.count >=7
143
username = fields.shift
144
core_id = fields.pop
145
2.times{ fields.pop }
146
# get the NT and LM hashes
147
nt_hash = fields.pop
148
lm_hash = fields.pop
149
core_id = fields.pop
150
password = fields.join(':')
151
if format == 'lm'
152
if password.blank?
153
if nt_hash == Metasploit::Credential::NTLMHash::BLANK_NT_HASH
154
password = ''
155
else
156
next
157
end
158
end
159
password = john_lm_upper_to_ntlm(password, nt_hash)
160
next if password.nil?
161
end
162
fields = password.split(':') #for consistency on the following join out of the case
163
end
164
unless core_id.nil?
165
password = fields.join(':')
166
print_good "#{username}:#{password}"
167
create_cracked_credential( username: username, password: password, core_id: core_id)
168
end
169
end
170
end
171
if datastore['DeleteTempFiles']
172
cleanup_files.each do |f|
173
File.delete(f)
174
end
175
end
176
end
177
end
178
179