From f00c38cfe235053fbb74a926c8faf8153594593c Mon Sep 17 00:00:00 2001 From: h00die Date: Fri, 22 Mar 2019 15:04:58 -0400 Subject: [PATCH] make creds exporter for jtr format --- lib/metasploit/framework/jtr/formatter.rb | 64 ++++++++++++++++++ lib/msf/core/auxiliary/jtr.rb | 66 +------------------ .../ui/console/command_dispatcher/creds.rb | 24 ++++++- 3 files changed, 88 insertions(+), 66 deletions(-) create mode 100644 lib/metasploit/framework/jtr/formatter.rb diff --git a/lib/metasploit/framework/jtr/formatter.rb b/lib/metasploit/framework/jtr/formatter.rb new file mode 100644 index 0000000000..dc7fe70645 --- /dev/null +++ b/lib/metasploit/framework/jtr/formatter.rb @@ -0,0 +1,64 @@ +# This method takes a {framework.db.cred}, and normalizes it +# to the string format JTR is expecting. +# +# @param [credClass] a credential from framework.db +# @return [String] the hash in jtr format or nil on no mach +def hash_to_jtr(cred) + case cred.private.type + when 'Metasploit::Credential::NTLMHash' + return "#{cred.public.username}:#{cred.id}:#{cred.private.data}:::#{cred.id}" + when 'Metasploit::Credential::PostgresMD5' + if cred.private.jtr_format =~ /postgres|raw-md5/ + # john --list=subformats | grep 'PostgreSQL MD5' + #UserFormat = dynamic_1034 type = dynamic_1034: md5($p.$u) (PostgreSQL MD5) + hash_string = cred.private.data + hash_string.gsub!(/^md5/, '') + return "#{cred.public.username}:$dynamic_1034$#{hash_string}" + end + when 'Metasploit::Credential::NonreplayableHash' + case cred.private.jtr_format + # oracle 11+ password hash descriptions: + # this password is stored as a long ascii string with several sections + # https://www.trustwave.com/en-us/resources/blogs/spiderlabs-blog/changes-in-oracle-database-12c-password-hashes/ + # example: + # hash = [] + # hash << "S:8F2D65FB5547B71C8DA3760F10960428CD307B1C6271691FC55C1F56554A;" + # hash << "H:DC9894A01797D91D92ECA1DA66242209;" + # hash << "T:23D1F8CAC9001F69630ED2DD8DF67DD3BE5C470B5EA97B622F757FE102D8BF14BEDC94A3CC046D10858D885DB656DC0CBF899A79CD8C76B788744844CADE54EEEB4FDEC478FB7C7CBFBBAC57BA3EF22C" + # puts hash.join('') + # S: = 60 characters -> sha1(password + salt (10 bytes)) + # 40 char sha1, 20 char salt + # hash is 8F2D65FB5547B71C8DA3760F10960428CD307B1C + # salt is 6271691FC55C1F56554A + # H: = 32 characters + # legacy MD5 + # T: = 160 characters + # PBKDF2-based SHA512 hash specific to 12C (12.1.0.2+) + when /raw-sha1|oracle11/ # oracle 11 + if cred.private.data =~ /S:([\dA-F]{60})/ # oracle 11 + return "#{cred.public.username}:#{$1}:#{cred.id}:" + end + when /oracle12c/ + if cred.private.data =~ /T:([\dA-F]{160})/ # oracle 12c + return "#{cred.public.username}:$oracle12c$#{$1.downcase}:#{cred.id}:" + end + when /dynamic_1506/ + if cred.private.data =~ /H:([\dA-F]{32})/ # oracle 11 + return "#{cred.public.username.upcase}:$dynamic_1506$#{$1}:#{cred.id}:" + end + when /oracle/ # oracle + if cred.private.jtr_format.start_with?('des') # 'des,oracle', not oracle11/12c + return "#{cred.public.username}:O$#{cred.public.username}##{cred.private.data}:#{cred.id}:" + end + when /md5|des|bsdi|crypt|bf/ + # md5(crypt), des(crypt), b(crypt) + return "#{cred.public.username}:#{cred.private.data}:::::#{cred.id}:" + else + # /mysql|mysql-sha1/ + # /mssql|mssql05|mssql12/ + # /des(crypt)/ + return "#{cred.public.username}:#{cred.private.data}:#{cred.id}:" + end + end + nil +end diff --git a/lib/msf/core/auxiliary/jtr.rb b/lib/msf/core/auxiliary/jtr.rb index 12a7f84a1f..15f2daff60 100644 --- a/lib/msf/core/auxiliary/jtr.rb +++ b/lib/msf/core/auxiliary/jtr.rb @@ -4,6 +4,7 @@ require 'fileutils' require 'rex/proto/ntlm/crypt' require 'metasploit/framework/jtr/cracker' require 'metasploit/framework/jtr/wordlist' +require 'metasploit/framework/jtr/formatter' module Msf @@ -96,70 +97,5 @@ module Auxiliary::JohnTheRipper ) wordlist.to_file(max_len) end - - # This method takes a {framework.db.cred}, and normalizes it - # to the string format JTR is expecting. - # - # @param [credClass] a credential from framework.db - # @return [String] the hash in jtr format or nil on no mach - def hash_to_jtr(cred) - case cred.private.type - when 'Metasploit::Credential::NTLMHash' - return "#{cred.public.username}:#{cred.id}:#{cred.private.data}:::#{cred.id}" - when 'Metasploit::Credential::PostgresMD5' - if cred.private.jtr_format =~ /postgres|raw-md5/ - # john --list=subformats | grep 'PostgreSQL MD5' - #UserFormat = dynamic_1034 type = dynamic_1034: md5($p.$u) (PostgreSQL MD5) - hash_string = cred.private.data - hash_string.gsub!(/^md5/, '') - return "#{cred.public.username}:$dynamic_1034$#{hash_string}" - end - when 'Metasploit::Credential::NonreplayableHash' - case cred.private.jtr_format - # oracle 11+ password hash descriptions: - # this password is stored as a long ascii string with several sections - # https://www.trustwave.com/en-us/resources/blogs/spiderlabs-blog/changes-in-oracle-database-12c-password-hashes/ - # example: - # hash = [] - # hash << "S:8F2D65FB5547B71C8DA3760F10960428CD307B1C6271691FC55C1F56554A;" - # hash << "H:DC9894A01797D91D92ECA1DA66242209;" - # hash << "T:23D1F8CAC9001F69630ED2DD8DF67DD3BE5C470B5EA97B622F757FE102D8BF14BEDC94A3CC046D10858D885DB656DC0CBF899A79CD8C76B788744844CADE54EEEB4FDEC478FB7C7CBFBBAC57BA3EF22C" - # puts hash.join('') - # S: = 60 characters -> sha1(password + salt (10 bytes)) - # 40 char sha1, 20 char salt - # hash is 8F2D65FB5547B71C8DA3760F10960428CD307B1C - # salt is 6271691FC55C1F56554A - # H: = 32 characters - # legacy MD5 - # T: = 160 characters - # PBKDF2-based SHA512 hash specific to 12C (12.1.0.2+) - when /raw-sha1|oracle11/ # oracle 11 - if cred.private.data =~ /S:([\dA-F]{60})/ # oracle 11 - return "#{cred.public.username}:#{$1}:#{cred.id}:" - end - when /oracle12c/ - if cred.private.data =~ /T:([\dA-F]{160})/ # oracle 12c - return "#{cred.public.username}:$oracle12c$#{$1.downcase}:#{cred.id}:" - end - when /dynamic_1506/ - if cred.private.data =~ /H:([\dA-F]{32})/ # oracle 11 - return "#{cred.public.username.upcase}:$dynamic_1506$#{$1}:#{cred.id}:" - end - when /oracle/ # oracle - if cred.private.jtr_format.start_with?('des') # 'des,oracle', not oracle11/12c - return "#{cred.public.username}:O$#{cred.public.username}##{cred.private.data}:#{cred.id}:" - end - when /md5|des|bsdi|crypt|bf/ - # md5(crypt), des(crypt), b(crypt) - return "#{cred.public.username}:#{cred.private.data}:::::#{cred.id}:" - else - # /mysql|mysql-sha1/ - # /mssql|mssql05|mssql12/ - # /des(crypt)/ - return "#{cred.public.username}:#{cred.private.data}:#{cred.id}:" - end - end - nil - end end end diff --git a/lib/msf/ui/console/command_dispatcher/creds.rb b/lib/msf/ui/console/command_dispatcher/creds.rb index 15e0562ee9..b26a89eb47 100644 --- a/lib/msf/ui/console/command_dispatcher/creds.rb +++ b/lib/msf/ui/console/command_dispatcher/creds.rb @@ -3,6 +3,7 @@ require 'rexml/document' require 'rex/parser/nmap_xml' require 'msf/core/db_export' +require 'msf/core/auxiliary/jtr' module Msf module Ui @@ -105,6 +106,8 @@ class Creds cmd_creds_help when 'add' creds_add(*args) + when 'export' + creds_export else # then it's not actually a subcommand args.unshift(subcommand) if subcommand @@ -126,6 +129,9 @@ class Creds print_line "Usage - Listing credentials:" print_line " creds [filter options] [address range]" print_line + print_line "Usage - Exporting in JtR format:" + print_line " creds export" + print_line print_line "Usage - Adding credentials:" print_line " creds add uses the following named parameters." { @@ -560,7 +566,23 @@ class Creds return tabs end - + def creds_export + hashlist = Rex::Quickfile.new("jtr_hashes") + count = 0 + ['Metasploit::Credential::NonreplayableHash', + 'Metasploit::Credential::PostgresMD5', + 'Metasploit::Credential::NTLMHash'].each do |type| + framework.db.creds(type: type).each do |core| + formatted = hash_to_jtr(core) + unless formatted.nil? + count += 1 + hashlist.puts formatted + end + end + end + hashlist.close + print_status("#{count} JtR formatted hashes written to #{hashlist.path}") + end end end end end end