##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Post
include Msf::Post::Windows::Registry
include Msf::Post::Windows::Priv
SID_PREFIX_USER = 'S-1-5-21-'.freeze
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Windows Gather SMB Share Enumeration via Registry',
'Description' => %q{ This module will enumerate configured and recently used file shares. },
'License' => MSF_LICENSE,
'Author' => [ 'Carlos Perez <carlos_perez[at]darkoperator.com>' ],
'Platform' => [ 'win' ],
'SessionTypes' => %w[shell powershell meterpreter],
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [],
'SideEffects' => []
},
'Compat' => {
'Meterpreter' => {
'Commands' => %w[
stdapi_registry_open_key
stdapi_registry_check_key_exists
]
}
}
)
)
register_options([
OptBool.new('CURRENT', [ true, 'Enumerate currently configured shares', true]),
OptBool.new('RECENT', [ true, 'Enumerate recently mapped shares', true]),
OptBool.new('ENTERED', [ true, 'Enumerate recently entered UNC Paths in the Run Dialog', true])
])
end
# Convert share type ID `val` to readable string
#
# @return [String] Share type as readable string
def share_type(val)
%w[DISK PRINTER DEVICE IPC SPECIAL TEMPORARY][val] || 'UNKNOWN'
end
# Method for enumerating recent mapped drives on target machine
#
# @return [Array] List of recently mounted UNC paths
def enum_recent_mounts(base_key)
partial_path = base_key + '\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer'
explorer_keys = registry_enumkeys(partial_path).to_s || ''
return [] unless explorer_keys.include?('Map Network Drive MRU')
full_path = "#{partial_path}\\Map Network Drive MRU"
vals_found = registry_enumvals(full_path)
return [] unless vals_found
recent_mounts = []
registry_enumvals(full_path).each do |k|
next if k.include?('MRUList')
mounted_path = registry_getvaldata(full_path, k)
recent_mounts << mounted_path if mounted_path.starts_with?('\\\\')
end
recent_mounts
end
# Method for enumerating UNC paths entered in Run dialog box
#
# @return [Array] List of MRU historical UNC paths
def enum_run_unc(base_key)
full_path = base_key + '\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU'
vals_found = registry_enumvals(full_path)
return [] unless vals_found
unc_paths = []
vals_found.each do |k|
next if k.include?('MRUList')
run_entry = registry_getvaldata(full_path, k).to_s
unc_paths << run_entry.gsub(/\\1$/, '') if run_entry.starts_with?('\\\\')
end
unc_paths
end
# Method for enumerating configured shares on a target box
#
# @return [Array] List of network shares in the form of [ name, type, remark, path ]
def enum_conf_shares
shares_key = nil
[
'HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\services\\LanmanServer\\Shares',
'HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\services\\lanmanserver\\Shares'
].each do |k|
if registry_key_exist?(k)
shares_key = k
break
end
end
if shares_key.blank?
print_status('No network shares were found')
return
end
share_names = registry_enumvals(shares_key)
if share_names.empty?
print_status('No network shares were found')
return
end
shares = []
print_status('The following shares were found:')
share_names.each do |sname|
share_info = registry_getvaldata(shares_key, sname)
next if share_info.nil?
print_status("\tName: #{sname}")
stype = remark = path = nil
share_info.each do |e|
name, val = e.split('=')
case name
when 'Path'
path = val
print_status "\tPath: #{path}"
when 'Type'
stype = share_type(val.to_i)
print_status "\tType: #{stype}"
when 'Remark'
remark = val
print_status("\tRemark: #{remark}") unless remark.blank?
end
end
print_status
# Match the format used by auxiliary/scanner/smb/smb_enumshares
# with an added field for path
shares << [ sname, stype, remark, path ]
end
report_note(
host: session,
type: 'smb.shares',
data: { shares: shares },
update: :unique_data
)
end
def run
unless datastore['CURRENT'] || datastore['RECENT'] || datastore['ENTERED']
fail_with(Failure::BadConfig, 'At least one option (CURRENT, RECENT, ENTERED) must be enabled. Nothing to do.')
end
hostname = sysinfo.nil? ? cmd_exec('hostname') : sysinfo['Computer']
print_status("Running module against #{hostname} (#{session.session_host})")
enum_conf_shares if datastore['CURRENT']
return unless datastore['RECENT'] || datastore['ENTERED']
mount_history = []
run_history = []
if is_system? || is_admin?
mount_history = enum_recent_mounts('HKEY_CURRENT_USER') if datastore['RECENT']
run_history = enum_run_unc('HKEY_CURRENT_USER') if datastore['ENTERED']
else
keys = registry_enumkeys('HKU') || []
keys.each do |maybe_sid|
next unless maybe_sid.starts_with?(SID_PREFIX_USER)
next if maybe_sid.include?('_Classes')
mount_history += enum_recent_mounts("HKU\\#{maybe_sid.chomp}") if datastore['RECENT']
run_history += enum_run_unc("HKU\\#{maybe_sid.chomp}") if datastore['ENTERED']
end
end
unless mount_history.empty?
print_status('Recent mounts found:')
mount_history.each do |i|
print_status("\t#{i}")
end
print_status
end
unless run_history.empty?
print_status('Recent UNC paths entered in Run dialog found:')
run_history.each do |i|
print_status("\t#{i}")
end
print_status
end
end
end
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation