diff --git a/data/meterpreter/ext_server_stdapi.py b/data/meterpreter/ext_server_stdapi.py index 1bd02b02f8..31811139a4 100644 --- a/data/meterpreter/ext_server_stdapi.py +++ b/data/meterpreter/ext_server_stdapi.py @@ -1334,10 +1334,12 @@ def stdapi_net_socket_tcp_shutdown(request, response): channel.shutdown(how) return ERROR_SUCCESS, response +def _wreg_close_key(hkey): + ctypes.windll.advapi32.RegCloseKey(hkey) + @meterpreter.register_function_windll def stdapi_registry_close_key(request, response): - hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value'] - result = ctypes.windll.advapi32.RegCloseKey(hkey) + _wreg_close_key(packet_get_tlv(request, TLV_TYPE_HKEY)['value']) return ERROR_SUCCESS, response @meterpreter.register_function_windll @@ -1372,11 +1374,9 @@ def stdapi_registry_delete_value(request, response): result = ctypes.windll.advapi32.RegDeleteValueA(root_key, ctypes.byref(value_name)) return result, response -@meterpreter.register_function_windll -def stdapi_registry_enum_key(request, response): +def _wreg_enum_key(request, response, hkey): ERROR_MORE_DATA = 0xea ERROR_NO_MORE_ITEMS = 0x0103 - hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value'] name = (ctypes.c_char * 4096)() index = 0 tries = 0 @@ -1399,10 +1399,22 @@ def stdapi_registry_enum_key(request, response): return result, response @meterpreter.register_function_windll -def stdapi_registry_enum_value(request, response): +def stdapi_registry_enum_key(request, response): + hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value'] + return _wreg_enum_key(request, response, hkey) + +@meterpreter.register_function_windll +def stdapi_registry_enum_key_direct(request, response): + err, hkey = _wreg_open_key(request) + if err != ERROR_SUCCESS: + return err, response + ret = _wreg_enum_key(request, response, hkey) + _wreg_close_key(hkey) + return ret + +def _wreg_enum_value(request, response, hkey): ERROR_MORE_DATA = 0xea ERROR_NO_MORE_ITEMS = 0x0103 - hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value'] name = (ctypes.c_char * 4096)() name_sz = ctypes.c_uint32() index = 0 @@ -1426,6 +1438,20 @@ def stdapi_registry_enum_value(request, response): index += 1 return result, response +@meterpreter.register_function_windll +def stdapi_registry_enum_value(request, response): + hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value'] + return _wreg_enum_value(request, response, hkey) + +@meterpreter.register_function_windll +def stdapi_registry_enum_value_direct(request, response): + err, hkey = _wreg_open_key(request) + if err != ERROR_SUCCESS: + return err, response + ret = _wreg_enum_value(request, response, hkey) + _wreg_close_key(hkey) + return ret + @meterpreter.register_function_windll def stdapi_registry_load_key(request, response): root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY) @@ -1434,16 +1460,22 @@ def stdapi_registry_load_key(request, response): result = ctypes.windll.advapi32.RegLoadKeyA(root_key, sub_key, file_name) return result, response -@meterpreter.register_function_windll -def stdapi_registry_open_key(request, response): +def _wreg_open_key(request): root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)['value'] base_key = packet_get_tlv(request, TLV_TYPE_BASE_KEY)['value'] base_key = ctypes.create_string_buffer(bytes(base_key, 'UTF-8')) permission = packet_get_tlv(request, TLV_TYPE_PERMISSION).get('value', winreg.KEY_ALL_ACCESS) handle_id = ctypes.c_void_p() if ctypes.windll.advapi32.RegOpenKeyExA(root_key, ctypes.byref(base_key), 0, permission, ctypes.byref(handle_id)) != ERROR_SUCCESS: - return error_result_windows(), response - response += tlv_pack(TLV_TYPE_HKEY, handle_id.value) + return error_result_windows(), 0 + return ERROR_SUCCESS, handle_id.value + +@meterpreter.register_function_windll +def stdapi_registry_open_key(request, response): + err, hkey = _wreg_open_key(request) + if err != ERROR_SUCCESS: + return err, response + response += tlv_pack(TLV_TYPE_HKEY, hkey) return ERROR_SUCCESS, response @meterpreter.register_function_windll @@ -1467,9 +1499,7 @@ def stdapi_registry_query_class(request, response): response += tlv_pack(TLV_TYPE_VALUE_DATA, ctypes.string_at(value_data)) return ERROR_SUCCESS, response -@meterpreter.register_function_windll -def stdapi_registry_query_value(request, response): - hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value'] +def _query_value(request, response, hkey): value_name = packet_get_tlv(request, TLV_TYPE_VALUE_NAME)['value'] value_name = ctypes.create_string_buffer(bytes(value_name, 'UTF-8')) value_type = ctypes.c_uint32() @@ -1496,8 +1526,20 @@ def stdapi_registry_query_value(request, response): return error_result_windows(), response @meterpreter.register_function_windll -def stdapi_registry_set_value(request, response): +def stdapi_registry_query_value(request, response): hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value'] + return _query_value(request, response, hkey) + +@meterpreter.register_function_windll +def stdapi_registry_query_value_direct(request, response): + err, hkey = _wreg_open_key(request) + if err != ERROR_SUCCESS: + return err, response + ret = _query_value(request, response, hkey) + _wreg_close_key(hkey) + return ret + +def _set_value(request, response, hkey): value_name = packet_get_tlv(request, TLV_TYPE_VALUE_NAME)['value'] value_name = ctypes.create_string_buffer(bytes(value_name, 'UTF-8')) value_type = packet_get_tlv(request, TLV_TYPE_VALUE_TYPE)['value'] @@ -1505,6 +1547,20 @@ def stdapi_registry_set_value(request, response): result = ctypes.windll.advapi32.RegSetValueExA(hkey, ctypes.byref(value_name), 0, value_type, value_data, len(value_data)) return result, response +@meterpreter.register_function_windll +def stdapi_registry_set_value(request, response): + hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value'] + return _set_value(request, response, hkey) + +@meterpreter.register_function_windll +def stdapi_registry_set_value_direct(request, response): + err, hkey = _wreg_open_key(request) + if err != ERROR_SUCCESS: + return err, response + ret = _set_value(request, response, hkey) + _wreg_close_key(hkey) + return ret + @meterpreter.register_function_windll def stdapi_registry_unload_key(request, response): root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)['value'] diff --git a/lib/msf/core/post/windows/registry.rb b/lib/msf/core/post/windows/registry.rb index 78f28aed55..d502eb26f4 100644 --- a/lib/msf/core/post/windows/registry.rb +++ b/lib/msf/core/post/windows/registry.rb @@ -439,12 +439,10 @@ protected subkeys = [] 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) - keys = open_key.enum_key + keys = session.sys.registry.enum_key_direct(root_key, base_key, perms) keys.each { |subkey| subkeys << subkey } - open_key.close return subkeys rescue Rex::Post::Meterpreter::RequestError => e return nil @@ -460,12 +458,10 @@ protected vals = {} 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) - vals = open_key.enum_value + vals = session.sys.registry.enum_value_direct(root_key, base_key, perms) vals.each { |val| values << val.name } - open_key.close return values rescue Rex::Post::Meterpreter::RequestError => e return nil @@ -480,10 +476,8 @@ protected value = nil 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) + v = session.sys.registry.query_value_direct(root_key, base_key, valname, perms) value = v.data - open_key.close rescue Rex::Post::Meterpreter::RequestError => e return nil end @@ -516,9 +510,8 @@ protected 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.set_value(valname, session.sys.registry.type2str(type), data) - open_key.close + 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 diff --git a/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb b/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb index 2a9583ee55..4a451c9fe4 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb @@ -89,7 +89,6 @@ class Registry request.add_tlv(TLV_TYPE_TARGET_HOST, target_host) request.add_tlv(TLV_TYPE_ROOT_KEY, root_key) - response = client.send_request(request) return Rex::Post::Meterpreter::Extensions::Stdapi::Sys::RegistrySubsystem::RemoteRegistryKey.new( @@ -166,6 +165,24 @@ class Registry return keys end + def Registry.enum_key_direct(root_key, base_key, perm = KEY_READ) + request = Packet.create_request('stdapi_registry_enum_key_direct') + keys = [] + + request.add_tlv(TLV_TYPE_ROOT_KEY, root_key) + request.add_tlv(TLV_TYPE_BASE_KEY, base_key) + request.add_tlv(TLV_TYPE_PERMISSION, perm) + + response = client.send_request(request) + + # Enumerate through all of the registry keys + response.each(TLV_TYPE_KEY_NAME) do |key_name| + keys << key_name.value + end + + keys + end + ## # # Registry value interaction @@ -195,10 +212,55 @@ class Registry return true end + def Registry.set_value_direct(root_key, base_key, name, type, data, perm = KEY_WRITE) + request = Packet.create_request('stdapi_registry_set_value_direct') + + request.add_tlv(TLV_TYPE_ROOT_KEY, root_key) + request.add_tlv(TLV_TYPE_BASE_KEY, base_key) + request.add_tlv(TLV_TYPE_PERMISSION, perm) + request.add_tlv(TLV_TYPE_VALUE_NAME, name) + request.add_tlv(TLV_TYPE_VALUE_TYPE, type) + + if type == REG_SZ + data += "\x00" + elsif type == REG_DWORD + data = [data.to_i].pack('V') + end + + request.add_tlv(TLV_TYPE_VALUE_DATA, data) + + response = client.send_request(request) + + true + end + # # Queries the registry value supplied in name and returns an # initialized RegistryValue instance if a match is found. # + def Registry.query_value_direct(root_key, base_key, name, perm = KEY_READ) + request = Packet.create_request('stdapi_registry_query_value_direct') + + request.add_tlv(TLV_TYPE_ROOT_KEY, root_key) + request.add_tlv(TLV_TYPE_BASE_KEY, base_key) + request.add_tlv(TLV_TYPE_PERMISSION, perm) + request.add_tlv(TLV_TYPE_VALUE_NAME, name) + + response = client.send_request(request) + + type = response.get_tlv(TLV_TYPE_VALUE_TYPE).value + data = response.get_tlv(TLV_TYPE_VALUE_DATA).value + + if type == REG_SZ + data = data[0..-2] + elsif type == REG_DWORD + data = data.unpack('N')[0] + end + + Rex::Post::Meterpreter::Extensions::Stdapi::Sys::RegistrySubsystem::RegistryValue.new( + client, 0, name, type, data) + end + def Registry.query_value(hkey, name) request = Packet.create_request('stdapi_registry_query_value') @@ -207,8 +269,8 @@ class Registry response = client.send_request(request) - data = response.get_tlv(TLV_TYPE_VALUE_DATA).value; - type = response.get_tlv(TLV_TYPE_VALUE_TYPE).value; + data = response.get_tlv(TLV_TYPE_VALUE_DATA).value + type = response.get_tlv(TLV_TYPE_VALUE_TYPE).value if (type == REG_SZ) data = data[0..-2] @@ -272,6 +334,24 @@ class Registry return values end + def Registry.enum_value_direct(root_key, base_key, perm = KEY_READ) + request = Packet.create_request('stdapi_registry_enum_value_direct') + values = [] + + request.add_tlv(TLV_TYPE_ROOT_KEY, root_key) + request.add_tlv(TLV_TYPE_BASE_KEY, base_key) + request.add_tlv(TLV_TYPE_PERMISSION, perm) + + response = client.send_request(request) + + response.each(TLV_TYPE_VALUE_NAME) do |value_name| + values << Rex::Post::Meterpreter::Extensions::Stdapi::Sys::RegistrySubsystem::RegistryValue.new( + client, 0, value_name.value) + end + + values + end + # # Return the key value associated with the supplied string. This is useful # for converting HKLM as a string into its actual integer representation.