123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- #!/usr/bin/env ruby
- ##
- # This module requires Metasploit: https://metasploit.com/download
- # Current source: https://github.com/rapid7/metasploit-framework
- ##
- #
- # This script cracks a half-lm challenge/response hash that uses a
- # a static challenge key. The idea is you use rainbow tables to
- # crack the first 7 chars and this script to complete a few remaining.
- # If the password is longer than 10 characters, this script will fail.
- #
- 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'
- def usage
- $stderr.puts("\n" + " Usage: #{$0} <options>\n" + $args.usage)
- exit
- end
- def try(word,challenge)
- buf = ::Rex::Proto::NTLM::Crypt.lanman_des(word, challenge)
- buf.unpack("H*")[0]
- end
- hash = pass = chall = nil
- $args = Rex::Parser::Arguments.new(
- "-n" => [ true, "The encrypted LM hash to crack" ],
- "-p" => [ true, "The decrypted LANMAN password for bytes 1-7" ],
- "-s" => [ true, "The server challenge (default value 1122334455667788)" ],
- "-h" => [ false, "Display this help information" ])
- $args.parse(ARGV) { |opt, idx, val|
- case opt
- when "-n"
- hash = val
- when "-p"
- pass = val
- when "-s"
- chall = val
- when "-h"
- usage
- else
- usage
- end
- }
- if (not (hash and pass))
- usage
- end
- if (not chall)
- chall = ["1122334455667788"].pack("H*")
- else
- if not chall =~ /^([a-fA-F0-9]{16})$/
- $stderr.puts "[*] Server challenge must be exactly 16 bytes of hexadecimal"
- exit
- else
- chall = [chall].pack("H*")
- end
- end
- if(hash.length != 48)
- $stderr.puts "[*] LANMAN should be exactly 48 bytes of hexadecimal"
- exit
- end
- if(pass.length != 7)
- $stderr.puts "[*] Cracked LANMAN password should be exactly 7 characters"
- exit
- end
- pass = pass.upcase
- hash = hash.downcase
- cset = [*(1..255)].pack("C*").upcase.unpack("C*").uniq
- stime = Time.now.to_f
- puts "[*] Trying one character..."
- 0.upto(cset.length-1) do |c1|
- test = pass + cset[c1].chr
- if(try(test, chall) == hash)
- puts "[*] Cracked: #{test}"
- exit
- end
- end
- etime = Time.now.to_f - stime
- puts "[*] Trying two characters (eta: #{etime * cset.length} seconds)..."
- 0.upto(cset.length-1) do |c1|
- 0.upto(cset.length-1) do |c2|
- test = pass + cset[c1].chr + cset[c2].chr
- if(try(test, chall) == hash)
- puts "[*] Cracked: #{test}"
- exit
- end
- end
- end
- puts "[*] Trying three characters (eta: #{etime * cset.length * cset.length} seconds)..."
- 0.upto(cset.length-1) do |c1|
- 0.upto(cset.length-1) do |c2|
- 0.upto(cset.length-1) do |c3|
- test = pass + cset[c1].chr + cset[c2].chr + cset[c3].chr
- if(try(test, chall) == hash)
- puts "[*] Cracked: #{test}"
- exit
- end
- end
- end
- end
- puts "[*] Trying four characters (eta: #{etime * cset.length * cset.length * cset.length} seconds)..."
- 0.upto(cset.length-1) do |c1|
- 0.upto(cset.length-1) do |c2|
- 0.upto(cset.length-1) do |c3|
- 0.upto(cset.length-1) do |c4|
- test = pass + cset[c1].chr + cset[c2].chr + cset[c3].chr + cset[c4].chr
- if(try(test, chall) == hash)
- puts "[*] Cracked: #{test}"
- exit
- end
- end
- end
- end
- end
|