diff --git a/lib/metasploit/framework/data_service.rb b/lib/metasploit/framework/data_service.rb index 49b4b2065e..a475f0c81b 100644 --- a/lib/metasploit/framework/data_service.rb +++ b/lib/metasploit/framework/data_service.rb @@ -6,8 +6,10 @@ require 'metasploit/framework/data_service/stubs/note_data_service' require 'metasploit/framework/data_service/stubs/web_data_service' require 'metasploit/framework/data_service/stubs/service_data_service' require 'metasploit/framework/data_service/stubs/session_data_service' +require 'metasploit/framework/data_service/stubs/session_event_service' require 'metasploit/framework/data_service/stubs/exploit_data_service' require 'metasploit/framework/data_service/stubs/loot_data_service' +require 'metasploit/framework/data_service/stubs/msf_data_service' # # All data service implementations should include this module to ensure proper implementation @@ -23,8 +25,10 @@ module DataService include NoteDataService include ServiceDataService include SessionDataService + include SessionEventDataService include ExploitDataService include LootDataService + include MsfDataService def name raise 'DataService#name is not implemented'; @@ -34,6 +38,10 @@ module DataService raise 'DataService#active is not implemented'; end + def active=(value) + raise 'DataService#active= is not implemented'; + end + def is_local? raise 'DataService#is_local? is not implemented'; end diff --git a/lib/metasploit/framework/data_service/proxy/core.rb b/lib/metasploit/framework/data_service/proxy/core.rb index f59ac73d1d..d1953e9ed1 100644 --- a/lib/metasploit/framework/data_service/proxy/core.rb +++ b/lib/metasploit/framework/data_service/proxy/core.rb @@ -52,30 +52,36 @@ class DataProxy end # - # Registers a data service with the proxy and immediately - # set as primary if online + # Registers the specified data service with the proxy + # and immediately sets it as the primary if active # - def register_data_service(data_service, online=false) + def register_data_service(data_service) validate(data_service) data_service_id = @data_service_id += 1 @data_services[data_service_id] = data_service - set_data_service(data_service_id, online) + set_data_service(data_service_id) end # # Set the data service to be used # - def set_data_service(data_service_id, online=false) + def set_data_service(data_service_id) data_service = @data_services[data_service_id.to_i] if data_service.nil? raise "Data service with id: #{data_service_id} does not exist" end - if !online && !data_service.active - raise "Data service not online: #{data_service.name}, not setting as active" + if !data_service.is_local? && !data_service.active + raise "Data service #{data_service.name} is not online, and won't be set as active" end + prev_data_service = @current_data_service @current_data_service = data_service + # reset the previous data service's active flag if it is remote + # to ensure checks are performed the next time it is set + if !prev_data_service.nil? && !prev_data_service.is_local? + prev_data_service.active = false + end end # @@ -154,12 +160,12 @@ class DataProxy begin db_manager = opts.delete(:db_manager) if !db_manager.nil? - register_data_service(db_manager, true) + register_data_service(db_manager) @usable = true else @error = 'disabled' end - rescue Exception => e + rescue => e raise "Unable to initialize data service: #{e.message}" end end diff --git a/lib/metasploit/framework/data_service/proxy/data_proxy_auto_loader.rb b/lib/metasploit/framework/data_service/proxy/data_proxy_auto_loader.rb index ce0eda6211..5088ad0f22 100644 --- a/lib/metasploit/framework/data_service/proxy/data_proxy_auto_loader.rb +++ b/lib/metasploit/framework/data_service/proxy/data_proxy_auto_loader.rb @@ -19,6 +19,7 @@ module DataProxyAutoLoader autoload :DbExportDataProxy, 'metasploit/framework/data_service/proxy/db_export_data_proxy' autoload :DbImportDataProxy, 'metasploit/framework/data_service/proxy/db_import_data_proxy' autoload :VulnAttemptDataProxy, 'metasploit/framework/data_service/proxy/vuln_attempt_data_proxy' + autoload :MsfDataProxy, 'metasploit/framework/data_service/proxy/msf_data_proxy' include ServiceDataProxy include HostDataProxy @@ -36,4 +37,5 @@ module DataProxyAutoLoader include DbExportDataProxy include DbImportDataProxy include VulnAttemptDataProxy + include MsfDataProxy end \ No newline at end of file diff --git a/lib/metasploit/framework/data_service/proxy/msf_data_proxy.rb b/lib/metasploit/framework/data_service/proxy/msf_data_proxy.rb new file mode 100644 index 0000000000..ab4605e936 --- /dev/null +++ b/lib/metasploit/framework/data_service/proxy/msf_data_proxy.rb @@ -0,0 +1,10 @@ +module MsfDataProxy + def get_msf_version + begin + data_service = self.get_data_service + data_service.get_msf_version + rescue => e + self.log_error(e, "Problem retrieving Metasploit version") + end + end +end \ No newline at end of file diff --git a/lib/metasploit/framework/data_service/remote/http/core.rb b/lib/metasploit/framework/data_service/remote/http/core.rb index 69a7f1fa5c..d0ad3a71db 100644 --- a/lib/metasploit/framework/data_service/remote/http/core.rb +++ b/lib/metasploit/framework/data_service/remote/http/core.rb @@ -25,6 +25,7 @@ class RemoteHTTPDataService # @param [String] endpoint A valid http or https URL. Cannot be nil # def initialize(endpoint, framework, https_opts = {}) + @active = false validate_endpoint(endpoint) @endpoint = URI.parse(endpoint) @https_opts = https_opts @@ -40,6 +41,26 @@ class RemoteHTTPDataService end + def name + "remote_data_service: (#{@endpoint})" + end + + def active + # checks if data service is online when @active is falsey and makes the assignment + # this is to prevent repetitive calls to check if data service is online + # logic should be enhanced to considering data service connectivity + # and future data service implementations + @active ||= is_online? + end + + def active=(value) + @active = value + end + + def is_local? + false + end + def error 'none' end @@ -152,7 +173,7 @@ class RemoteHTTPDataService rescue EOFError => e elog "No data was returned from the data service for request type/path : #{request_type}/#{path}, message: #{e.message}" return FailedResponse.new('') - rescue Exception => e + rescue => e elog "Problem with HTTP request for type/path: #{request_type}/#{path} message: #{e.message}" return FailedResponse.new('') ensure @@ -160,21 +181,6 @@ class RemoteHTTPDataService end end - # - # TODO: fix this - # - def active - return true - end - - def name - "remote_data_service: (#{@endpoint})" - end - - def is_local? - false - end - def set_header(key, value) @headers = Hash.new() if @headers.nil? @@ -224,6 +230,19 @@ class RemoteHTTPDataService raise 'Endpoint cannot be nil' if endpoint.nil? end + # + # Checks if the data service is online by making a request + # for the Metasploit version number from the remote endpoint + # + def is_online? + response = self.get_msf_version + if response && !response[:metasploit_version].empty? + return true + end + + return false + end + def build_request(request, data_hash) request.content_type = 'application/json' if !data_hash.nil? && !data_hash.empty? diff --git a/lib/metasploit/framework/data_service/remote/http/data_service_auto_loader.rb b/lib/metasploit/framework/data_service/remote/http/data_service_auto_loader.rb index c4bc34d9af..6086f99955 100644 --- a/lib/metasploit/framework/data_service/remote/http/data_service_auto_loader.rb +++ b/lib/metasploit/framework/data_service/remote/http/data_service_auto_loader.rb @@ -17,6 +17,7 @@ module DataServiceAutoLoader autoload :RemoteNmapDataService, 'metasploit/framework/data_service/remote/http/remote_nmap_data_service' autoload :RemoteDbExportDataService, 'metasploit/framework/data_service/remote/http/remote_db_export_data_service' autoload :RemoteVulnAttemptDataService, 'metasploit/framework/data_service/remote/http/remote_vuln_attempt_data_service' + autoload :RemoteMsfDataService, 'metasploit/framework/data_service/remote/http/remote_msf_data_service' include RemoteHostDataService include RemoteEventDataService @@ -33,4 +34,5 @@ module DataServiceAutoLoader include RemoteNmapDataService include RemoteDbExportDataService include RemoteVulnAttemptDataService + include RemoteMsfDataService end \ No newline at end of file diff --git a/lib/metasploit/framework/data_service/remote/http/remote_msf_data_service.rb b/lib/metasploit/framework/data_service/remote/http/remote_msf_data_service.rb new file mode 100644 index 0000000000..103267f209 --- /dev/null +++ b/lib/metasploit/framework/data_service/remote/http/remote_msf_data_service.rb @@ -0,0 +1,12 @@ +require 'metasploit/framework/data_service/remote/http/response_data_helper' + +module RemoteMsfDataService + include ResponseDataHelper + + MSF_API_PATH = '/api/v1/msf' + MSF_VERSION_API_PATH = "#{MSF_API_PATH}/version" + + def get_msf_version + json_to_hash(self.get_data(MSF_VERSION_API_PATH, nil, nil)) + end +end \ No newline at end of file diff --git a/lib/metasploit/framework/data_service/stubs/msf_data_service.rb b/lib/metasploit/framework/data_service/stubs/msf_data_service.rb new file mode 100644 index 0000000000..c898981fbf --- /dev/null +++ b/lib/metasploit/framework/data_service/stubs/msf_data_service.rb @@ -0,0 +1,5 @@ +module MsfDataService + def get_msf_version + raise 'MsfDataService#get_msf_version is not implemented' + end +end \ No newline at end of file diff --git a/lib/msf/core/db_manager/http/servlet/msf_servlet.rb b/lib/msf/core/db_manager/http/servlet/msf_servlet.rb new file mode 100644 index 0000000000..5fc6ba307a --- /dev/null +++ b/lib/msf/core/db_manager/http/servlet/msf_servlet.rb @@ -0,0 +1,25 @@ +module MsfServlet + + def self.api_path + '/api/v1/msf' + end + + def self.api_version_path + "#{MsfServlet.api_path}/version" + end + + def self.registered(app) + app.get MsfServlet.api_version_path, &get_msf_version + end + + ####### + private + ####### + + def self.get_msf_version + lambda { + set_json_response({metasploit_version: Metasploit::Framework::VERSION}) + } + end + +end \ No newline at end of file diff --git a/lib/msf/core/db_manager/http/servlet/online_test_servlet.rb b/lib/msf/core/db_manager/http/servlet/online_test_servlet.rb deleted file mode 100644 index 1462f81ede..0000000000 --- a/lib/msf/core/db_manager/http/servlet/online_test_servlet.rb +++ /dev/null @@ -1,21 +0,0 @@ -module OnlineTestServlet - - def self.api_path - '/api/v1/online' - end - - def self.registered(app) - app.get OnlineTestServlet.api_path, &get_active - end - - ####### - private - ####### - - def self.get_active - lambda { - set_empty_response() - } - end - -end \ No newline at end of file diff --git a/lib/msf/core/db_manager/http/sinatra_app.rb b/lib/msf/core/db_manager/http/sinatra_app.rb index 5f7d67b7d8..7a4e575ff3 100644 --- a/lib/msf/core/db_manager/http/sinatra_app.rb +++ b/lib/msf/core/db_manager/http/sinatra_app.rb @@ -5,7 +5,7 @@ require 'msf/core/db_manager/http/servlet/note_servlet' require 'msf/core/db_manager/http/servlet/vuln_servlet' require 'msf/core/db_manager/http/servlet/event_servlet' require 'msf/core/db_manager/http/servlet/web_servlet' -require 'msf/core/db_manager/http/servlet/online_test_servlet' +require 'msf/core/db_manager/http/servlet/msf_servlet' require 'msf/core/db_manager/http/servlet/workspace_servlet' require 'msf/core/db_manager/http/servlet/service_servlet' require 'msf/core/db_manager/http/servlet/session_servlet' @@ -26,7 +26,7 @@ class SinatraApp < Sinatra::Base register VulnServlet register EventServlet register WebServlet - register OnlineTestServlet + register MsfServlet register NoteServlet register WorkspaceServlet register ServiceServlet diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index 943cdcb768..00784a40e8 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -1994,7 +1994,7 @@ class Db framework.db.register_data_service(remote_data_service) print_line "Registered data service: #{remote_data_service.name}" framework.db.workspace = framework.db.default_workspace - rescue Exception => e + rescue => e print_error "There was a problem registering the remote data service: #{e.message}" end end @@ -2004,7 +2004,7 @@ class Db data_service = framework.db.set_data_service(service_id) framework.db.workspace = framework.db.default_workspace data_service - rescue Exception => e + rescue => e print_error "Unable to set data service: #{e.message}" end end