151 lines
4.7 KiB
Ruby
151 lines
4.7 KiB
Ruby
|
##
|
||
|
# This file is part of the Metasploit Framework and may be subject to
|
||
|
# redistribution and commercial restrictions. Please see the Metasploit
|
||
|
# Framework web site for more information on licensing and terms of use.
|
||
|
# http://metasploit.com/framework/
|
||
|
#
|
||
|
##
|
||
|
|
||
|
|
||
|
require 'msf/core'
|
||
|
|
||
|
class Metasploit3 < Msf::Auxiliary
|
||
|
|
||
|
include Msf::Auxiliary::JohnTheRipper
|
||
|
|
||
|
def initialize
|
||
|
super(
|
||
|
'Name' => 'John the Ripper Password Cracker (Fast Mode)',
|
||
|
'Version' => '$Revision$',
|
||
|
'Description' => %Q{
|
||
|
This module uses John the Ripper to identify weak passwords that have been
|
||
|
acquired as hashed files (loot) or raw LANMAN/NTLM hashes (hashdump). The goal
|
||
|
of this module is to find trivial passwords in a short amount of time. To
|
||
|
crack complex passwords or use large wordlists, John the Ripper should be
|
||
|
used outside of Metasploit. This initial version just handles LM/NTLM credentials
|
||
|
from hashdump and uses the standard wordlist and rules.
|
||
|
},
|
||
|
'Author' => 'hdm',
|
||
|
'License' => MSF_LICENSE # JtR itself is GPLv2, but this wrapper is MSF (BSD)
|
||
|
)
|
||
|
end
|
||
|
|
||
|
def run
|
||
|
wordlist = Rex::Quickfile.new("jtrtmp")
|
||
|
hashlist = Rex::Quickfile.new("jtrtmp")
|
||
|
|
||
|
begin
|
||
|
# Seed the wordlist with usernames, passwords, and hostnames
|
||
|
seed = []
|
||
|
|
||
|
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/)
|
||
|
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" )
|
||
|
|
||
|
# Append the standard JtR wordlist as well
|
||
|
::File.open(john_wordlist_path, "rb") do |fd|
|
||
|
wordlist.write fd.read(fd.stat.size)
|
||
|
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 = []
|
||
|
|
||
|
# Crack this in LANMAN format first
|
||
|
john_crack(hashlist.path, :wordlist => wordlist.path, :rules => 'single', :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
|
||
|
# Crack this in LANMAN format first
|
||
|
john_crack(hashlist.path, :wordlist => wordlist.path, :rules => 'single', :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
|
||
|
|
||
|
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'
|
||
|
)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
# XXX: Enter other hash types here (shadow, etc)
|
||
|
|
||
|
rescue ::Timeout::Error
|
||
|
ensure
|
||
|
wordlist.close rescue nil
|
||
|
hashlist.close rescue nil
|
||
|
::File.unlink(wordlist.path) rescue nil
|
||
|
::File.unlink(hashlist.path) rescue nil
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|