hmac_sha1_crack.rb 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. #!/usr/bin/env ruby
  2. ##
  3. # This module requires Metasploit: https://metasploit.com/download
  4. # Current source: https://github.com/rapid7/metasploit-framework
  5. ##
  6. #
  7. # This script cracks HMAC SHA1 hashes. It is strangely necessary as existing tools
  8. # have issues with binary salt values and extremely large salt values. The primary
  9. # goal of this tool is to handle IPMI 2.0 HMAC SHA1 hashes.
  10. #
  11. # Support for this format is being added to both hashcat and jtr, hopefully
  12. # making this code obsolete.
  13. #
  14. msfbase = __FILE__
  15. while File.symlink?(msfbase)
  16. msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))
  17. end
  18. $:.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib')))
  19. require 'msfenv'
  20. $:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB']
  21. require 'rex'
  22. require 'openssl'
  23. def usage
  24. $stderr.puts("\nUsage: #{$0} hashes.txt <wordlist | - >\n")
  25. $stderr.puts("The format of hash file is <identifier>:<hex-salt>:<hash>\n\n")
  26. exit
  27. end
  28. hash_inp = ARGV.shift || usage()
  29. word_inp = ARGV.shift || usage()
  30. usage if [hash_inp, word_inp].include?("-h") or [hash_inp, word_inp].include?("--help")
  31. hash_fd = ::File.open(hash_inp, "rb")
  32. word_fd = $stdin
  33. if word_inp != "-"
  34. word_fd = ::File.open(word_inp, "rb")
  35. end
  36. hashes = []
  37. hash_fd.each_line do |line|
  38. next unless line.strip.length > 0
  39. h_id, h_salt, h_hash = line.unpack("C*").pack("C*").strip.split(':', 3)
  40. unless h_id and h_salt and h_hash
  41. $stderr.puts "[-] Invalid hash entry, missing field: #{line}"
  42. next
  43. end
  44. unless h_salt =~ /^[a-f0-9]+$/i
  45. $stderr.puts "[-] Invalid hash entry, salt must be in hex: #{line}"
  46. next
  47. end
  48. hashes << [h_id, [h_salt].pack("H*"), [h_hash].pack("H*") ]
  49. end
  50. hash_fd.close
  51. stime = Time.now.to_f
  52. count = 0
  53. cracked = 0
  54. word_fd.each_line do |line|
  55. # Preferable to strip so we can test passwords made of whitespace (or null)
  56. line = line.unpack("C*").pack("C*").sub(/\r?\n?$/, '')
  57. hashes.each do |hinfo|
  58. if OpenSSL::HMAC.digest('sha1', line.to_s, hinfo[1]) == hinfo[2]
  59. $stdout.puts [ hinfo[0], hinfo[1].unpack("H*").first, hinfo[2].unpack("H*").first, line.to_s ].join(":")
  60. $stdout.flush
  61. hinfo[3] = true
  62. cracked += 1
  63. end
  64. count += 1
  65. if count % 2500000 == 0
  66. $stderr.puts "[*] Found #{cracked} passwords with #{hashes.length} left (#{(count / (Time.now.to_f - stime)).to_i}/s)"
  67. end
  68. end
  69. hashes.delete_if {|e| e[3] }
  70. break if hashes.length == 0
  71. end
  72. word_fd.close
  73. $stderr.puts "[*] Cracked #{cracked} passwords with #{hashes.length} left (#{(count / (Time.now.to_f - stime)).to_i}/s)"