723 lines
21 KiB
Ruby
723 lines
21 KiB
Ruby
# -*- coding: binary -*-
|
|
|
|
module Msf
|
|
class Post
|
|
module Windows
|
|
|
|
module Registry
|
|
|
|
include Msf::Post::Windows::CliParse
|
|
|
|
#
|
|
# This is the default view. It reflects what the remote process would see
|
|
# natively. So, if you are using a remote 32-bit meterpreter session, you
|
|
# will see 32-bit registry keys and values.
|
|
#
|
|
REGISTRY_VIEW_NATIVE = 0
|
|
|
|
#
|
|
# Access 32-bit registry keys and values regardless of whether the session is
|
|
# 32 or 64-bit.
|
|
#
|
|
REGISTRY_VIEW_32_BIT = 1
|
|
|
|
#
|
|
# Access 64-bit registry keys and values regardless of whether the session is
|
|
# 32 or 64-bit.
|
|
#
|
|
REGISTRY_VIEW_64_BIT = 2
|
|
|
|
#
|
|
# Windows Registry Constants.
|
|
#
|
|
REG_NONE = 0
|
|
REG_SZ = 1
|
|
REG_EXPAND_SZ = 2
|
|
REG_BINARY = 3
|
|
REG_DWORD = 4
|
|
REG_LITTLE_ENDIAN = 4
|
|
REG_BIG_ENDIAN = 5
|
|
REG_LINK = 6
|
|
REG_MULTI_SZ = 7
|
|
REG_QWORD = 11
|
|
|
|
HKEY_CLASSES_ROOT = 0x80000000
|
|
HKEY_CURRENT_USER = 0x80000001
|
|
HKEY_LOCAL_MACHINE = 0x80000002
|
|
HKEY_USERS = 0x80000003
|
|
HKEY_PERFORMANCE_DATA = 0x80000004
|
|
HKEY_CURRENT_CONFIG = 0x80000005
|
|
HKEY_DYN_DATA = 0x80000006
|
|
|
|
def initialize(info = {})
|
|
super(
|
|
update_info(
|
|
info,
|
|
'Compat' => {
|
|
'Meterpreter' => {
|
|
'Commands' => %w[
|
|
stdapi_registry_check_key_exists
|
|
stdapi_registry_create_key
|
|
stdapi_registry_delete_key
|
|
stdapi_registry_enum_key_direct
|
|
stdapi_registry_enum_value_direct
|
|
stdapi_registry_load_key
|
|
stdapi_registry_open_key
|
|
stdapi_registry_query_value_direct
|
|
stdapi_registry_set_value_direct
|
|
stdapi_registry_unload_key
|
|
stdapi_sys_config_getprivs
|
|
]
|
|
}
|
|
}
|
|
)
|
|
)
|
|
end
|
|
|
|
#
|
|
# Lookup registry hives by key.
|
|
#
|
|
def registry_hive_lookup(hive)
|
|
case hive
|
|
when 'HKCR'
|
|
HKEY_LOCAL_MACHINE
|
|
when 'HKCU'
|
|
HKEY_CURRENT_USER
|
|
when 'HKLM'
|
|
HKEY_LOCAL_MACHINE
|
|
when 'HKU'
|
|
HKEY_USERS
|
|
when 'HKPD'
|
|
HKEY_PERFORMANCE_DATA
|
|
when 'HKCC'
|
|
HKEY_CURRENT_CONFIG
|
|
when 'HKDD'
|
|
HKEY_DYN_DATA
|
|
else
|
|
HKEY_LOCAL_MACHINE
|
|
end
|
|
end
|
|
|
|
#
|
|
# Load a hive file
|
|
#
|
|
def registry_loadkey(key, file)
|
|
if session.commands.include?(Rex::Post::Meterpreter::Extensions::Stdapi::COMMAND_ID_STDAPI_REGISTRY_LOAD_KEY)
|
|
meterpreter_registry_loadkey(key, file)
|
|
else
|
|
shell_registry_loadkey(key, file)
|
|
end
|
|
end
|
|
|
|
#
|
|
# Unload a hive file
|
|
#
|
|
def registry_unloadkey(key)
|
|
if session.commands.include?(Rex::Post::Meterpreter::Extensions::Stdapi::COMMAND_ID_STDAPI_REGISTRY_UNLOAD_KEY)
|
|
meterpreter_registry_unloadkey(key)
|
|
else
|
|
shell_registry_unloadkey(key)
|
|
end
|
|
end
|
|
|
|
#
|
|
# Create the given registry key
|
|
#
|
|
def registry_createkey(key, view = REGISTRY_VIEW_NATIVE)
|
|
if session.commands.include?(Rex::Post::Meterpreter::Extensions::Stdapi::COMMAND_ID_STDAPI_REGISTRY_CREATE_KEY)
|
|
meterpreter_registry_createkey(key, view)
|
|
else
|
|
shell_registry_createkey(key, view)
|
|
end
|
|
end
|
|
|
|
#
|
|
# Deletes a registry value given the key and value name
|
|
#
|
|
# returns true if successful
|
|
#
|
|
def registry_deleteval(key, valname, view = REGISTRY_VIEW_NATIVE)
|
|
if session.commands.include?(Rex::Post::Meterpreter::Extensions::Stdapi::COMMAND_ID_STDAPI_REGISTRY_DELETE_KEY)
|
|
meterpreter_registry_deleteval(key, valname, view)
|
|
else
|
|
shell_registry_deleteval(key, valname, view)
|
|
end
|
|
end
|
|
|
|
#
|
|
# Delete a given registry key
|
|
#
|
|
# returns true if successful
|
|
#
|
|
def registry_deletekey(key, view = REGISTRY_VIEW_NATIVE)
|
|
if session.commands.include?(Rex::Post::Meterpreter::Extensions::Stdapi::COMMAND_ID_STDAPI_REGISTRY_DELETE_KEY)
|
|
meterpreter_registry_deletekey(key, view)
|
|
else
|
|
shell_registry_deletekey(key, view)
|
|
end
|
|
end
|
|
|
|
#
|
|
# Return an array of subkeys for the given registry key
|
|
#
|
|
def registry_enumkeys(key, view = REGISTRY_VIEW_NATIVE)
|
|
if session.commands.include?(Rex::Post::Meterpreter::Extensions::Stdapi::COMMAND_ID_STDAPI_REGISTRY_ENUM_KEY)
|
|
meterpreter_registry_enumkeys(key, view)
|
|
else
|
|
shell_registry_enumkeys(key, view)
|
|
end
|
|
end
|
|
|
|
#
|
|
# Return an array of value names for the given registry key
|
|
#
|
|
def registry_enumvals(key, view = REGISTRY_VIEW_NATIVE)
|
|
if session.commands.include?(Rex::Post::Meterpreter::Extensions::Stdapi::COMMAND_ID_STDAPI_REGISTRY_ENUM_VALUE_DIRECT)
|
|
meterpreter_registry_enumvals(key, view)
|
|
else
|
|
shell_registry_enumvals(key, view)
|
|
end
|
|
end
|
|
|
|
#
|
|
# Return the data of a given registry key and value
|
|
#
|
|
def registry_getvaldata(key, valname, view = REGISTRY_VIEW_NATIVE)
|
|
if session.commands.include?(Rex::Post::Meterpreter::Extensions::Stdapi::COMMAND_ID_STDAPI_REGISTRY_ENUM_VALUE_DIRECT)
|
|
meterpreter_registry_getvaldata(key, valname, view)
|
|
else
|
|
shell_registry_getvaldata(key, valname, view)
|
|
end
|
|
end
|
|
|
|
#
|
|
# Return the data and type of a given registry key and value
|
|
#
|
|
def registry_getvalinfo(key, valname, view = REGISTRY_VIEW_NATIVE)
|
|
if session.commands.include?(Rex::Post::Meterpreter::Extensions::Stdapi::COMMAND_ID_STDAPI_REGISTRY_OPEN_KEY)
|
|
meterpreter_registry_getvalinfo(key, valname, view)
|
|
else
|
|
shell_registry_getvalinfo(key, valname, view)
|
|
end
|
|
end
|
|
|
|
#
|
|
# Sets the data for a given value and type of data on the target registry
|
|
#
|
|
# returns true if successful
|
|
#
|
|
def registry_setvaldata(key, valname, data, type, view = REGISTRY_VIEW_NATIVE)
|
|
if session.commands.include?(Rex::Post::Meterpreter::Extensions::Stdapi::COMMAND_ID_STDAPI_REGISTRY_SET_VALUE_DIRECT)
|
|
meterpreter_registry_setvaldata(key, valname, data, type, view)
|
|
else
|
|
shell_registry_setvaldata(key, valname, data, type, view)
|
|
end
|
|
end
|
|
|
|
# Checks if a key exists on the target registry
|
|
#
|
|
# @param key [String] the full path of the key to check
|
|
# @return [Boolean] true if the key exists on the target registry, false otherwise
|
|
# (also in case of error)
|
|
def registry_key_exist?(key)
|
|
if session.commands.include?(Rex::Post::Meterpreter::Extensions::Stdapi::COMMAND_ID_STDAPI_REGISTRY_CHECK_KEY_EXISTS)
|
|
meterpreter_registry_key_exist?(key)
|
|
else
|
|
shell_registry_key_exist?(key)
|
|
end
|
|
end
|
|
|
|
protected
|
|
|
|
#
|
|
# Determines whether the session can use meterpreter registry methods
|
|
#
|
|
# @deprecated Use granular command ID checking session.commands instead
|
|
def session_has_registry_ext
|
|
begin
|
|
return !!(session.sys and session.sys.registry)
|
|
rescue NoMethodError
|
|
return false
|
|
end
|
|
end
|
|
|
|
|
|
##
|
|
# Generic registry manipulation methods based on reg.exe
|
|
##
|
|
|
|
def shell_registry_cmd(suffix, view = REGISTRY_VIEW_NATIVE)
|
|
cmd = "cmd.exe /c reg #{suffix}"
|
|
if view == REGISTRY_VIEW_32_BIT
|
|
cmd << " /reg:32"
|
|
elsif view == REGISTRY_VIEW_64_BIT
|
|
cmd << " /reg:64"
|
|
end
|
|
result = cmd_exec(cmd)
|
|
result
|
|
end
|
|
|
|
def shell_registry_cmd_result(suffix, view = REGISTRY_VIEW_NATIVE)
|
|
results = shell_registry_cmd(suffix, view)
|
|
results.include?('The operation completed successfully')
|
|
end
|
|
|
|
#
|
|
# Use reg.exe to load the hive file +file+ into +key+
|
|
#
|
|
def shell_registry_loadkey(key, file)
|
|
key = normalize_key(key)
|
|
shell_registry_cmd_result("load \"#{key}\" \"#{file}\"")
|
|
end
|
|
|
|
#
|
|
# Use reg.exe to unload the hive in +key+
|
|
#
|
|
def shell_registry_unloadkey(key)
|
|
key = normalize_key(key)
|
|
shell_registry_cmd_result("unload \"#{key}\"")
|
|
end
|
|
|
|
#
|
|
# Use reg.exe to create a new registry key
|
|
#
|
|
def shell_registry_createkey(key, view)
|
|
key = normalize_key(key)
|
|
# REG ADD KeyName [/v ValueName | /ve] [/t Type] [/s Separator] [/d Data] [/f]
|
|
shell_registry_cmd_result("add \"#{key}\" /f", view)
|
|
end
|
|
|
|
#
|
|
# Use reg.exe to delete +valname+ in +key+
|
|
#
|
|
def shell_registry_deleteval(key, valname, view)
|
|
key = normalize_key(key)
|
|
# REG DELETE KeyName [/v ValueName | /ve | /va] [/f]
|
|
shell_registry_cmd_result("delete \"#{key}\" /v \"#{valname}\" /f", view)
|
|
end
|
|
|
|
#
|
|
# Use reg.exe to delete +key+ and all its subkeys and values
|
|
#
|
|
def shell_registry_deletekey(key, view)
|
|
key = normalize_key(key)
|
|
# REG DELETE KeyName [/v ValueName | /ve | /va] [/f]
|
|
shell_registry_cmd_result("delete \"#{key}\" /f", view)
|
|
end
|
|
|
|
#
|
|
# Use reg.exe to enumerate all the subkeys in +key+
|
|
#
|
|
def shell_registry_enumkeys(key, view)
|
|
key = normalize_key(key)
|
|
subkeys = []
|
|
reg_data_types = 'REG_SZ|REG_MULTI_SZ|REG_DWORD_BIG_ENDIAN|REG_DWORD|REG_BINARY|'
|
|
reg_data_types << 'REG_DWORD_LITTLE_ENDIAN|REG_NONE|REG_EXPAND_SZ|REG_LINK|REG_FULL_RESOURCE_DESCRIPTOR'
|
|
|
|
bslashes = key.count('\\')
|
|
bslashes = bslashes - 1 if key.ends_with?('\\')
|
|
|
|
results = shell_registry_cmd("query \"#{key}\"", view)
|
|
unless results.to_s.upcase.starts_with?('ERROR:')
|
|
results.each_line do |line|
|
|
# now let's keep the ones that have a count = bslashes+1
|
|
# feels like there's a smarter way to do this but...
|
|
if (line.count('\\') == bslashes+1 && !line.ends_with?('\\'))
|
|
# then it's a first level subkey
|
|
subkeys << line.split('\\').last.chomp # take & chomp the last item only
|
|
end
|
|
end
|
|
end
|
|
subkeys
|
|
end
|
|
|
|
#
|
|
# Use reg.exe to enumerate all the values in +key+
|
|
#
|
|
def shell_registry_enumvals(key, view)
|
|
key = normalize_key(key)
|
|
values = []
|
|
reg_data_types = 'REG_SZ|REG_MULTI_SZ|REG_DWORD_BIG_ENDIAN|REG_DWORD|REG_BINARY|'
|
|
reg_data_types << 'REG_DWORD_LITTLE_ENDIAN|REG_NONE|REG_EXPAND_SZ|REG_LINK|REG_FULL_RESOURCE_DESCRIPTOR'
|
|
# REG QUERY KeyName [/v ValueName | /ve] [/s]
|
|
results = shell_registry_cmd("query \"#{key}\"", view)
|
|
unless results.to_s.upcase.starts_with?('ERROR:')
|
|
if values = results.scan(/^ +.*[#{reg_data_types}].*/)
|
|
# yanked the lines with legit REG value types like REG_SZ
|
|
# now let's parse out the names (first field basically)
|
|
values.collect! do |line|
|
|
t = line.split(' ')[0].chomp #chomp for good measure
|
|
# check if reg returned "<NO NAME>", which splits to "<NO", if so nil instead
|
|
t = nil if t == "<NO"
|
|
t
|
|
end
|
|
end
|
|
end
|
|
values
|
|
end
|
|
|
|
#
|
|
# Returns the data portion of the value +valname+
|
|
#
|
|
def shell_registry_getvaldata(key, valname, view)
|
|
valinfo = shell_registry_getvalinfo(key, valname, view)
|
|
return nil if valinfo.nil?
|
|
|
|
valinfo['Data']
|
|
end
|
|
|
|
#
|
|
# Enumerate the type and data stored in the registry value +valname+ in
|
|
# +key+
|
|
#
|
|
def shell_registry_getvalinfo(key, valname, view)
|
|
key = normalize_key(key)
|
|
value = {
|
|
'Data' => nil,
|
|
'Type' => nil
|
|
}
|
|
|
|
# REG QUERY KeyName [/v ValueName | /ve] [/s]
|
|
results = shell_registry_cmd("query \"#{key}\" /v \"#{valname}\"", view)
|
|
|
|
# pull out the interesting line (the one with the value name in it)
|
|
return nil unless match_arr = /^ +#{valname}.*/i.match(results)
|
|
|
|
# split with ' ' yielding [valname,REGvaltype,REGdata] and extract reg type
|
|
vtype = match_arr[0].split[1]
|
|
if %w[ REG_BINARY REG_DWORD REG_EXPAND_SZ REG_MULTI_SZ REG_NONE REG_QWORD REG_SZ ].include?(vtype)
|
|
value['Type'] = self.class.const_get(vtype)
|
|
end
|
|
# treat the remainder of the line after the reg type as the reg value
|
|
vdata = match_arr[0].strip.scan(/#{vtype}\s+(.+)/).flatten.first
|
|
case vtype
|
|
when 'REG_BINARY'
|
|
vdata = vdata.scan(/../).map { |x| x.hex.chr }.join
|
|
when 'REG_DWORD', 'REG_QWORD'
|
|
if vdata.start_with?('0x')
|
|
vdata = vdata[2..].to_i(16)
|
|
else
|
|
vdata = vdata.to_i
|
|
end
|
|
when 'REG_MULTI_SZ'
|
|
vdata = vdata.split('\0')
|
|
end
|
|
value['Data'] = vdata
|
|
|
|
value
|
|
end
|
|
|
|
#
|
|
# Use reg.exe to add a value +valname+ in the key +key+ with the specified
|
|
# +type+ and +data+
|
|
#
|
|
def shell_registry_setvaldata(key, valname, data, type, view)
|
|
key = normalize_key(key)
|
|
|
|
case type
|
|
when 'REG_BINARY'
|
|
data = data.each_byte.map { |b| b.to_s(16).rjust(2, '0') }.join
|
|
when 'REG_EXPAND_SZ'
|
|
if session.type == 'powershell'
|
|
data = data.gsub('%', '""%""')
|
|
elsif session.type == 'shell'
|
|
data = data.gsub('%', '"%"')
|
|
end
|
|
when 'REG_MULTI_SZ'
|
|
data = data.join('\0')
|
|
end
|
|
|
|
# REG ADD KeyName [/v ValueName | /ve] [/t Type] [/s Separator] [/d Data] [/f]
|
|
# /f to overwrite w/o prompt
|
|
shell_registry_cmd_result("add \"#{key}\" /v \"#{valname}\" /t \"#{type}\" /d \"#{data}\" /f", view)
|
|
end
|
|
|
|
# Checks if a key exists on the target registry using a shell session
|
|
#
|
|
# @param key [String] the full path of the key to check
|
|
# @return [Boolean] true if the key exists on the target registry, false otherwise,
|
|
# even if case of error (invalid arguments) or the session hasn't permission to
|
|
# access the key
|
|
def shell_registry_key_exist?(key)
|
|
begin
|
|
key = normalize_key(key)
|
|
rescue ArgumentError
|
|
return false
|
|
end
|
|
|
|
results = shell_registry_cmd("query \"#{key}\"")
|
|
return false if results.blank? || results =~ /ERROR: /i
|
|
|
|
true
|
|
end
|
|
|
|
##
|
|
# Meterpreter-specific registry manipulation methods
|
|
##
|
|
|
|
def meterpreter_registry_perms(perms, view = REGISTRY_VIEW_NATIVE)
|
|
if view == REGISTRY_VIEW_32_BIT
|
|
perms |= KEY_WOW64_32KEY
|
|
elsif view == REGISTRY_VIEW_64_BIT
|
|
perms |= KEY_WOW64_64KEY
|
|
end
|
|
perms
|
|
end
|
|
|
|
#
|
|
# Load a registry hive stored in +file+ into +key+
|
|
#
|
|
def meterpreter_registry_loadkey(key, file)
|
|
begin
|
|
client.sys.config.getprivs()
|
|
root_key, base_key = session.sys.registry.splitkey(key)
|
|
begin
|
|
loadres = session.sys.registry.load_key(root_key, base_key, file)
|
|
rescue Rex::Post::Meterpreter::RequestError => e
|
|
case e.to_s
|
|
when "stdapi_registry_load_key: Operation failed: 1314"
|
|
#print_error("You appear to be lacking the SeRestorePrivilege. Are you running with Admin privs?")
|
|
return false
|
|
when "stdapi_registry_load_key: Operation failed: The system cannot find the path specified."
|
|
#print_error("The path you provided to the Registry Hive does not Appear to be valid: #{file}")
|
|
return false
|
|
when "stdapi_registry_load_key: Operation failed: The process cannot access the file because it is being used by another process."
|
|
#print_error("The file you specified is currently locked by another process: #{file}")
|
|
return false
|
|
when /stdapi_registry_load_key: Operation failed:/
|
|
#print_error("An unknown error has occurred: #{loadres.to_s}")
|
|
return false
|
|
else
|
|
return true
|
|
end
|
|
end
|
|
|
|
rescue
|
|
return false
|
|
end
|
|
end
|
|
|
|
#
|
|
# Unload the hive file stored in +key+
|
|
#
|
|
def meterpreter_registry_unloadkey(key)
|
|
begin
|
|
client.sys.config.getprivs()
|
|
root_key, base_key = session.sys.registry.splitkey(key)
|
|
begin
|
|
unloadres= session.sys.registry.unload_key(root_key,base_key)
|
|
rescue Rex::Post::Meterpreter::RequestError => e
|
|
case e.to_s
|
|
when "stdapi_registry_unload_key: Operation failed: The parameter is incorrect."
|
|
#print_error("The KEY you provided does not appear to match a loaded Registry Hive: #{key}")
|
|
return false
|
|
when /stdapi_registry_unload_key: Operation failed:/
|
|
#print_error("An unknown error has occurred: #{unloadres.to_s}")
|
|
return false
|
|
else
|
|
return true
|
|
end
|
|
end
|
|
rescue
|
|
return false
|
|
end
|
|
end
|
|
|
|
#
|
|
# Create a new registry key
|
|
#
|
|
def meterpreter_registry_createkey(key, view)
|
|
begin
|
|
root_key, base_key = session.sys.registry.splitkey(key)
|
|
perms = meterpreter_registry_perms(KEY_WRITE, view)
|
|
open_key = session.sys.registry.create_key(root_key, base_key, perms)
|
|
open_key.close
|
|
return true
|
|
rescue Rex::Post::Meterpreter::RequestError => e
|
|
return nil
|
|
end
|
|
end
|
|
|
|
#
|
|
# Delete the registry value +valname+ store in +key+
|
|
#
|
|
def meterpreter_registry_deleteval(key, valname, view)
|
|
begin
|
|
root_key, base_key = session.sys.registry.splitkey(key)
|
|
perms = meterpreter_registry_perms(KEY_WRITE, view)
|
|
open_key = session.sys.registry.open_key(root_key, base_key, perms)
|
|
open_key.delete_value(valname)
|
|
open_key.close
|
|
return true
|
|
rescue Rex::Post::Meterpreter::RequestError => e
|
|
return nil
|
|
end
|
|
end
|
|
|
|
#
|
|
# Delete the registry key +key+
|
|
#
|
|
def meterpreter_registry_deletekey(key, view)
|
|
begin
|
|
root_key, base_key = session.sys.registry.splitkey(key)
|
|
perms = meterpreter_registry_perms(KEY_WRITE, view)
|
|
deleted = session.sys.registry.delete_key(root_key, base_key, perms)
|
|
return deleted
|
|
rescue Rex::Post::Meterpreter::RequestError => e
|
|
return nil
|
|
end
|
|
end
|
|
|
|
#
|
|
# Enumerate the subkeys in +key+
|
|
#
|
|
def meterpreter_registry_enumkeys(key, view)
|
|
begin
|
|
subkeys = []
|
|
root_key, base_key = session.sys.registry.splitkey(key)
|
|
perms = meterpreter_registry_perms(KEY_READ, view)
|
|
keys = session.sys.registry.enum_key_direct(root_key, base_key, perms)
|
|
keys.each { |subkey|
|
|
subkeys << subkey
|
|
}
|
|
return subkeys
|
|
rescue Rex::Post::Meterpreter::RequestError => e
|
|
return nil
|
|
end
|
|
end
|
|
|
|
#
|
|
# Enumerate the values in +key+
|
|
#
|
|
def meterpreter_registry_enumvals(key, view)
|
|
begin
|
|
values = []
|
|
vals = {}
|
|
root_key, base_key = session.sys.registry.splitkey(key)
|
|
perms = meterpreter_registry_perms(KEY_READ, view)
|
|
vals = session.sys.registry.enum_value_direct(root_key, base_key, perms)
|
|
vals.each { |val|
|
|
values << val.name
|
|
}
|
|
return values
|
|
rescue Rex::Post::Meterpreter::RequestError => e
|
|
return nil
|
|
end
|
|
end
|
|
|
|
#
|
|
# Get the data stored in the value +valname+
|
|
#
|
|
def meterpreter_registry_getvaldata(key, valname, view)
|
|
begin
|
|
value = nil
|
|
root_key, base_key = session.sys.registry.splitkey(key)
|
|
perms = meterpreter_registry_perms(KEY_READ, view)
|
|
v = session.sys.registry.query_value_direct(root_key, base_key, valname, perms)
|
|
value = v.data
|
|
rescue Rex::Post::Meterpreter::RequestError => e
|
|
return nil
|
|
end
|
|
return value
|
|
end
|
|
|
|
#
|
|
# Enumerate the type and data of the value +valname+
|
|
#
|
|
def meterpreter_registry_getvalinfo(key, valname, view)
|
|
value = {}
|
|
begin
|
|
root_key, base_key = session.sys.registry.splitkey(key)
|
|
perms = meterpreter_registry_perms(KEY_READ, view)
|
|
open_key = session.sys.registry.open_key(root_key, base_key, perms)
|
|
v = open_key.query_value(valname)
|
|
value["Data"] = v.data
|
|
value["Type"] = v.type
|
|
open_key.close
|
|
rescue Rex::Post::Meterpreter::RequestError => e
|
|
return nil
|
|
end
|
|
return value
|
|
end
|
|
|
|
#
|
|
# Add the value +valname+ to the key +key+ with the specified +type+ and +data+
|
|
#
|
|
def meterpreter_registry_setvaldata(key, valname, data, type, view)
|
|
begin
|
|
root_key, base_key = session.sys.registry.splitkey(key)
|
|
perms = meterpreter_registry_perms(KEY_WRITE, view)
|
|
session.sys.registry.set_value_direct(root_key, base_key,
|
|
valname, session.sys.registry.type2str(type), data, perms)
|
|
return true
|
|
rescue Rex::Post::Meterpreter::RequestError => e
|
|
return nil
|
|
end
|
|
end
|
|
|
|
# Checks if a key exists on the target registry using a meterpreter session
|
|
#
|
|
# @param key [String] the full path of the key to check
|
|
# @return [Boolean] true if the key exists on the target registry, false otherwise
|
|
# (also in case of error)
|
|
def meterpreter_registry_key_exist?(key)
|
|
begin
|
|
root_key, base_key = session.sys.registry.splitkey(key)
|
|
rescue ArgumentError
|
|
return false
|
|
end
|
|
|
|
begin
|
|
check = session.sys.registry.check_key_exists(root_key, base_key)
|
|
rescue Rex::Post::Meterpreter::RequestError, Rex::TimeoutError
|
|
return false
|
|
end
|
|
|
|
check
|
|
end
|
|
|
|
#
|
|
# Normalize the supplied full registry key string so the root key is sane. For
|
|
# instance, passing "HKLM\Software\Dog" will return 'HKEY_LOCAL_MACHINE\Software\Dog'
|
|
#
|
|
def normalize_key(key)
|
|
keys = split_key(key)
|
|
if (keys[0] =~ /HKLM|HKEY_LOCAL_MACHINE/)
|
|
keys[0] = 'HKEY_LOCAL_MACHINE'
|
|
elsif (keys[0] =~ /HKCU|HKEY_CURRENT_USER/)
|
|
keys[0] = 'HKEY_CURRENT_USER'
|
|
elsif (keys[0] =~ /HKU|HKEY_USERS/)
|
|
keys[0] = 'HKEY_USERS'
|
|
elsif (keys[0] =~ /HKCR|HKEY_CLASSES_ROOT/)
|
|
keys[0] = 'HKEY_CLASSES_ROOT'
|
|
elsif (keys[0] =~ /HKCC|HKEY_CURRENT_CONFIG/)
|
|
keys[0] = 'HKEY_CURRENT_CONFIG'
|
|
elsif (keys[0] =~ /HKPD|HKEY_PERFORMANCE_DATA/)
|
|
keys[0] = 'HKEY_PERFORMANCE_DATA'
|
|
elsif (keys[0] =~ /HKDD|HKEY_DYN_DATA/)
|
|
keys[0] = 'HKEY_DYN_DATA'
|
|
else
|
|
raise ArgumentError, "Cannot normalize unknown key: #{key}"
|
|
end
|
|
# print_status("Normalized #{key} to #{keys.join("\\")}")
|
|
return keys.compact.join("\\")
|
|
end
|
|
|
|
#
|
|
# Split the supplied full registry key string into its root key and base key. For
|
|
# instance, passing "HKLM\Software\Dog" will return [ 'HKEY_LOCAL_MACHINE',
|
|
# 'Software\Dog' ]
|
|
#
|
|
def split_key(str)
|
|
if (str =~ /^(.+?)\\(.*)$/)
|
|
[ $1, $2 ]
|
|
else
|
|
[ str, nil ]
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
end
|
|
end
|