Module: Msf::Auxiliary::PasswordCracker
- Includes:
- Report
- Defined in:
- lib/msf/core/auxiliary/password_cracker.rb
Overview
This module provides methods for working with a Password Cracker
Instance Method Summary collapse
-
#append_results(tbl, cracked_hashes) ⇒ String
This method appends a list of cracked hashes to the list used to generate the printed table.
-
#cracker_results_table ⇒ Rex::Text::Table
This method returns a cracker results table.
-
#hash_job(jtr_type, cracker) ⇒ Hash
This method creates a job for the password cracker to do.
-
#initialize(info = {}) ⇒ Object
Initializes an instance of an auxiliary module that calls out to John the Ripper (jtr).
- #john_lm_upper_to_ntlm(pwd, hash) ⇒ String?
-
#new_password_cracker(cracking_application) ⇒ nilClass, Metasploit::Framework::PasswordCracker::Cracker
This method creates a new Metasploit::Framework::PasswordCracker::Cracker and populates some of the attributes based on the module datastore options.
-
#password_cracked?(hash) ⇒ Boolean
This method determines if a given password hash already been cracked in the database.
-
#process_cracker_results(results, cred) ⇒ Array
This method takes a results table, and a newly cracked cred, and adds the cred to the table if it isn’t there already.
- #resolve_cracking_application(cracking_application, cracker) ⇒ Object
-
#wordlist_file(max_len = 0) ⇒ nilClass, Rex::Quickfile
This method instantiates a Metasploit::Framework::JtR::Wordlist, writes the data out to a file and returns the Rex::Quickfile object.
Methods included from Report
#active_db?, #create_cracked_credential, #create_credential, #create_credential_and_login, #create_credential_login, #db, #db_warning_given?, #get_client, #get_host, #inside_workspace_boundary?, #invalidate_login, #mytask, #myworkspace, #myworkspace_id, #report_auth_info, #report_client, #report_exploit, #report_host, #report_loot, #report_note, #report_service, #report_vuln, #report_web_form, #report_web_page, #report_web_site, #report_web_vuln, #store_cred, #store_local, #store_loot
Methods included from Metasploit::Framework::Require
optionally, optionally_active_record_railtie, optionally_include_metasploit_credential_creation, #optionally_include_metasploit_credential_creation, optionally_require_metasploit_db_gem_engines
Instance Method Details
#append_results(tbl, cracked_hashes) ⇒ String
This method appends a list of cracked hashes to the list used to generate the printed table
237 238 239 240 241 242 243 244 |
# File 'lib/msf/core/auxiliary/password_cracker.rb', line 237 def append_results(tbl, cracked_hashes) cracked_hashes.each do |row| next if tbl.rows.include? row tbl << row end tbl.to_s end |
#cracker_results_table ⇒ Rex::Text::Table
This method returns a cracker results table
249 250 251 252 253 254 255 |
# File 'lib/msf/core/auxiliary/password_cracker.rb', line 249 def cracker_results_table Rex::Text::Table.new( 'Header' => 'Cracked Hashes', 'Indent' => 1, 'Columns' => ['DB ID', 'Hash Type', 'Username', 'Cracked Password', 'Method'] ) end |
#hash_job(jtr_type, cracker) ⇒ Hash
This method creates a job for the password cracker to do. A job is categorized by the hash type and will include the hash type (type), formatted_hashlist (hashes in the cracker’s format), creds (db objects for each hash), and cred_ids_left_to_crack (array of db ids that aren’t cracked yet)
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/msf/core/auxiliary/password_cracker.rb', line 174 def hash_job(jtr_type, cracker) # create the base data job = { 'type' => jtr_type, 'formatted_hashlist' => [], 'creds' => [], 'cred_ids_left_to_crack' => [] } job['db_formats'] = Metasploit::Framework::PasswordCracker::JtR::Formatter.jtr_to_db(jtr_type) if jtr_type == 'dynamic_1034' # postgres creds = framework.db.creds(workspace: myworkspace, type: 'Metasploit::Credential::PostgresMD5') elsif ['lm', 'nt'].include? jtr_type creds = framework.db.creds(workspace: myworkspace, type: 'Metasploit::Credential::NTLMHash') else creds = framework.db.creds(workspace: myworkspace, type: 'Metasploit::Credential::NonreplayableHash') end creds.each do |core| jtr_format = core.private.jtr_format # Unfortunately NTLMHash always set JtR Format to 'nt,lm' so we have to do a special case here # to figure out which it is if jtr_format == 'nt,lm' jtr_format = core.private.data.start_with?('aad3b435b51404eeaad3b435b51404ee') ? 'nt' : 'lm' end next unless job['db_formats'].include? jtr_format # only add hashes which havne't been cracked next if password_cracked?(core.private.data) job['creds'] << core job['cred_ids_left_to_crack'] << core.id if cracker == 'john' job['formatted_hashlist'] << Metasploit::Framework::PasswordCracker::JtR::Formatter.hash_to_jtr(core) elsif cracker == 'hashcat' job['formatted_hashlist'] << Metasploit::Framework::PasswordCracker::Hashcat::Formatter.hash_to_hashcat(core) end end if job['creds'].length > 0 return job end nil end |
#initialize(info = {}) ⇒ Object
Initializes an instance of an auxiliary module that calls out to John the Ripper (jtr)
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/msf/core/auxiliary/password_cracker.rb', line 23 def initialize(info = {}) super ( [ OptPath.new('CONFIG', [false, 'The path to a John config file to use instead of the default']), OptPath.new('CUSTOM_WORDLIST', [false, 'The path to an optional custom wordlist']), OptInt.new('ITERATION_TIMEOUT', [false, 'The max-run-time for each iteration of cracking']), OptPath.new('CRACKER_PATH', [false, 'The absolute path to the cracker executable']), OptInt.new('FORK', [false, 'Forks for John the Ripper to use', 1]), OptBool.new('KORELOGIC', [false, 'Apply the KoreLogic rules to John the Ripper Wordlist Mode(slower)', false]), OptBool.new('MUTATE', [false, 'Apply common mutations to the Wordlist (SLOW)', false]), OptPath.new('POT', [false, 'The path to a John POT file to use instead of the default']), OptBool.new('USE_CREDS', [false, 'Use existing credential data saved in the database', true]), OptBool.new('USE_DB_INFO', [false, 'Use looted database schema info to seed the wordlist', true]), OptBool.new('USE_DEFAULT_WORDLIST', [false, 'Use the default metasploit wordlist', true]), OptBool.new('USE_HOSTNAMES', [false, 'Seed the wordlist with hostnames from the workspace', true]), OptBool.new('USE_ROOT_WORDS', [false, 'Use the Common Root Words Wordlist', true]) ], Msf::Auxiliary::PasswordCracker ) ( [ OptBool.new('DeleteTempFiles', [false, 'Delete temporary wordlist and hash files', true]), OptBool.new('OptimizeKernel', [false, 'Utilize Optimized Kernels in Hashcat', true]), OptBool.new('ShowCommand', [false, 'Print the cracker command being used', true]), ], Msf::Auxiliary::PasswordCracker ) end |
#john_lm_upper_to_ntlm(pwd, hash) ⇒ String?
59 60 61 62 63 64 65 66 67 68 |
# File 'lib/msf/core/auxiliary/password_cracker.rb', line 59 def john_lm_upper_to_ntlm(pwd, hash) pwd = pwd.upcase hash = hash.upcase Rex::Text.permute_case(pwd).each do |str| if hash == Rex::Proto::NTLM::Crypt.ntlm_hash(str).unpack('H*')[0].upcase return str end end nil end |
#new_password_cracker(cracking_application) ⇒ nilClass, Metasploit::Framework::PasswordCracker::Cracker
This method creates a new Metasploit::Framework::PasswordCracker::Cracker and populates some of the attributes based on the module datastore options.
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/msf/core/auxiliary/password_cracker.rb', line 75 def new_password_cracker(cracking_application) fail_with(Msf::Module::Failure::BadConfig, 'Password cracking is not available without an active database connection.') unless framework.db.active cracker = Metasploit::Framework::PasswordCracker::Cracker.new( config: datastore['CONFIG'], cracker_path: datastore['CRACKER_PATH'], max_runtime: datastore['ITERATION_TIMEOUT'], pot: datastore['POT'], optimize: datastore['OptimizeKernel'], wordlist: datastore['CUSTOM_WORDLIST'] ) cracker.cracker = resolve_cracking_application(cracking_application, cracker) begin cracker.binary_path rescue Metasploit::Framework::PasswordCracker::PasswordCrackerNotFoundError => e fail_with(Msf::Module::Failure::BadConfig, e.) end # throw this to a local variable since it causes a shell out to pull the version cracker_version = cracker.cracker_version if cracker.cracker == 'john' && (cracker_version.nil? || !cracker_version.include?('jumbo')) fail_with(Msf::Module::Failure::BadConfig, 'John the Ripper JUMBO patch version required. See https://github.com/magnumripper/JohnTheRipper') end print_good("#{cracker.cracker} Version Detected: #{cracker_version}") cracker end |
#password_cracked?(hash) ⇒ Boolean
This method determines if a given password hash already been cracked in the database
156 157 158 159 160 161 162 163 164 165 |
# File 'lib/msf/core/auxiliary/password_cracker.rb', line 156 def password_cracked?(hash) framework.db.creds({ pass: hash }).each do |test_cred| test_cred.public.cores.each do |core| if core.origin_type == 'Metasploit::Credential::Origin::CrackedPassword' return true end end end false end |
#process_cracker_results(results, cred) ⇒ Array
This method takes a results table, and a newly cracked cred, and adds the cred to the table if it isn’t there already. It also creates the cracked credential in the database.
220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/msf/core/auxiliary/password_cracker.rb', line 220 def process_cracker_results(results, cred) return results if cred['core_id'].nil? # make sure we have good data # make sure we dont add the same one again if results.select { |r| r.first == cred['core_id'] }.empty? results << [cred['core_id'], cred['hash_type'], cred['username'], cred['password'], cred['method']] end create_cracked_credential(username: cred['username'], password: cred['password'], core_id: cred['core_id']) results end |
#resolve_cracking_application(cracking_application, cracker) ⇒ Object
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/msf/core/auxiliary/password_cracker.rb', line 100 def resolve_cracking_application(cracking_application, cracker) return cracking_application unless cracking_application == 'auto' if cracker.cracker_path.present? basename = ::File.basename(cracker.cracker_path).downcase return 'john' if basename.start_with?('john') return 'hashcat' if basename.start_with?('hashcat') fail_with( Msf::Module::Failure::BadConfig, "CRACKER_PATH '#{cracker.cracker_path}' does not look like john or hashcat; set ACTION to 'john' or 'hashcat'." ) end %w[john hashcat].each do |candidate| cracker.cracker = candidate begin cracker.binary_path return candidate rescue Metasploit::Framework::PasswordCracker::PasswordCrackerNotFoundError next end end fail_with( Msf::Module::Failure::BadConfig, 'No suitable john/hashcat binary was found on the system. Set CRACKER_PATH or ACTION.' ) end |
#wordlist_file(max_len = 0) ⇒ nilClass, Rex::Quickfile
This method instantiates a Metasploit::Framework::JtR::Wordlist, writes the data out to a file and returns the Rex::Quickfile object.
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/msf/core/auxiliary/password_cracker.rb', line 136 def wordlist_file(max_len = 0) return nil unless framework.db.active wordlist = Metasploit::Framework::PasswordCracker::Wordlist.new( custom_wordlist: datastore['CUSTOM_WORDLIST'], mutate: datastore['MUTATE'], use_creds: datastore['USE_CREDS'], use_db_info: datastore['USE_DB_INFO'], use_default_wordlist: datastore['USE_DEFAULT_WORDLIST'], use_hostnames: datastore['USE_HOSTNAMES'], use_common_root: datastore['USE_ROOT_WORDS'], workspace: myworkspace ) wordlist.to_file(max_len) end |