diff --git a/modules/auxiliary/analyze/jtr_linux.rb b/modules/auxiliary/analyze/jtr_linux.rb index 452abf99dc..5e124b513d 100644 --- a/modules/auxiliary/analyze/jtr_linux.rb +++ b/modules/auxiliary/analyze/jtr_linux.rb @@ -5,6 +5,7 @@ require 'msf/core' +require 'msf/core/auxiliary/jtr' class Metasploit3 < Msf::Auxiliary @@ -36,77 +37,62 @@ class Metasploit3 < Msf::Auxiliary end def run - @wordlist = Rex::Quickfile.new("jtrtmp") - begin - @wordlist.write( build_seed().join("\n") + "\n" ) - ensure - @wordlist.close + formats = [ 'md5', 'des', 'bsdi'] + if datastore['Crypt'] + format << 'crypt' end - myloots = myworkspace.loots.where('ltype=?', 'linux.hashes') - return if myloots.nil? or myloots.empty? + cracker = new_john_cracker - build_hashlist(myloots) + #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 - print_status("HashList: #{@hashlist.path}") - - try('md5') - try('des') - try('bsdi') - try('crypt') if datastore['Crypt'] - - cracked = john_show_passwords(@hashlist.path) - - print_status("#{cracked[:cracked]} hashes were cracked!") - - cracked[:users].each_pair do |k,v| - if v[0] == "NO PASSWORD" - passwd="" - else - passwd=v[0] + formats.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 + + 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 + 4.times { fields.pop } + password = fields.join('') # Anything left must be the password. This accounts for passwords with : in them + print_good password_line + create_cracked_credential( username: username, password: password, core_id: core_id) end - print_good("Host: #{v.last} User: #{k} Pass: #{passwd}") - report_auth_info( - :host => v.last, - :port => 22, - :sname => 'ssh', - :user => k, - :pass => passwd - ) end end - def try(format) - print_status("Trying Format:#{format} Wordlist: #{@wordlist.path}") - john_crack(@hashlist.path, :wordlist => @wordlist.path, :rules => 'single', :format => format) - print_status("Trying Format:#{format} Rule: All4...") - john_crack(@hashlist.path, :incremental => "All4", :format => format) - print_status("Trying Format:#{format} Rule: Digits5...") - john_crack(@hashlist.path, :incremental => "Digits5", :format => format) - end - - def build_hashlist(myloots) - loot_data = [] - - myloots.each do |myloot| - usf = '' - begin - File.open(myloot.path, "rb") do |f| - usf = f.read(f.stat.size) - end - rescue Exception => e - print_error("Unable to read #{myloot.path} \n #{e}") - end - usf.each_line do |row| - row.gsub!("\n", ":#{myloot.host.address}\n") - loot_data << row + def hash_file + hashlist = Rex::Quickfile.new("hashes_tmp") + Metasploit::Credential::NonreplayableHash.joins(:cores).where(metasploit_credential_cores: { workspace_id: myworkspace.id }, jtr_format: 'md5,des,bsdi,crypt').each do |hash| + hash.cores.each do |core| + user = core.public.username + hash_string = "#{hash.data}" + id = core.id + hashlist.puts "#{user}:#{hash_string}:::::#{id}:" end end - - @hashlist = Rex::Quickfile.new("jtrtmp") - @hashlist.write(loot_data.join) - @hashlist.close + hashlist.close + print_status "Hashes Written out to #{hashlist.path}" + hashlist.path end + + end