2013-06-23 04:38:28 +00:00
|
|
|
#!/usr/bin/env ruby
|
|
|
|
#
|
|
|
|
# $Id$
|
|
|
|
#
|
|
|
|
# This script cracks HMAC SHA1 hashes. It is strangely necessary as existing tools
|
|
|
|
# have issues with binary salt values and extremely large salt values. The primary
|
2013-06-30 03:01:25 +00:00
|
|
|
# goal of this tool is to handle IPMI 2.0 HMAC SHA1 hashes.
|
|
|
|
#
|
|
|
|
# Support for this format is being added to both hashcat and jtr, hopefully
|
|
|
|
# making this code obsolete.
|
2013-06-23 04:38:28 +00:00
|
|
|
#
|
|
|
|
|
|
|
|
msfbase = __FILE__
|
|
|
|
while File.symlink?(msfbase)
|
2013-09-30 18:47:53 +00:00
|
|
|
msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))
|
2013-06-23 04:38:28 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
$:.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', 'lib')))
|
|
|
|
require 'msfenv'
|
|
|
|
|
|
|
|
$:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB']
|
|
|
|
|
|
|
|
require 'rex'
|
|
|
|
require 'openssl'
|
|
|
|
|
|
|
|
def usage
|
2013-09-30 18:47:53 +00:00
|
|
|
$stderr.puts("\nUsage: #{$0} hashes.txt <wordlist | - >\n")
|
|
|
|
$stderr.puts("The format of hash file is <identifier>:<hex-salt>:<hash>\n\n")
|
|
|
|
exit
|
2013-06-23 04:38:28 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
hash_inp = ARGV.shift || usage()
|
|
|
|
word_inp = ARGV.shift || usage()
|
|
|
|
|
|
|
|
usage if [hash_inp, word_inp].include?("-h") or [hash_inp, word_inp].include?("--help")
|
|
|
|
|
|
|
|
hash_fd = ::File.open(hash_inp, "rb")
|
|
|
|
word_fd = $stdin
|
|
|
|
|
|
|
|
if word_inp != "-"
|
2013-09-30 18:47:53 +00:00
|
|
|
word_fd = ::File.open(word_inp, "rb")
|
2013-06-23 04:38:28 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
hashes = []
|
|
|
|
hash_fd.each_line do |line|
|
2013-09-30 18:47:53 +00:00
|
|
|
next unless line.strip.length > 0
|
|
|
|
h_id, h_salt, h_hash = line.unpack("C*").pack("C*").strip.split(':', 3)
|
|
|
|
|
|
|
|
unless h_id and h_salt and h_hash
|
|
|
|
$stderr.puts "[-] Invalid hash entry, missing field: #{line}"
|
|
|
|
next
|
|
|
|
end
|
|
|
|
unless h_salt =~ /^[a-f0-9]+$/i
|
|
|
|
$stderr.puts "[-] Invalid hash entry, salt must be in hex: #{line}"
|
|
|
|
next
|
|
|
|
end
|
|
|
|
hashes << [h_id, [h_salt].pack("H*"), [h_hash].pack("H*") ]
|
2013-06-23 04:38:28 +00:00
|
|
|
end
|
|
|
|
hash_fd.close
|
|
|
|
|
|
|
|
|
|
|
|
stime = Time.now.to_f
|
|
|
|
count = 0
|
|
|
|
cracked = 0
|
|
|
|
|
|
|
|
word_fd.each_line do |line|
|
2013-09-30 18:47:53 +00:00
|
|
|
# Preferable to strip so we can test passwords made of whitespace (or null)
|
|
|
|
line = line.unpack("C*").pack("C*").sub(/\r?\n?$/, '')
|
|
|
|
hashes.each do |hinfo|
|
|
|
|
if OpenSSL::HMAC.digest('sha1', line.to_s, hinfo[1]) == hinfo[2]
|
|
|
|
$stdout.puts [ hinfo[0], hinfo[1].unpack("H*").first, hinfo[2].unpack("H*").first, line.to_s ].join(":")
|
|
|
|
$stdout.flush
|
|
|
|
hinfo[3] = true
|
|
|
|
cracked += 1
|
|
|
|
end
|
|
|
|
count += 1
|
|
|
|
|
|
|
|
if count % 2500000 == 0
|
|
|
|
$stderr.puts "[*] Found #{cracked} passwords with #{hashes.length} left (#{(count / (Time.now.to_f - stime)).to_i}/s)"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
hashes.delete_if {|e| e[3] }
|
|
|
|
break if hashes.length == 0
|
2013-06-23 04:38:28 +00:00
|
|
|
|
|
|
|
end
|
|
|
|
word_fd.close
|
|
|
|
|
2013-06-30 03:01:25 +00:00
|
|
|
$stderr.puts "[*] Cracked #{cracked} passwords with #{hashes.length} left (#{(count / (Time.now.to_f - stime)).to_i}/s)"
|