Merge branch 'feature/MSP-9713/jtr_crack_fast' into staging/electro-release
commit
70fd3344fd
|
@ -5,6 +5,7 @@
|
|||
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/auxiliary/jtr'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
|
@ -27,132 +28,96 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
|
||||
def run
|
||||
wordlist = Rex::Quickfile.new("jtrtmp")
|
||||
hashlist = Rex::Quickfile.new("jtrtmp")
|
||||
cracker = new_john_cracker
|
||||
|
||||
begin
|
||||
# Seed the wordlist with usernames, passwords, and hostnames
|
||||
seed = []
|
||||
#generate our wordlist and close the file handle
|
||||
wordlist = wordlist_file
|
||||
wordlist.close
|
||||
print_status "Wordlist file written out to #{wordlist.path}"
|
||||
cracker.wordlist = wordlist.path
|
||||
cracker.hash_path = hash_file
|
||||
|
||||
myworkspace.hosts.find(:all).each {|o| seed << john_expand_word( o.name ) if o.name }
|
||||
myworkspace.creds.each do |o|
|
||||
seed << john_expand_word( o.user ) if o.user
|
||||
seed << john_expand_word( o.pass ) if (o.pass and o.ptype !~ /hash/)
|
||||
['lm','nt'].each do |format|
|
||||
# dupe our original cracker so we can safely change options between each run
|
||||
cracker_instance = cracker.dup
|
||||
cracker_instance.format = format
|
||||
print_status "Cracking #{format} hashes in normal wordlist mode..."
|
||||
cracker_instance.crack do |line|
|
||||
print_status line.chomp
|
||||
end
|
||||
|
||||
# Grab any known passwords out of the john.pot file
|
||||
john_cracked_passwords.values {|v| seed << v }
|
||||
|
||||
# Write the seed file
|
||||
wordlist.write( seed.flatten.uniq.join("\n") + "\n" )
|
||||
|
||||
print_status("Seeded the password database with #{seed.length} words...")
|
||||
|
||||
# Append the standard JtR wordlist as well
|
||||
::File.open(john_wordlist_path, "rb") do |fd|
|
||||
wordlist.write fd.read(fd.stat.size)
|
||||
print_status "Cracking #{format} hashes in single mode..."
|
||||
cracker_instance.rules = 'single'
|
||||
cracker_instance.crack do |line|
|
||||
print_status line.chomp
|
||||
end
|
||||
|
||||
# Close the wordlist to prevent sharing violations (windows)
|
||||
wordlist.close
|
||||
|
||||
# Create a PWDUMP style input file for SMB Hashes
|
||||
smb_hashes = myworkspace.creds.select{|x| x.ptype == "smb_hash" }
|
||||
smb_hashes.each do |cred|
|
||||
hashlist.write( "cred_#{cred[:id]}:#{cred[:id]}:#{cred[:pass]}:::\n" )
|
||||
end
|
||||
hashlist.close
|
||||
|
||||
if smb_hashes.length > 0
|
||||
cracked_ntlm = {}
|
||||
cracked_lm = {}
|
||||
added = []
|
||||
|
||||
john_crack(hashlist.path, :wordlist => datastore['Wordlist'], :format => 'lm')
|
||||
john_crack(hashlist.path, :wordlist => datastore['Wordlist'], :format => 'nt')
|
||||
|
||||
# Crack this in LANMAN format using wordlist mode with tweaked rules
|
||||
john_crack(hashlist.path, :wordlist => wordlist.path, :rules => 'single', :format => 'lm')
|
||||
|
||||
# Crack this in LANMAN format using various incremntal modes
|
||||
john_crack(hashlist.path, :incremental => "All4", :format => 'lm')
|
||||
john_crack(hashlist.path, :incremental => "Digits5", :format => 'lm')
|
||||
|
||||
# Parse cracked passwords and permute LANMAN->NTLM as needed
|
||||
cracked = john_show_passwords(hashlist.path, 'lm')
|
||||
cracked[:users].each_pair do |k,v|
|
||||
next if v == ""
|
||||
next if (v[0,7] == "???????" or v[7,7] == "???????")
|
||||
next if not k =~ /^cred_(\d+)/m
|
||||
cid = $1.to_i
|
||||
|
||||
cracked_lm[k] = v
|
||||
|
||||
cred_find = smb_hashes.select{|x| x[:id] == cid}
|
||||
next if cred_find.length == 0
|
||||
|
||||
cred = cred_find.first
|
||||
ntlm = cred.pass.split(":", 2).last
|
||||
done = john_lm_upper_to_ntlm(v, ntlm)
|
||||
cracked_ntlm[k] = done if done
|
||||
end
|
||||
|
||||
# Append any cracked values to the wordlist
|
||||
tfd = ::File.open(wordlist.path, "ab")
|
||||
cracked_lm.values.each {|w| if not added.include?(w); tfd.write( w + "\n" ); added << w; end }
|
||||
cracked_ntlm.values.each {|w| if not added.include?(w); tfd.write( w + "\n" ); added << w; end }
|
||||
tfd.close
|
||||
|
||||
# Crack this in NTLM format
|
||||
john_crack(hashlist.path, :wordlist => wordlist.path, :rules => 'single', :format => 'nt')
|
||||
|
||||
# Crack this in NTLM format using various incremntal modes
|
||||
john_crack(hashlist.path, :incremental => "All4", :format => 'nt')
|
||||
john_crack(hashlist.path, :incremental => "Digits5", :format => 'nt')
|
||||
|
||||
# Parse cracked passwords
|
||||
cracked = john_show_passwords(hashlist.path, 'nt')
|
||||
cracked[:users].each_pair do |k,v|
|
||||
next if cracked_ntlm[k]
|
||||
cracked_ntlm[k] = v
|
||||
end
|
||||
|
||||
# Append any cracked values to the wordlist
|
||||
tfd = ::File.open(wordlist.path, "ab")
|
||||
cracked_ntlm.values.each {|w| if not added.include?(w); tfd.write( w + "\n" ); added << w; end }
|
||||
tfd.close
|
||||
|
||||
# Store the cracked results based on user_id => cred.id
|
||||
cracked_ntlm.each_pair do |k,v|
|
||||
next if not k =~ /^cred_(\d+)/m
|
||||
cid = $1.to_i
|
||||
|
||||
cred_find = smb_hashes.select{|x| x[:id] == cid}
|
||||
next if cred_find.length == 0
|
||||
cred = cred_find.first
|
||||
next if cred.user.to_s.strip.length == 0
|
||||
|
||||
print_good("Cracked: #{cred.user}:#{v} (#{cred.service.host.address}:#{cred.service.port})")
|
||||
report_auth_info(
|
||||
:host => cred.service.host,
|
||||
:service => cred.service,
|
||||
:user => cred.user,
|
||||
:pass => v,
|
||||
:type => "password",
|
||||
:source_id => cred[:id],
|
||||
:source_type => 'cracked'
|
||||
)
|
||||
if format == 'lm'
|
||||
print_status "Cracking #{format} hashes in incremental mode (LanMan)..."
|
||||
cracker_instance.rules = nil
|
||||
cracker_instance.wordlist = nil
|
||||
cracker_instance.incremental = 'LanMan'
|
||||
cracker_instance.crack do |line|
|
||||
print_status line.chomp
|
||||
end
|
||||
end
|
||||
|
||||
# XXX: Enter other hash types here (shadow, etc)
|
||||
print_status "Cracking #{format} hashes in incremental mode (Digits)..."
|
||||
cracker_instance.rules = nil
|
||||
cracker_instance.wordlist = nil
|
||||
cracker_instance.incremental = 'Digits'
|
||||
cracker_instance.crack do |line|
|
||||
print_status line.chomp
|
||||
end
|
||||
|
||||
rescue ::Timeout::Error
|
||||
ensure
|
||||
wordlist.close rescue nil
|
||||
hashlist.close rescue nil
|
||||
::File.unlink(wordlist.path) rescue nil
|
||||
::File.unlink(hashlist.path) rescue nil
|
||||
print_status "Cracked Passwords this run:"
|
||||
cracker_instance.each_cracked_password do |password_line|
|
||||
password_line.chomp!
|
||||
next if password_line.blank?
|
||||
|
||||
fields = password_line.split(":")
|
||||
# If we don't have an expected minimum number of fields, this is probably not a hash line
|
||||
next unless fields.count >=7
|
||||
username = fields.shift
|
||||
core_id = fields.pop
|
||||
|
||||
# pop off dead space here
|
||||
2.times{ fields.pop }
|
||||
|
||||
# get the NT and LM hashes
|
||||
nt_hash = fields.pop
|
||||
lm_hash = 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)
|
||||
end
|
||||
|
||||
print_good "#{username}:#{password}:#{core_id}"
|
||||
create_cracked_credential( username: username, password: password, core_id: core_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def hash_file
|
||||
hashlist = Rex::Quickfile.new("hashes_tmp")
|
||||
Metasploit::Credential::NTLMHash.joins(:cores).where(metasploit_credential_cores: { workspace_id: myworkspace.id } ).each do |hash|
|
||||
hash.cores.each do |core|
|
||||
user = core.public.username
|
||||
hash_string = "#{hash.data}"
|
||||
id = core.id
|
||||
hashlist.puts "#{user}:#{id}:#{hash_string}:::#{id}"
|
||||
end
|
||||
end
|
||||
hashlist.close
|
||||
print_status "Hashes Written out to #{hashlist.path}"
|
||||
hashlist.path
|
||||
end
|
||||
end
|
||||
|
|
|
@ -54,16 +54,8 @@ class Metasploit3 < Msf::Auxiliary
|
|||
print_status line.chomp
|
||||
end
|
||||
|
||||
print_status "Cracking #{format} hashes in incremental mode (All4)..."
|
||||
cracker_instance.rules = nil
|
||||
cracker_instance.wordlist = nil
|
||||
cracker_instance.incremental = 'All4'
|
||||
cracker_instance.crack do |line|
|
||||
print_status line.chomp
|
||||
end
|
||||
|
||||
print_status "Cracking #{format} hashes in incremental mode (Digits5)..."
|
||||
cracker_instance.incremental = 'Digits5'
|
||||
print_status "Cracking #{format} hashes in incremental mode (Digits)..."
|
||||
cracker_instance.incremental = 'Digits'
|
||||
cracker_instance.crack do |line|
|
||||
print_status line.chomp
|
||||
end
|
||||
|
@ -92,7 +84,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
@formats << hash.jtr_format
|
||||
hash.cores.each do |core|
|
||||
user = core.public.username
|
||||
hash_string = "0x#{hash.data}"
|
||||
hash_string = "#{hash.data}"
|
||||
id = core.id
|
||||
hashlist.puts "#{user}:#{hash_string}:#{id}:"
|
||||
end
|
||||
|
|
|
@ -132,7 +132,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
module_fullname: self.fullname,
|
||||
origin_type: :service,
|
||||
private_type: :nonreplayable_hash,
|
||||
private_data: row[1],
|
||||
private_data: "0x#{row[1]}",
|
||||
username: row[0],
|
||||
jtr_format: hashtype
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue