Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/auxiliary/analyze/crack_mobile.rb
Views: 11778
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Auxiliary::PasswordCracker78def initialize9super(10'Name' => 'Password Cracker: Mobile',11'Description' => %{12This module uses Hashcat to identify weak passwords that have been13acquired from Android systems. These utilize MD5 or SHA1 hashing.14Android (Samsung) SHA1 is format 5800 in Hashcat. Android15(non-Samsung) SHA1 is format 110 in Hashcat. Android MD5 is format 10.16JTR does not support Android hashes at the time of writing.17},18'Author' => [19'h00die'20],21'License' => MSF_LICENSE, # JtR itself is GPLv2, but this wrapper is MSF (BSD)22'Actions' => [23['hashcat', { 'Description' => 'Use Hashcat' }],24],25'DefaultAction' => 'hashcat',26)2728register_options(29[30OptBool.new('SAMSUNG', [false, 'Include Samsung SHA1 hashes', true]),31OptBool.new('SHA1', [false, 'Include Android-SHA1 hashes', true]),32OptBool.new('MD5', [false, 'Include Android-MD5 hashes', true]),33OptBool.new('INCREMENTAL', [false, 'Run in incremental mode', true]),34OptBool.new('WORDLIST', [false, 'Run in wordlist mode', true])35]36)37end3839def show_command(cracker_instance)40return unless datastore['ShowCommand']4142if action.name == 'john' # leaving this code here figuring jtr will eventually come around, but its an unused code block43cmd = cracker_instance.john_crack_command44elsif action.name == 'hashcat'45cmd = cracker_instance.hashcat_crack_command46end47print_status(" Cracking Command: #{cmd.join(' ')}")48end4950def run51def check_results(passwords, results, hash_type, method)52passwords.each do |password_line|53password_line.chomp!54next if password_line.blank?5556fields = password_line.split(':')57cred = { 'hash_type' => hash_type, 'method' => method }58# If we don't have an expected minimum number of fields, this is probably not a hash line59if action.name == 'john'60next unless fields.count >= 36162cred['username'] = fields.shift63cred['core_id'] = fields.pop644.times { fields.pop } # Get rid of extra :65cred['password'] = fields.join(':') # Anything left must be the password. This accounts for passwords with semi-colons in it66elsif action.name == 'hashcat'67next unless fields.count >= 26869cred['core_id'] = fields.shift70cred['hash'] = "#{fields.shift}:#{fields.shift}" # grab hash and salt71cred['password'] = fields.join(':') # Anything left must be the password. This accounts for passwords with : in them72next if cred['core_id'].include?("Hashfile '") && cred['core_id'].include?("' on line ") # skip error lines7374# we don't have the username since we overloaded it with the core_id (since its a better fit for us)75# so we can now just go grab the username from the DB76cred['username'] = framework.db.creds(workspace: myworkspace, id: cred['core_id'])[0].public.username77end78results = process_cracker_results(results, cred)79end80results81end8283tbl = Rex::Text::Table.new(84'Header' => 'Cracked Hashes',85'Indent' => 1,86'Columns' => ['DB ID', 'Hash Type', 'Username', 'Cracked Password', 'Method']87)8889# array of hashes in jtr_format in the db, converted to an OR combined regex90hash_types_to_crack = []91hash_types_to_crack << 'android-sha1' if datastore['SHA1']92hash_types_to_crack << 'android-samsung-sha1' if datastore['SAMSUNG']93hash_types_to_crack << 'android-md5' if datastore['MD5']9495jobs_to_do = []9697# build our job list98hash_types_to_crack.each do |hash_type|99job = hash_job(hash_type, action.name)100if job.nil?101print_status("No #{hash_type} found to crack")102else103jobs_to_do << job104end105end106107# bail early of no jobs to do108if jobs_to_do.empty?109print_good("No uncracked password hashes found for: #{hash_types_to_crack.join(', ')}")110return111end112113# array of arrays for cracked passwords.114# Inner array format: db_id, hash_type, username, password, method_of_crack115results = []116117cracker = new_password_cracker(action.name)118119# generate our wordlist and close the file handle. max length of DES is 8120wordlist = wordlist_file(8)121unless wordlist122print_error('This module cannot run without a database connected. Use db_connect to connect to a database.')123return124end125126wordlist.close127print_status "Wordlist file written out to #{wordlist.path}"128129cleanup_files = [wordlist.path]130131jobs_to_do.each do |job|132format = job['type']133hash_file = Rex::Quickfile.new("hashes_#{job['type']}_")134hash_file.puts job['formatted_hashlist']135hash_file.close136cracker.hash_path = hash_file.path137cleanup_files << hash_file.path138# dupe our original cracker so we can safely change options between each run139cracker_instance = cracker.dup140cracker_instance.format = format141142if action.name == 'john'143cracker_instance.fork = datastore['FORK']144end145146# first check if anything has already been cracked so we don't report it incorrectly147print_status "Checking #{format} hashes already cracked..."148results = check_results(cracker_instance.each_cracked_password, results, format, 'Already Cracked/POT')149vprint_good(append_results(tbl, results)) unless results.empty?150job['cred_ids_left_to_crack'] = job['cred_ids_left_to_crack'] - results.map { |i| i[0].to_i } # remove cracked hashes from the hash list151next if job['cred_ids_left_to_crack'].empty?152153if action.name == 'john'154print_status "Cracking #{format} hashes in single mode..."155cracker_instance.mode_single(wordlist.path)156show_command cracker_instance157cracker_instance.crack do |line|158vprint_status line.chomp159end160results = check_results(cracker_instance.each_cracked_password, results, format, 'Single')161vprint_good(append_results(tbl, results)) unless results.empty?162job['cred_ids_left_to_crack'] = job['cred_ids_left_to_crack'] - results.map { |i| i[0].to_i } # remove cracked hashes from the hash list163next if job['cred_ids_left_to_crack'].empty?164165print_status "Cracking #{format} hashes in normal mode..."166cracker_instance.mode_normal167show_command cracker_instance168cracker_instance.crack do |line|169vprint_status line.chomp170end171results = check_results(cracker_instance.each_cracked_password, results, format, 'Normal')172vprint_good(append_results(tbl, results)) unless results.empty?173job['cred_ids_left_to_crack'] = job['cred_ids_left_to_crack'] - results.map { |i| i[0].to_i } # remove cracked hashes from the hash list174next if job['cred_ids_left_to_crack'].empty?175end176177if action.name == 'hashcat'178print_status "Cracking #{format} hashes in pin mode..."179cracker_instance.mode_pin180show_command cracker_instance181cracker_instance.crack do |line|182vprint_status line.chomp183end184results = check_results(cracker_instance.each_cracked_password, results, format, 'Pin')185vprint_good(append_results(tbl, results)) unless results.empty?186job['cred_ids_left_to_crack'] = job['cred_ids_left_to_crack'] - results.map { |i| i[0].to_i } # remove cracked hashes from the hash list187next if job['cred_ids_left_to_crack'].empty?188end189190if datastore['INCREMENTAL']191print_status "Cracking #{format} hashes in incremental mode..."192cracker_instance.mode_incremental193show_command cracker_instance194cracker_instance.crack do |line|195vprint_status line.chomp196end197results = check_results(cracker_instance.each_cracked_password, results, format, 'Incremental')198vprint_good(append_results(tbl, results)) unless results.empty?199job['cred_ids_left_to_crack'] = job['cred_ids_left_to_crack'] - results.map { |i| i[0].to_i } # remove cracked hashes from the hash list200next if job['cred_ids_left_to_crack'].empty?201end202203if datastore['WORDLIST']204print_status "Cracking #{format} hashes in wordlist mode..."205cracker_instance.mode_wordlist(wordlist.path)206# Turn on KoreLogic rules if the user asked for it207if action.name == 'john' && datastore['KORELOGIC']208cracker_instance.rules = 'KoreLogicRules'209print_status 'Applying KoreLogic ruleset...'210end211show_command cracker_instance212cracker_instance.crack do |line|213vprint_status line.chomp214end215216results = check_results(cracker_instance.each_cracked_password, results, format, 'Wordlist')217vprint_good(append_results(tbl, results)) unless results.empty?218job['cred_ids_left_to_crack'] = job['cred_ids_left_to_crack'] - results.map { |i| i[0].to_i } # remove cracked hashes from the hash list219next if job['cred_ids_left_to_crack'].empty?220end221222# give a final print of results223print_good(append_results(tbl, results))224end225226if datastore['DeleteTempFiles']227cleanup_files.each do |f|228File.delete(f)229end230end231end232end233234235