877 lines
28 KiB
Ruby
Executable File
877 lines
28 KiB
Ruby
Executable File
#!/usr/bin/env ruby
|
|
#
|
|
# $Id$
|
|
#
|
|
# This script cracks any type of NTLM hash
|
|
# Credit to -Yannick Hamon <yannick.hamon[at]xmcopartners.com> for the original idea/perl code
|
|
# -Alexandre Maloteaux <a.maloteaux[at]gmail.com> for improvments
|
|
# $Revision$
|
|
#
|
|
|
|
msfbase = __FILE__
|
|
while File.symlink?(msfbase)
|
|
msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))
|
|
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 'rex/proto/ntlm/crypt'
|
|
|
|
CRYPT = Rex::Proto::NTLM::Crypt
|
|
|
|
BRUTE_MODE = 1
|
|
HASH_MODE = 2
|
|
PASS_MODE = 3
|
|
|
|
def usage
|
|
$stderr.puts("\nUsage: #{$0} -t type <options>\n" + $args.usage)
|
|
$stderr.puts("This tool can be use in 3 ways whatever type is choosen\n")
|
|
$stderr.puts("-If only a password (-p) is provided, it will display the hash.\n")
|
|
$stderr.puts("-If a password (-p) and an hash (-a) is provided, it will test the password against the hash.\n")
|
|
$stderr.puts("-If a list of password (-l) is provided and an hash (-a), it will try to bruteforce the hash \n\n")
|
|
exit
|
|
end
|
|
|
|
def permute_pw(pw)
|
|
# fast permutation from http://stackoverflow.com/a/1398900
|
|
perms = [""]
|
|
if pw.nil?
|
|
return perms
|
|
end
|
|
tail = pw.downcase
|
|
while tail.length > 0 do
|
|
head, tail, psize = tail[0..0], tail[1..-1], perms.size
|
|
hu = head.upcase
|
|
for i in (0...psize)
|
|
tp = perms[i]
|
|
perms[i] = tp + hu
|
|
if hu != head
|
|
perms.push(tp + head)
|
|
end
|
|
end
|
|
end
|
|
return perms
|
|
end
|
|
|
|
type = hash = pass = srvchal = clichal = calculatedhash = list = user = domain = nil
|
|
|
|
$args = Rex::Parser::Arguments.new(
|
|
"-t" => [ true, "The type of hash to crack : HALFLM/LM/NTLM/HALFNETLMv1/NETLMv1/NETNTLMv1/NETNTLM2_SESSION/NETLMv2/NETNTLMv2" ],
|
|
"-a" => [ true, "The hash to crack" ],
|
|
"-p" => [ true, "The password " ],
|
|
"-l" => [ true, "The list of password to check against an hash" ],
|
|
"-s" => [ true, "The LM/NTLM Server Challenge (NET* type only)" ],
|
|
"-c" => [ true, "The LM/NTLM Client Challenge (NETNTLM2_SESSION/NETLMv2/NETNTLMv2/ type only)" ],
|
|
"-u" => [ true, "The user name (NETLMv2/NETNTLMv2 type only)" ],
|
|
"-d" => [ true, "The domain (machine) name (NETLMv2/NETNTLMv2 type only)" ],
|
|
"-h" => [ false, "Display this help information" ])
|
|
|
|
|
|
$args.parse(ARGV) { |opt, idx, val|
|
|
case opt
|
|
when "-t"
|
|
type = val
|
|
when "-a"
|
|
hash = val
|
|
when "-p"
|
|
pass = val
|
|
when "-l"
|
|
list = val
|
|
when "-s"
|
|
srvchal = val
|
|
when "-c"
|
|
clichal = val
|
|
when "-u"
|
|
user = val
|
|
when "-d"
|
|
domain = val
|
|
when "-h"
|
|
usage
|
|
else
|
|
usage
|
|
end
|
|
}
|
|
|
|
if not type
|
|
usage
|
|
else
|
|
if pass and (not (hash or list))
|
|
mode = HASH_MODE
|
|
elsif pass and hash and not list
|
|
mode = PASS_MODE
|
|
elsif list and hash and not pass
|
|
mode = BRUTE_MODE
|
|
if not File.exist? list
|
|
$stderr.puts "[*] The passwords list file does not exist"
|
|
exit
|
|
end
|
|
if not File.file? list
|
|
$stderr.puts "[*] The passwords list provided is not a file"
|
|
exit
|
|
end
|
|
if not File.readable? list
|
|
$stderr.puts "[*] The passwords list file is not readable"
|
|
exit
|
|
end
|
|
else
|
|
usage
|
|
end
|
|
end
|
|
|
|
|
|
if type == "HALFLM" or type == "LM" or type == "NTLM" then
|
|
if srvchal != nil or clichal != nil or user != nil or domain != nil then
|
|
$stderr.puts "[*] No challenge, user or domain must be provided with this type"
|
|
exit
|
|
end
|
|
elsif type == "HALFNETLMv1" or type == "NETLMv1" or type == "NETNTLMv1" then
|
|
if clichal != nil or user != nil or domain != nil then
|
|
$stderr.puts "[*] Client challenge, user or domain must not be provided with this type"
|
|
exit
|
|
end
|
|
elsif type == "NETNTLM2_SESSION" then
|
|
if user != nil or domain != nil then
|
|
$stderr.puts "[*] User or domain must not be provided with this type"
|
|
exit
|
|
end
|
|
end
|
|
|
|
case type
|
|
when "HALFLM"
|
|
case mode
|
|
when BRUTE_MODE
|
|
if not hash =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] HALFLM HASH must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
File.open(list,"rb") do |password_list|
|
|
password_list.each_line do |line|
|
|
password = line.gsub("\r\n",'').gsub("\n",'')
|
|
if password =~ /^.{1,7}$/
|
|
puts password
|
|
calculatedhash = CRYPT::lm_hash(password,true).unpack("H*")[0].upcase
|
|
if calculatedhash == hash.upcase
|
|
puts "[*] Correct password found : #{password.upcase}"
|
|
exit
|
|
end
|
|
end
|
|
end
|
|
end
|
|
puts "[*] No password found"
|
|
exit
|
|
when HASH_MODE
|
|
if not pass =~ /^.{0,7}$/
|
|
$stderr.puts "[*] LM password can not be bigger then 7 characters"
|
|
exit
|
|
end
|
|
calculatedhash = CRYPT::lm_hash(pass,true).unpack("H*")[0].upcase
|
|
puts "[*] The LM hash for #{pass.upcase} is : #{calculatedhash}"
|
|
exit
|
|
when PASS_MODE
|
|
if not pass =~ /^.{0,7}$/
|
|
$stderr.puts "[*] LM password can not be bigger then 7 characters"
|
|
exit
|
|
end
|
|
if not hash =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] LM HASH must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
calculatedhash = CRYPT::lm_hash(pass,true).unpack("H*")[0].upcase
|
|
if hash.upcase == calculatedhash
|
|
puts "[*] Correct password provided : #{pass.upcase}"
|
|
exit
|
|
else
|
|
puts "[*] Incorrect password provided : #{pass.upcase}"
|
|
exit
|
|
end
|
|
end
|
|
|
|
when "LM"
|
|
case mode
|
|
when BRUTE_MODE
|
|
if not hash =~ /^([a-fA-F0-9]{32})$/
|
|
$stderr.puts "[*] LM HASH must be exactly 32 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
File.open(list,"rb") do |password_list|
|
|
password_list.each_line do |line|
|
|
password = line.gsub("\r\n",'').gsub("\n",'')
|
|
if password =~ /^.{1,14}$/
|
|
puts password
|
|
calculatedhash = CRYPT::lm_hash(password.upcase).unpack("H*")[0].upcase
|
|
if calculatedhash == hash.upcase
|
|
puts "[*] Correct password found : #{password.upcase}"
|
|
exit
|
|
end
|
|
end
|
|
end
|
|
end
|
|
puts "[*] No password found"
|
|
exit
|
|
when HASH_MODE
|
|
if not pass =~ /^.{0,14}$/
|
|
$stderr.puts "[*] LM password can not be bigger then 14 characters"
|
|
exit
|
|
end
|
|
calculatedhash = CRYPT::lm_hash(pass.upcase).unpack("H*")[0].upcase
|
|
puts "[*] The LM hash for #{pass.upcase} is : #{calculatedhash}"
|
|
exit
|
|
when PASS_MODE
|
|
if not pass =~ /^.{0,14}$/
|
|
$stderr.puts "[*] LM password can not be bigger then 14 characters"
|
|
exit
|
|
end
|
|
if not hash =~ /^([a-fA-F0-9]{32})$/
|
|
$stderr.puts "[*] LM HASH must be exactly 32 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
calculatedhash = CRYPT::lm_hash(pass.upcase).unpack("H*")[0].upcase
|
|
if hash.upcase == calculatedhash
|
|
puts "[*] Correct password provided : #{pass.upcase}"
|
|
exit
|
|
else
|
|
puts "[*] Incorrect password provided : #{pass.upcase}"
|
|
exit
|
|
end
|
|
end
|
|
|
|
when "NTLM"
|
|
case mode
|
|
when BRUTE_MODE
|
|
if not hash =~ /^([a-fA-F0-9]{32})$/
|
|
$stderr.puts "[*] NTLM HASH must be exactly 32 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
File.open(list,"rb") do |password_list|
|
|
password_list.each_line do |line|
|
|
password = line.gsub("\r\n",'').gsub("\n",'')
|
|
for permutedpw in permute_pw(password)
|
|
puts permutedpw
|
|
calculatedhash = CRYPT::ntlm_hash(permutedpw).unpack("H*")[0].upcase
|
|
if calculatedhash == hash.upcase
|
|
puts "[*] Correct password found : #{permutedpw}"
|
|
exit
|
|
end
|
|
end
|
|
end
|
|
end
|
|
puts "[*] No password found"
|
|
exit
|
|
when HASH_MODE
|
|
calculatedhash = CRYPT::ntlm_hash(pass).unpack("H*")[0].upcase
|
|
puts "[*] The NTLM hash for #{pass} is : #{calculatedhash}"
|
|
exit
|
|
when PASS_MODE
|
|
if not hash =~ /^([a-fA-F0-9]{32})$/
|
|
$stderr.puts "[*] NTLM HASH must be exactly 32 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
for permutedpw in permute_pw(pass)
|
|
calculatedhash = CRYPT::ntlm_hash(permutedpw).unpack("H*")[0].upcase
|
|
if hash.upcase == calculatedhash
|
|
puts "[*] Correct password provided : #{permutedpw}"
|
|
exit
|
|
end
|
|
end
|
|
puts "[*] Incorrect password provided : #{pass}"
|
|
end
|
|
when "HALFNETLMv1"
|
|
case mode
|
|
when BRUTE_MODE
|
|
if not hash =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] NETLMv1 HASH must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not srvchal
|
|
$stderr.puts "[*] Server challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not srvchal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Server challenge must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
File.open(list,"rb") do |password_list|
|
|
password_list.each_line do |line|
|
|
password = line.gsub("\r\n",'').gsub("\n",'')
|
|
if password =~ /^.{1,7}$/
|
|
puts password
|
|
#Rem : cause of the [0,7] there is only 1/256 chance that the guessed password will be the good one
|
|
arglm = { :lm_hash => CRYPT::lm_hash(password,true)[0,7],
|
|
:challenge => [ srvchal ].pack("H*") }
|
|
calculatedhash = CRYPT::lm_response(arglm,true).unpack("H*")[0].upcase
|
|
if calculatedhash == hash.upcase
|
|
puts "[*] Correct password found : #{password.upcase}"
|
|
exit
|
|
end
|
|
end
|
|
end
|
|
end
|
|
puts "[*] No password found"
|
|
exit
|
|
when HASH_MODE
|
|
if not pass =~ /^.{0,7}$/
|
|
$stderr.puts "[*] HALFNETLMv1 password can not be bigger then 7 characters"
|
|
exit
|
|
end
|
|
if not srvchal
|
|
$stderr.puts "[*] Server challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not srvchal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Server challenge must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
arglm = { :lm_hash => CRYPT::lm_hash(pass,true)[0,7],
|
|
:challenge => [ srvchal ].pack("H*") }
|
|
|
|
calculatedhash = CRYPT::lm_response(arglm,true).unpack("H*")[0].upcase
|
|
puts "[*] The HALFNETLMv1 hash for #{pass.upcase} is : #{calculatedhash}"
|
|
exit
|
|
when PASS_MODE
|
|
if not pass =~ /^.{0,7}$/
|
|
$stderr.puts "[*] HALFNETLMv1 password can not be bigger then 7 characters"
|
|
exit
|
|
end
|
|
if not hash =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] HALFNETLMv1 HASH must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not srvchal
|
|
$stderr.puts "[*] Server challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not srvchal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Server challenge must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
#Rem : cause of the [0,7] there is only 1/256 chance that the guessed password will be the good one
|
|
arglm = { :lm_hash => CRYPT::lm_hash(pass,true)[0,7],
|
|
:challenge => [ srvchal ].pack("H*") }
|
|
|
|
calculatedhash = CRYPT::lm_response(arglm,true).unpack("H*")[0].upcase
|
|
if hash.upcase == calculatedhash
|
|
puts "[*] Correct password provided : #{pass.upcase}"
|
|
exit
|
|
else
|
|
puts "[*] Incorrect password provided : #{pass.upcase}"
|
|
exit
|
|
end
|
|
end
|
|
when "NETLMv1"
|
|
case mode
|
|
when BRUTE_MODE
|
|
if not hash =~ /^([a-fA-F0-9]{48})$/
|
|
$stderr.puts "[*] NETLMv1 HASH must be exactly 48 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not srvchal
|
|
$stderr.puts "[*] Server challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not srvchal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Server challenge must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
File.open(list,"rb") do |password_list|
|
|
password_list.each_line do |line|
|
|
password = line.gsub("\r\n",'').gsub("\n",'')
|
|
if password =~ /^.{1,14}$/
|
|
puts password
|
|
arglm = { :lm_hash => CRYPT::lm_hash(password),
|
|
:challenge => [ srvchal ].pack("H*") }
|
|
calculatedhash = CRYPT::lm_response(arglm).unpack("H*")[0].upcase
|
|
if calculatedhash == hash.upcase
|
|
puts "[*] Correct password found : #{password.upcase}"
|
|
exit
|
|
end
|
|
end
|
|
end
|
|
end
|
|
puts "[*] No password found"
|
|
exit
|
|
when HASH_MODE
|
|
if not pass =~ /^.{1,14}$/
|
|
$stderr.puts "[*] NETLMv1 password can not be bigger then 14 characters"
|
|
exit
|
|
end
|
|
if not srvchal
|
|
$stderr.puts "[*] Server challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not srvchal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Server challenge must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
arglm = { :lm_hash => CRYPT::lm_hash(pass),
|
|
:challenge => [ srvchal ].pack("H*") }
|
|
|
|
calculatedhash = CRYPT::lm_response(arglm).unpack("H*")[0].upcase
|
|
puts "[*] The NETLMv1 hash for #{pass.upcase} is : #{calculatedhash}"
|
|
exit
|
|
when PASS_MODE
|
|
if not pass =~ /^.{1,14}$/
|
|
$stderr.puts "[*] NETLMv1 password can not be bigger then 14 characters"
|
|
exit
|
|
end
|
|
if not hash =~ /^([a-fA-F0-9]{48})$/
|
|
$stderr.puts "[*] NETLMv1 HASH must be exactly 48 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not srvchal
|
|
$stderr.puts "[*] Server challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not srvchal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Server challenge must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
arglm = { :lm_hash => CRYPT::lm_hash(pass),
|
|
:challenge => [ srvchal ].pack("H*") }
|
|
|
|
calculatedhash = CRYPT::lm_response(arglm).unpack("H*")[0].upcase
|
|
if hash.upcase == calculatedhash
|
|
puts "[*] Correct password provided : #{pass.upcase}"
|
|
exit
|
|
else
|
|
puts "[*] Incorrect password provided : #{pass.upcase}"
|
|
exit
|
|
end
|
|
end
|
|
when "NETNTLMv1"
|
|
case mode
|
|
when BRUTE_MODE
|
|
if not hash =~ /^([a-fA-F0-9]{48})$/
|
|
$stderr.puts "[*] NETNTLMv1 HASH must be exactly 48 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not srvchal
|
|
$stderr.puts "[*] Server challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not srvchal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Server challenge must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
File.open(list,"rb") do |password_list|
|
|
password_list.each_line do |line|
|
|
password = line.gsub("\r\n",'').gsub("\n",'')
|
|
for permutedpw in permute_pw(password)
|
|
puts permutedpw
|
|
argntlm = { :ntlm_hash => CRYPT::ntlm_hash(permutedpw),
|
|
:challenge => [ srvchal ].pack("H*") }
|
|
calculatedhash = CRYPT::ntlm_response(argntlm).unpack("H*")[0].upcase
|
|
if calculatedhash == hash.upcase
|
|
puts "[*] Correct password found : #{permutedpw}"
|
|
exit
|
|
end
|
|
end
|
|
end
|
|
end
|
|
puts "[*] No password found"
|
|
exit
|
|
when HASH_MODE
|
|
if not srvchal
|
|
$stderr.puts "[*] Server challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not srvchal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Server challenge must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
argntlm = { :ntlm_hash => CRYPT::ntlm_hash(pass),
|
|
:challenge => [ srvchal ].pack("H*") }
|
|
calculatedhash = CRYPT::ntlm_response(argntlm).unpack("H*")[0].upcase
|
|
puts "[*] The NETNTLMv1 hash for #{pass} is : #{calculatedhash}"
|
|
exit
|
|
when PASS_MODE
|
|
if not hash =~ /^([a-fA-F0-9]{48})$/
|
|
$stderr.puts "[*] NETNTLMv1 HASH must be exactly 48 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not srvchal
|
|
$stderr.puts "[*] Server challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not srvchal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Server challenge must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
for permutedpw in permute_pw(pass)
|
|
argntlm = { :ntlm_hash => CRYPT::ntlm_hash(permutedpw),
|
|
:challenge => [ srvchal ].pack("H*") }
|
|
|
|
calculatedhash = CRYPT::ntlm_response(argntlm).unpack("H*")[0].upcase
|
|
if hash.upcase == calculatedhash
|
|
puts "[*] Correct password provided : #{permutedpw}"
|
|
exit
|
|
end
|
|
end
|
|
puts "[*] Incorrect password provided : #{pass}"
|
|
exit
|
|
end
|
|
when "NETNTLM2_SESSION"
|
|
case mode
|
|
when BRUTE_MODE
|
|
if not hash =~ /^([a-fA-F0-9]{48})$/
|
|
$stderr.puts "[*] NETNTLM2_SESSION HASH must be exactly 48 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not srvchal
|
|
$stderr.puts "[*] Server challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not srvchal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Server challenge must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not clichal
|
|
$stderr.puts "[*] Client challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not clichal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Client challenge must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
|
|
File.open(list,"rb") do |password_list|
|
|
password_list.each_line do |line|
|
|
password = line.gsub("\r\n",'').gsub("\n",'')
|
|
for permutedpw in permute_pw(password)
|
|
puts permutedpw
|
|
argntlm = { :ntlm_hash => CRYPT::ntlm_hash(permutedpw),
|
|
:challenge => [ srvchal ].pack("H*") }
|
|
optntlm = { :client_challenge => [ clichal ].pack("H*")}
|
|
|
|
calculatedhash = CRYPT::ntlm2_session(argntlm,optntlm).join[24,24].unpack("H*")[0].upcase
|
|
|
|
if calculatedhash == hash.upcase
|
|
puts "[*] Correct password found : #{permutedpw}"
|
|
exit
|
|
end
|
|
end
|
|
end
|
|
end
|
|
puts "[*] No password found"
|
|
exit
|
|
when HASH_MODE
|
|
if not srvchal
|
|
$stderr.puts "[*] Server challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not srvchal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Server challenge must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not clichal
|
|
$stderr.puts "[*] Client challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not clichal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Client challenge must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
argntlm = { :ntlm_hash => CRYPT::ntlm_hash(pass),
|
|
:challenge => [ srvchal ].pack("H*") }
|
|
optntlm = { :client_challenge => [ clichal ].pack("H*")}
|
|
|
|
calculatedhash = CRYPT::ntlm2_session(argntlm,optntlm).join[24,24].unpack("H*")[0].upcase
|
|
puts "[*] The NETNTLM2_SESSION hash for #{pass} is : #{calculatedhash}"
|
|
exit
|
|
when PASS_MODE
|
|
if not hash =~ /^([a-fA-F0-9]{48})$/
|
|
$stderr.puts "[*] NETNTLM2_SESSION HASH must be exactly 48 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not srvchal
|
|
$stderr.puts "[*] Server challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not srvchal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Server challenge must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not clichal
|
|
$stderr.puts "[*] Client challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not clichal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Client challenge must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
for permutedpw in permute_pw(pass)
|
|
argntlm = { :ntlm_hash => CRYPT::ntlm_hash(permutedpw),
|
|
:challenge => [ srvchal ].pack("H*") }
|
|
optntlm = { :client_challenge => [ clichal ].pack("H*")}
|
|
|
|
calculatedhash = CRYPT::ntlm2_session(argntlm,optntlm).join[24,24].unpack("H*")[0].upcase
|
|
|
|
if hash.upcase == calculatedhash
|
|
puts "[*] Correct password provided : #{permutedpw}"
|
|
exit
|
|
end
|
|
end
|
|
puts "[*] Incorrect password provided : #{pass}"
|
|
exit
|
|
end
|
|
when "NETLMv2"
|
|
case mode
|
|
when BRUTE_MODE
|
|
if not hash =~ /^([a-fA-F0-9]{32})$/
|
|
$stderr.puts "[*] NETLMv2 HASH must be exactly 32 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not srvchal
|
|
$stderr.puts "[*] Server challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not srvchal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Server challenge mus be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not clichal
|
|
$stderr.puts "[*] Client challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not clichal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Client challenge must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not user
|
|
$stderr.puts "[*] User name must be provided with this type"
|
|
exit
|
|
end
|
|
if not domain
|
|
$stderr.puts "[*] Domain name must be provided with this type"
|
|
exit
|
|
end
|
|
|
|
File.open(list,"rb") do |password_list|
|
|
password_list.each_line do |line|
|
|
password = line.gsub("\r\n",'').gsub("\n",'')
|
|
puts password
|
|
arglm = { :ntlmv2_hash => CRYPT::ntlmv2_hash(user,password, domain),
|
|
:challenge => [ srvchal ].pack("H*") }
|
|
optlm = { :client_challenge => [ clichal ].pack("H*")}
|
|
calculatedhash = CRYPT::lmv2_response(arglm, optlm).unpack("H*")[0].upcase
|
|
if calculatedhash.slice(0,32) == hash.upcase
|
|
puts "[*] Correct password found : #{password}"
|
|
exit
|
|
end
|
|
end
|
|
end
|
|
puts "[*] No password found"
|
|
exit
|
|
when HASH_MODE
|
|
if not srvchal
|
|
$stderr.puts "[*] Server challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not srvchal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Server challenge must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not clichal
|
|
$stderr.puts "[*] Client challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not clichal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Client challenge must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not user
|
|
$stderr.puts "[*] User name must be provided with this type"
|
|
exit
|
|
end
|
|
if not domain
|
|
$stderr.puts "[*] Domain name must be provided with this type"
|
|
exit
|
|
end
|
|
|
|
arglm = { :ntlmv2_hash => CRYPT::ntlmv2_hash(user,pass, domain),
|
|
:challenge => [ srvchal ].pack("H*") }
|
|
optlm = { :client_challenge => [ clichal ].pack("H*")}
|
|
calculatedhash = CRYPT::lmv2_response(arglm, optlm).unpack("H*")[0].upcase
|
|
|
|
puts "[*] The NETLMv2 hash for #{pass} is : #{calculatedhash.slice(0,32)}"
|
|
exit
|
|
when PASS_MODE
|
|
if not hash =~ /^([a-fA-F0-9]{32})$/
|
|
$stderr.puts "[*] NETLMv2 HASH must be exactly 32 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not srvchal
|
|
$stderr.puts "[*] Server challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not srvchal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Server challenge must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not clichal
|
|
$stderr.puts "[*] Client challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not clichal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Client challenge must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not user
|
|
$stderr.puts "[*] User name must be provided with this type"
|
|
exit
|
|
end
|
|
if not domain
|
|
$stderr.puts "[*] Domain name must be provided with this type"
|
|
exit
|
|
end
|
|
arglm = { :ntlmv2_hash => CRYPT::ntlmv2_hash(user,pass, domain),
|
|
:challenge => [ srvchal ].pack("H*") }
|
|
optlm = { :client_challenge => [ clichal ].pack("H*")}
|
|
calculatedhash = CRYPT::lmv2_response(arglm, optlm).unpack("H*")[0].upcase
|
|
if hash.upcase == calculatedhash.slice(0,32)
|
|
puts "[*] Correct password provided : #{pass}"
|
|
exit
|
|
else
|
|
puts "[*] Incorrect password provided : #{pass}"
|
|
exit
|
|
end
|
|
end
|
|
|
|
when "NETNTLMv2"
|
|
case mode
|
|
when BRUTE_MODE
|
|
if not hash =~ /^([a-fA-F0-9]{32})$/
|
|
$stderr.puts "[*] NETNTLMv2 HASH must be exactly 32 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not srvchal
|
|
$stderr.puts "[*] Server challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not srvchal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Server challenge must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not clichal
|
|
$stderr.puts "[*] Client challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not clichal =~ /^([a-fA-F0-9]{17,})$/
|
|
$stderr.puts "[*] Client challenge must be bigger then 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not user
|
|
$stderr.puts "[*] User name must be provided with this type"
|
|
exit
|
|
end
|
|
if not domain
|
|
$stderr.puts "[*] Domain name must be provided with this type"
|
|
exit
|
|
end
|
|
|
|
File.open(list,"rb") do |password_list|
|
|
password_list.each_line do |line|
|
|
password = line.gsub("\r\n",'').gsub("\n",'')
|
|
for permutedpw in permute_pw(password)
|
|
puts permutedpw
|
|
argntlm = { :ntlmv2_hash => CRYPT::ntlmv2_hash(user, permutedpw, domain),
|
|
:challenge => [ srvchal ].pack("H*") }
|
|
optntlm = { :nt_client_challenge => [ clichal ].pack("H*")}
|
|
calculatedhash = CRYPT::ntlmv2_response(argntlm,optntlm).unpack("H*")[0].upcase
|
|
|
|
if calculatedhash.slice(0,32) == hash.upcase
|
|
puts "[*] Correct password found : #{password}"
|
|
exit
|
|
end
|
|
end
|
|
end
|
|
end
|
|
puts "[*] No password found"
|
|
exit
|
|
when HASH_MODE
|
|
if not srvchal
|
|
$stderr.puts "[*] Server challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not srvchal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Server challenge must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not clichal
|
|
$stderr.puts "[*] Client challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not clichal =~ /^([a-fA-F0-9]{17,})$/
|
|
$stderr.puts "[*] Client challenge must be bigger then 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not user
|
|
$stderr.puts "[*] User name must be provided with this type"
|
|
exit
|
|
end
|
|
if not domain
|
|
$stderr.puts "[*] Domain name must be provided with this type"
|
|
exit
|
|
end
|
|
|
|
argntlm = { :ntlmv2_hash => CRYPT::ntlmv2_hash(user, pass, domain),
|
|
:challenge => [ srvchal ].pack("H*") }
|
|
optntlm = { :nt_client_challenge => [ clichal ].pack("H*")}
|
|
calculatedhash = CRYPT::ntlmv2_response(argntlm,optntlm).unpack("H*")[0].upcase
|
|
|
|
puts "[*] The NETNTLMv2 hash for #{pass} is : #{calculatedhash.slice(0,32)}"
|
|
exit
|
|
when PASS_MODE
|
|
if not hash =~ /^([a-fA-F0-9]{32})$/
|
|
$stderr.puts "[*] NETNTLMv2 HASH must be exactly 32 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not srvchal
|
|
$stderr.puts "[*] Server challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not srvchal =~ /^([a-fA-F0-9]{16})$/
|
|
$stderr.puts "[*] Server challenge must be exactly 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not clichal
|
|
$stderr.puts "[*] Client challenge must be provided with this type"
|
|
exit
|
|
end
|
|
if not clichal =~ /^([a-fA-F0-9]{17,})$/
|
|
$stderr.puts "[*] Client challenge must be bigger then 16 bytes of hexadecimal"
|
|
exit
|
|
end
|
|
if not user
|
|
$stderr.puts "[*] User name must be provided with this type"
|
|
exit
|
|
end
|
|
if not domain
|
|
$stderr.puts "[*] Domain name must be provided with this type"
|
|
exit
|
|
end
|
|
|
|
for permutedpw in permute_pw(password)
|
|
argntlm = { :ntlmv2_hash => CRYPT::ntlmv2_hash(user, permutedpw, domain),
|
|
:challenge => [ srvchal ].pack("H*") }
|
|
optntlm = { :nt_client_challenge => [ clichal ].pack("H*")}
|
|
calculatedhash = CRYPT::ntlmv2_response(argntlm,optntlm).unpack("H*")[0].upcase
|
|
|
|
if hash.upcase == calculatedhash.slice(0,32)
|
|
puts "[*] Correct password provided : #{permutedpw}"
|
|
exit
|
|
end
|
|
end
|
|
puts "[*] Incorrect password provided : #{pass}"
|
|
exit
|
|
end
|
|
else
|
|
$stderr.puts "type must be of type : HALFLM/LM/NTLM/HALFNETLMv1/NETLMv1/NETNTLMv1/NETNTLM2_SESSION/NETLMv2/NETNTLMv2"
|
|
exit
|
|
end
|
|
|
|
|