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