diff --git a/lib/metasploit/framework/data_service/proxy/core.rb b/lib/metasploit/framework/data_service/proxy/core.rb index 3379552275..44f69d6324 100644 --- a/lib/metasploit/framework/data_service/proxy/core.rb +++ b/lib/metasploit/framework/data_service/proxy/core.rb @@ -1,8 +1,6 @@ -require 'singleton' require 'open3' require 'rex/ui' require 'rex/logging' -require 'msf/core/db_manager' require 'metasploit/framework/data_service/remote/http/core' require 'metasploit/framework/data_service/proxy/data_proxy_auto_loader' @@ -14,11 +12,17 @@ module Metasploit module Framework module DataService class DataProxy - include Singleton include DataProxyAutoLoader attr_reader :usable + def initialize(opts = {}) + @data_services = {} + @data_service_id = 0 + @usable = false + setup(opts) + end + # # Returns current error state # @@ -47,34 +51,6 @@ class DataProxy return false end - # - # Initializes the data service to be used - primarily on startup - # - def init(framework, opts) - @mutex.synchronize { - if (@initialized) - return - end - - begin - if (opts['DisableDatabase']) - @error = 'disabled' - return - elsif (opts['DatabaseRemoteProcess']) - run_remote_db_process(opts) - else - run_local_db_process(framework, opts) - end - @usable = true - @initialized = true - rescue Exception => e - puts "Unable to initialize a dataservice #{e.message}" - return - end - } - - end - # # Registers a data service with the proxy and immediately # set as primary if online @@ -130,6 +106,14 @@ class DataProxy end end + def respond_to?(method_name, include_private=false) + unless @data_service.nil? + return @data_service.respond_to?(method_name, include_private) + end + + false + end + # # Attempt to shutdown the local db process if it exists # @@ -144,10 +128,6 @@ class DataProxy end end - ######### - protected - ######### - def get_data_service raise 'No registered data_service' unless @data_service return @data_service @@ -157,12 +137,21 @@ class DataProxy private ####### - def initialize - @data_services = {} - @data_service_id = 0 - @usable = false - @initialized = false - @mutex = Mutex.new() + def setup(opts) + begin + db_manager = opts.delete(:db_manager) + if !db_manager.nil? + register_data_service(db_manager, true) + @usable = true + elsif opts['DatabaseRemoteProcess'] + run_remote_db_process(opts) + @usable = true + else + @error = 'disabled' + end + rescue Exception => e + puts "Unable to initialize a dataservice #{e.message}" + end end def validate(data_service) @@ -182,15 +171,6 @@ class DataProxy end - def run_local_db_process(framework, opts) - puts 'Initializing local db process' - db_manager = Msf::DBManager.new(framework) - if (db_manager.usable and not opts['SkipDatabaseInit']) - register_data_service(db_manager, true) - db_manager.init_db(opts) - end - end - def run_remote_db_process(opts) # started with no signal to prevent ctrl-c from taking out db db_script = File.join( Msf::Config.install_root, "msfdb -ns") diff --git a/lib/metasploit/framework/data_service/remote/http/core.rb b/lib/metasploit/framework/data_service/remote/http/core.rb index 4b959829cb..ac8321e04b 100644 --- a/lib/metasploit/framework/data_service/remote/http/core.rb +++ b/lib/metasploit/framework/data_service/remote/http/core.rb @@ -2,6 +2,7 @@ require 'metasploit/framework/data_service' require 'metasploit/framework/data_service/remote/http/data_service_auto_loader' require 'net/http' require 'net/https' +require 'uri' # # Parent data service for managing metasploit data in/on a separate process/machine over HTTP(s) @@ -13,7 +14,7 @@ class RemoteHTTPDataService include Metasploit::Framework::DataService include DataServiceAutoLoader - ONLINE_TEST_URL = "/api/1/msf/online" + ONLINE_TEST_URL = "/api/v1/online" EXEC_ASYNC = { :exec_async => true } GET_REQUEST = 'GET' POST_REQUEST = 'POST' @@ -30,71 +31,94 @@ class RemoteHTTPDataService end # - # POST data and don't wait for the endpoint to process the data before getting a response + # POST data to the HTTP endpoint and don't wait for the endpoint to process the data before getting a response # - def post_data_async(path, data_hash) - make_request(POST_REQUEST, path, data_hash.merge(EXEC_ASYNC)) + # @param path - The URI path to send the request + # @param data_hash - A hash representation of the object to be posted. Cannot be nil or empty. + # @param query - A hash representation of the URI query data. Key-value pairs will be URL-encoded. + # + # @return A wrapped response (ResponseWrapper), see below. + # + def post_data_async(path, data_hash, query = nil) + make_request(POST_REQUEST, path, data_hash.merge(EXEC_ASYNC), query) end # # POST data to the HTTP endpoint # + # @param path - The URI path to send the request # @param data_hash - A hash representation of the object to be posted. Cannot be nil or empty. - # @param path - The URI path to post to + # @param query - A hash representation of the URI query data. Key-value pairs will be URL-encoded. # # @return A wrapped response (ResponseWrapper), see below. # - def post_data(path, data_hash) - make_request(POST_REQUEST, path, data_hash) + def post_data(path, data_hash, query = nil) + make_request(POST_REQUEST, path, data_hash, query) end # # GET data from the HTTP endpoint # - # @param path - The URI path to post to - # @param data_hash - A hash representation of the object to be posted. Can be nil or empty. + # @param path - The URI path to send the request + # @param data_hash - A hash representation of the object to be included. Can be nil or empty. + # @param query - A hash representation of the URI query data. Key-value pairs will be URL-encoded. # # @return A wrapped response (ResponseWrapper), see below. # - def get_data(path, data_hash = nil) - make_request(GET_REQUEST, path, data_hash) + def get_data(path, data_hash = nil, query = nil) + make_request(GET_REQUEST, path, data_hash, query) end # # Send DELETE request to delete the specified resource from the HTTP endpoint # - # @param path - The URI path to send the delete + # @param path - The URI path to send the request # @param data_hash - A hash representation of the object to be deleted. Cannot be nil or empty. + # @param query - A hash representation of the URI query data. Key-value pairs will be URL-encoded. # # @return A wrapped response (ResponseWrapper), see below. # - def delete_data(path, data_hash) - make_request(DELETE_REQUEST, path, data_hash) + def delete_data(path, data_hash, query = nil) + make_request(DELETE_REQUEST, path, data_hash, query) end - def make_request(request_type, path, data_hash = nil) + # + # Make the specified request_type + # + # @param request_type - A string representation of the HTTP method + # @param path - The URI path to send the request + # @param data_hash - A hash representation of the object to be included in the request. Cannot be nil or empty. + # @param query - A hash representation of the URI query data. Key-value pairs will be URL-encoded. + # + # @return A wrapped response (ResponseWrapper) + # + def make_request(request_type, path, data_hash = nil, query = nil) begin - puts "#{Time.now} - HTTP #{request_type} request to #{path} with #{data_hash ? data_hash : "nil"}" + query_str = (!query.nil? && !query.empty?) ? URI.encode_www_form(query) : nil + uri = URI::HTTP::build({path: path, query: query_str}) + puts "#{Time.now} - HTTP #{request_type} request to #{uri.request_uri} with #{data_hash ? data_hash : "nil"}" + client = @client_pool.pop() case request_type when GET_REQUEST - request = Net::HTTP::Get.new(path) + request = Net::HTTP::Get.new(uri.request_uri) when POST_REQUEST - request = Net::HTTP::Post.new(path) + request = Net::HTTP::Post.new(uri.request_uri) when DELETE_REQUEST - request = Net::HTTP::Delete.new(path) + request = Net::HTTP::Delete.new(uri.request_uri) else raise Exception, 'A request_type must be specified' end built_request = build_request(request, data_hash) response = client.request(built_request) - if response.code == "200" - # puts 'request sent successfully' - return SuccessResponse.new(response) - else - puts "HTTP #{request_type} request: #{path} failed with code: #{response.code} message: #{response.body}" - return FailedResponse.new(response) + case response + when Net::HTTPOK + # puts 'request sent successfully' + return SuccessResponse.new(response) + else + puts "HTTP #{request_type} request: #{uri.request_uri} failed with code: #{response.code} message: #{response.body}" + return FailedResponse.new(response) end rescue EOFError => e puts "ERROR: No data was returned from the server." @@ -147,9 +171,7 @@ class RemoteHTTPDataService end def set_header(key, value) - if (@headers.nil?) - @headers = Hash.new() - end + @headers = Hash.new() if @headers.nil? @headers[key] = value end @@ -199,24 +221,20 @@ class RemoteHTTPDataService def append_workspace(data_hash) workspace = data_hash[:workspace] - unless (workspace) - workspace = data_hash.delete(:wspace) - end + workspace = data_hash.delete(:wspace) unless workspace - if (workspace && (workspace.is_a?(OpenStruct) || workspace.is_a?(::Mdm::Workspace))) + if workspace && (workspace.is_a?(OpenStruct) || workspace.is_a?(::Mdm::Workspace)) data_hash[:workspace] = workspace.name end - if (workspace.nil?) - data_hash[:workspace] = current_workspace_name - end + data_hash[:workspace] = current_workspace_name if workspace.nil? data_hash end def build_request(request, data_hash) request.content_type = 'application/json' - if (!data_hash.nil? && !data_hash.empty?) + if !data_hash.nil? && !data_hash.empty? data_hash.each do |k,v| if v.is_a?(Msf::Session) puts "#{Time.now} - DEBUG: Dropping Msf::Session object before converting to JSON." @@ -230,7 +248,7 @@ class RemoteHTTPDataService request.body = json_body end - if (!@headers.nil? && !@headers.empty?) + if !@headers.nil? && !@headers.empty? @headers.each do |key, value| request[key] = value end diff --git a/lib/metasploit/framework/data_service/remote/http/remote_credential_data_service.rb b/lib/metasploit/framework/data_service/remote/http/remote_credential_data_service.rb index 84f2c98236..c133490f5c 100644 --- a/lib/metasploit/framework/data_service/remote/http/remote_credential_data_service.rb +++ b/lib/metasploit/framework/data_service/remote/http/remote_credential_data_service.rb @@ -3,7 +3,7 @@ require 'metasploit/framework/data_service/remote/http/response_data_helper' module RemoteCredentialDataService include ResponseDataHelper - CREDENTIAL_API_PATH = '/api/1/msf/credential' + CREDENTIAL_API_PATH = '/api/v1/credentials' # "MDM_CLASS" is a little misleading since it is not in that repo but trying to keep naming consistent across DataServices CREDENTIAL_MDM_CLASS = 'Metasploit::Credential::Core' diff --git a/lib/metasploit/framework/data_service/remote/http/remote_event_data_service.rb b/lib/metasploit/framework/data_service/remote/http/remote_event_data_service.rb index 45106c7580..26b878420f 100644 --- a/lib/metasploit/framework/data_service/remote/http/remote_event_data_service.rb +++ b/lib/metasploit/framework/data_service/remote/http/remote_event_data_service.rb @@ -1,5 +1,5 @@ module RemoteEventDataService - EVENT_API_PATH = '/api/1/msf/event' + EVENT_API_PATH = '/api/v1/events' def report_event(opts) self.post_data_async(EVENT_API_PATH, opts) diff --git a/lib/metasploit/framework/data_service/remote/http/remote_exploit_data_service.rb b/lib/metasploit/framework/data_service/remote/http/remote_exploit_data_service.rb index 5bf0bab7ed..0b8f3862a8 100644 --- a/lib/metasploit/framework/data_service/remote/http/remote_exploit_data_service.rb +++ b/lib/metasploit/framework/data_service/remote/http/remote_exploit_data_service.rb @@ -1,5 +1,5 @@ module RemoteExploitDataService - EXPLOIT_API_PATH = '/api/1/msf/exploit' + EXPLOIT_API_PATH = '/api/v1/exploits' def report_exploit_attempt(host, opts) opts[:host] = host diff --git a/lib/metasploit/framework/data_service/remote/http/remote_host_data_service.rb b/lib/metasploit/framework/data_service/remote/http/remote_host_data_service.rb index fd11f79287..47eb5b404d 100644 --- a/lib/metasploit/framework/data_service/remote/http/remote_host_data_service.rb +++ b/lib/metasploit/framework/data_service/remote/http/remote_host_data_service.rb @@ -3,7 +3,7 @@ require 'metasploit/framework/data_service/remote/http/response_data_helper' module RemoteHostDataService include ResponseDataHelper - HOST_API_PATH = '/api/1/msf/host' + HOST_API_PATH = '/api/v1/hosts' HOST_SEARCH_PATH = HOST_API_PATH + "/search" HOST_MDM_CLASS = 'Mdm::Host' diff --git a/lib/metasploit/framework/data_service/remote/http/remote_loot_data_service.rb b/lib/metasploit/framework/data_service/remote/http/remote_loot_data_service.rb index c2f578d918..8fbcce713e 100644 --- a/lib/metasploit/framework/data_service/remote/http/remote_loot_data_service.rb +++ b/lib/metasploit/framework/data_service/remote/http/remote_loot_data_service.rb @@ -3,7 +3,7 @@ require 'metasploit/framework/data_service/remote/http/response_data_helper' module RemoteLootDataService include ResponseDataHelper - LOOT_API_PATH = '/api/1/msf/loot' + LOOT_API_PATH = '/api/v1/loots' LOOT_MDM_CLASS = 'Mdm::Loot' def loot(opts = {}) diff --git a/lib/metasploit/framework/data_service/remote/http/remote_nmap_data_service.rb b/lib/metasploit/framework/data_service/remote/http/remote_nmap_data_service.rb index 5b043cdd91..fc0d728ff2 100644 --- a/lib/metasploit/framework/data_service/remote/http/remote_nmap_data_service.rb +++ b/lib/metasploit/framework/data_service/remote/http/remote_nmap_data_service.rb @@ -3,7 +3,7 @@ require 'metasploit/framework/data_service/remote/http/response_data_helper' module RemoteNmapDataService include ResponseDataHelper - NMAP_PATH = '/api/1/msf/nmap' + NMAP_PATH = '/api/v1/nmaps' def import_nmap_xml_file(opts) filename = opts[:filename] diff --git a/lib/metasploit/framework/data_service/remote/http/remote_note_data_service.rb b/lib/metasploit/framework/data_service/remote/http/remote_note_data_service.rb index f0f50f059d..58e8cbceed 100644 --- a/lib/metasploit/framework/data_service/remote/http/remote_note_data_service.rb +++ b/lib/metasploit/framework/data_service/remote/http/remote_note_data_service.rb @@ -3,7 +3,7 @@ require 'metasploit/framework/data_service/remote/http/response_data_helper' module RemoteNoteDataService include ResponseDataHelper - NOTE_API_PATH = '/api/1/msf/note' + NOTE_API_PATH = '/api/v1/notes' def report_note(opts) self.post_data_async(NOTE_API_PATH, opts) diff --git a/lib/metasploit/framework/data_service/remote/http/remote_service_data_service.rb b/lib/metasploit/framework/data_service/remote/http/remote_service_data_service.rb index 4f40fbd937..9c4889af8e 100644 --- a/lib/metasploit/framework/data_service/remote/http/remote_service_data_service.rb +++ b/lib/metasploit/framework/data_service/remote/http/remote_service_data_service.rb @@ -1,5 +1,5 @@ module RemoteServiceDataService - SERVICE_API_PATH = '/api/1/msf/service' + SERVICE_API_PATH = '/api/v1/services' def report_service(opts) self.post_data_async(SERVICE_API_PATH, opts) diff --git a/lib/metasploit/framework/data_service/remote/http/remote_session_data_service.rb b/lib/metasploit/framework/data_service/remote/http/remote_session_data_service.rb index 3c3faa5029..109a60e82e 100644 --- a/lib/metasploit/framework/data_service/remote/http/remote_session_data_service.rb +++ b/lib/metasploit/framework/data_service/remote/http/remote_session_data_service.rb @@ -1,6 +1,6 @@ module RemoteSessionDataService - SESSION_API_PATH = '/api/1/msf/session' + SESSION_API_PATH = '/api/v1/sessions' SESSION_MDM_CLASS = 'Mdm::Session' def report_session(opts) diff --git a/lib/metasploit/framework/data_service/remote/http/remote_session_event_data_service.rb b/lib/metasploit/framework/data_service/remote/http/remote_session_event_data_service.rb index ca21e4fe3a..5f7f9e730f 100644 --- a/lib/metasploit/framework/data_service/remote/http/remote_session_event_data_service.rb +++ b/lib/metasploit/framework/data_service/remote/http/remote_session_event_data_service.rb @@ -3,7 +3,7 @@ require 'metasploit/framework/data_service/remote/http/response_data_helper' module RemoteSessionEventDataService include ResponseDataHelper - SESSION_EVENT_API_PATH = '/api/1/msf/session_event' + SESSION_EVENT_API_PATH = '/api/v1/session-events' SESSION_EVENT_MDM_CLASS = 'Mdm::SessionEvent' def session_events(opts = {}) diff --git a/lib/metasploit/framework/data_service/remote/http/remote_vuln_data_service.rb b/lib/metasploit/framework/data_service/remote/http/remote_vuln_data_service.rb index ccd3f30743..41606f7b8f 100644 --- a/lib/metasploit/framework/data_service/remote/http/remote_vuln_data_service.rb +++ b/lib/metasploit/framework/data_service/remote/http/remote_vuln_data_service.rb @@ -1,6 +1,6 @@ module RemoteVulnDataService - VULN_API_PATH = '/api/1/msf/vuln' + VULN_API_PATH = '/api/v1/vulns' def report_vuln(opts) self.post_data_async(VULN_API_PATH, opts) end diff --git a/lib/metasploit/framework/data_service/remote/http/remote_web_data_service.rb b/lib/metasploit/framework/data_service/remote/http/remote_web_data_service.rb index 4c3c29704d..896881aad3 100644 --- a/lib/metasploit/framework/data_service/remote/http/remote_web_data_service.rb +++ b/lib/metasploit/framework/data_service/remote/http/remote_web_data_service.rb @@ -3,7 +3,7 @@ require 'metasploit/framework/data_service/remote/http/response_data_helper' module RemoteWebDataService include ResponseDataHelper - WEB_API_PATH = '/api/1/msf/web' + WEB_API_PATH = '/api/v1/webs' def report_web_site(opts) self.post_data_async(WEB_API_PATH, opts) diff --git a/lib/metasploit/framework/data_service/remote/http/remote_workspace_data_service.rb b/lib/metasploit/framework/data_service/remote/http/remote_workspace_data_service.rb index 557286023c..e3ca39afb0 100644 --- a/lib/metasploit/framework/data_service/remote/http/remote_workspace_data_service.rb +++ b/lib/metasploit/framework/data_service/remote/http/remote_workspace_data_service.rb @@ -3,8 +3,9 @@ require 'metasploit/framework/data_service/remote/http/response_data_helper' module RemoteWorkspaceDataService include ResponseDataHelper - WORKSPACE_COUNTS_API_PATH = '/api/1/msf/workspace/counts' - WORKSPACE_API_PATH = '/api/1/msf/workspace' + # TODO: should counts be a flag in query data for the workspaces resource? + WORKSPACE_COUNTS_API_PATH = '/api/v1/workspaces/counts' + WORKSPACE_API_PATH = '/api/v1/workspaces' WORKSPACE_MDM_CLASS = 'Mdm::Workspace' DEFAULT_WORKSPACE_NAME = 'default' @@ -38,7 +39,7 @@ module RemoteWorkspaceDataService end def workspace_associations_counts() - json_to_mdm_object(self.get_data(WORKSPACE_API_PATH, []), WORKSPACE_MDM_CLASS, []) + json_to_mdm_object(self.get_data(WORKSPACE_COUNTS_API_PATH, []), WORKSPACE_MDM_CLASS, []) end ######### diff --git a/lib/msf/core/db_manager/connection.rb b/lib/msf/core/db_manager/connection.rb index 5f47998b50..70e7889c73 100644 --- a/lib/msf/core/db_manager/connection.rb +++ b/lib/msf/core/db_manager/connection.rb @@ -18,7 +18,7 @@ module Msf::DBManager::Connection migrate # Set the default workspace - framework.db.workspace = framework.db.default_workspace + self.workspace = self.default_workspace rescue ::Exception => exception self.error = exception elog("DB.connect threw an exception: #{exception}") diff --git a/lib/msf/core/db_manager/host.rb b/lib/msf/core/db_manager/host.rb index 8789d7cbe2..9cdeb41b7e 100644 --- a/lib/msf/core/db_manager/host.rb +++ b/lib/msf/core/db_manager/host.rb @@ -56,7 +56,7 @@ module Msf::DBManager::Host # Exactly like report_host but waits for the database to create a host and returns it. def find_or_create_host(opts) - host = get_host(opts) + host = get_host(opts.clone) return host unless host.nil? report_host(opts) diff --git a/lib/msf/core/db_manager/http/servlet/credential_servlet.rb b/lib/msf/core/db_manager/http/servlet/credential_servlet.rb index ea426adcd5..c80c5f593d 100644 --- a/lib/msf/core/db_manager/http/servlet/credential_servlet.rb +++ b/lib/msf/core/db_manager/http/servlet/credential_servlet.rb @@ -1,7 +1,7 @@ module CredentialServlet def self.api_path - '/api/1/msf/credential' + '/api/v1/credentials' end def self.registered(app) diff --git a/lib/msf/core/db_manager/http/servlet/event_servlet.rb b/lib/msf/core/db_manager/http/servlet/event_servlet.rb index 05a2c9df8f..8cc3882e8a 100644 --- a/lib/msf/core/db_manager/http/servlet/event_servlet.rb +++ b/lib/msf/core/db_manager/http/servlet/event_servlet.rb @@ -1,7 +1,7 @@ module EventServlet def self.api_path - '/api/1/msf/event' + '/api/v1/events' end def self.registered(app) diff --git a/lib/msf/core/db_manager/http/servlet/exploit_servlet.rb b/lib/msf/core/db_manager/http/servlet/exploit_servlet.rb index 8f23ea274b..f5f7a31748 100644 --- a/lib/msf/core/db_manager/http/servlet/exploit_servlet.rb +++ b/lib/msf/core/db_manager/http/servlet/exploit_servlet.rb @@ -1,7 +1,7 @@ module ExploitServlet def self.api_path - '/api/1/msf/exploit' + '/api/v1/exploits' end def self.registered(app) diff --git a/lib/msf/core/db_manager/http/servlet/host_servlet.rb b/lib/msf/core/db_manager/http/servlet/host_servlet.rb index 6945b27350..843a7ab069 100644 --- a/lib/msf/core/db_manager/http/servlet/host_servlet.rb +++ b/lib/msf/core/db_manager/http/servlet/host_servlet.rb @@ -1,7 +1,7 @@ module HostServlet def self.api_path - '/api/1/msf/host' + '/api/v1/hosts' end def self.registered(app) diff --git a/lib/msf/core/db_manager/http/servlet/loot_servlet.rb b/lib/msf/core/db_manager/http/servlet/loot_servlet.rb index f2f8a23b17..b29b4ae04a 100644 --- a/lib/msf/core/db_manager/http/servlet/loot_servlet.rb +++ b/lib/msf/core/db_manager/http/servlet/loot_servlet.rb @@ -1,7 +1,7 @@ module LootServlet def self.api_path - '/api/1/msf/loot' + '/api/v1/loots' end def self.registered(app) diff --git a/lib/msf/core/db_manager/http/servlet/nmap_servlet.rb b/lib/msf/core/db_manager/http/servlet/nmap_servlet.rb index 1a2858b235..761b0ec30a 100644 --- a/lib/msf/core/db_manager/http/servlet/nmap_servlet.rb +++ b/lib/msf/core/db_manager/http/servlet/nmap_servlet.rb @@ -1,7 +1,7 @@ module NmapServlet def self.api_path - '/api/1/msf/nmap' + '/api/v1/nmaps' end def self.registered(app) diff --git a/lib/msf/core/db_manager/http/servlet/note_servlet.rb b/lib/msf/core/db_manager/http/servlet/note_servlet.rb index c3c8812d82..21c581ab7d 100644 --- a/lib/msf/core/db_manager/http/servlet/note_servlet.rb +++ b/lib/msf/core/db_manager/http/servlet/note_servlet.rb @@ -1,7 +1,7 @@ module NoteServlet def self.api_path - '/api/1/msf/note' + '/api/v1/notes' end def self.registered(app) 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 index 551f3c9bd9..1462f81ede 100644 --- a/lib/msf/core/db_manager/http/servlet/online_test_servlet.rb +++ b/lib/msf/core/db_manager/http/servlet/online_test_servlet.rb @@ -1,7 +1,7 @@ module OnlineTestServlet def self.api_path - '/api/1/msf/online' + '/api/v1/online' end def self.registered(app) diff --git a/lib/msf/core/db_manager/http/servlet/service_servlet.rb b/lib/msf/core/db_manager/http/servlet/service_servlet.rb index bbd3be53bb..569a118fc3 100644 --- a/lib/msf/core/db_manager/http/servlet/service_servlet.rb +++ b/lib/msf/core/db_manager/http/servlet/service_servlet.rb @@ -1,7 +1,7 @@ module ServiceServlet def self.api_path - '/api/1/msf/service' + '/api/v1/services' end def self.registered(app) diff --git a/lib/msf/core/db_manager/http/servlet/session_event_servlet.rb b/lib/msf/core/db_manager/http/servlet/session_event_servlet.rb index a21e59fdf4..9fc269a55c 100644 --- a/lib/msf/core/db_manager/http/servlet/session_event_servlet.rb +++ b/lib/msf/core/db_manager/http/servlet/session_event_servlet.rb @@ -1,7 +1,7 @@ module SessionEventServlet def self.api_path - '/api/1/msf/session_event' + '/api/v1/session-events' end def self.registered(app) diff --git a/lib/msf/core/db_manager/http/servlet/session_servlet.rb b/lib/msf/core/db_manager/http/servlet/session_servlet.rb index e56c579a2d..b7ffa30d80 100644 --- a/lib/msf/core/db_manager/http/servlet/session_servlet.rb +++ b/lib/msf/core/db_manager/http/servlet/session_servlet.rb @@ -1,6 +1,6 @@ module SessionServlet def self.api_path - '/api/1/msf/session' + '/api/v1/sessions' end def self.registered(app) diff --git a/lib/msf/core/db_manager/http/servlet/vuln_servlet.rb b/lib/msf/core/db_manager/http/servlet/vuln_servlet.rb index bd2ca157d8..1414e13c96 100644 --- a/lib/msf/core/db_manager/http/servlet/vuln_servlet.rb +++ b/lib/msf/core/db_manager/http/servlet/vuln_servlet.rb @@ -1,7 +1,7 @@ module VulnServlet def self.api_path - '/api/1/msf/vuln' + '/api/v1/vulns' end def self.registered(app) diff --git a/lib/msf/core/db_manager/http/servlet/web_servlet.rb b/lib/msf/core/db_manager/http/servlet/web_servlet.rb index 8e0fa1cdfa..45c294f45d 100644 --- a/lib/msf/core/db_manager/http/servlet/web_servlet.rb +++ b/lib/msf/core/db_manager/http/servlet/web_servlet.rb @@ -1,7 +1,7 @@ module WebServlet def self.api_path - '/api/1/msf/web' + '/api/v1/webs' end def self.registered(app) diff --git a/lib/msf/core/db_manager/http/servlet/workspace_servlet.rb b/lib/msf/core/db_manager/http/servlet/workspace_servlet.rb index b2a650d3ef..f1b1a41554 100644 --- a/lib/msf/core/db_manager/http/servlet/workspace_servlet.rb +++ b/lib/msf/core/db_manager/http/servlet/workspace_servlet.rb @@ -1,7 +1,7 @@ module WorkspaceServlet def self.api_path - '/api/1/msf/workspace' + '/api/v1/workspaces' end def self.registered(app) diff --git a/lib/msf/core/db_manager/workspace.rb b/lib/msf/core/db_manager/workspace.rb index b808e9869d..e1f45d0fd2 100644 --- a/lib/msf/core/db_manager/workspace.rb +++ b/lib/msf/core/db_manager/workspace.rb @@ -58,20 +58,23 @@ module Msf::DBManager::Workspace end def delete_all_workspaces() - delete_workspaces(workspaces.map(&:name)) + return delete_workspaces(workspaces.map(&:name)) end def delete_workspaces(names) + status_msg = [] + error_msg = [] + switched = false # Delete workspaces names.each do |name| workspace = framework.db.find_workspace(name) if workspace.nil? - print_error("Workspace not found: #{name}") + error << "Workspace not found: #{name}" elsif workspace.default? workspace.destroy workspace = framework.db.add_workspace(name) - print_status("Deleted and recreated the default workspace") + status_msg << 'Deleted and recreated the default workspace' else # switch to the default workspace if we're about to delete the current one if framework.db.workspace.name == workspace.name @@ -80,10 +83,11 @@ module Msf::DBManager::Workspace end # now destroy the named workspace workspace.destroy - print_status("Deleted workspace: #{name}") + status_msg << "Deleted workspace: #{name}" end end - print_status("Switched workspace: #{framework.db.workspace.name}") if switched + (status_msg << "Switched workspace: #{framework.db.workspace.name}") if switched + return status_msg, error_msg end # diff --git a/lib/msf/core/framework.rb b/lib/msf/core/framework.rb index 0bf08276fb..693862e329 100644 --- a/lib/msf/core/framework.rb +++ b/lib/msf/core/framework.rb @@ -199,7 +199,7 @@ class Framework # @return [Metasploit::Framework::DataService::DataProxy] def db synchronize { - @db ||= Metasploit::Framework::DataService::DataProxy.instance + @db ||= get_db } end @@ -268,6 +268,19 @@ protected attr_writer :db # :nodoc: attr_writer :uuid_db # :nodoc: attr_writer :browser_profiles # :nodoc: + + private + + def get_db + if !options['DatabaseRemoteProcess'] && !options['DisableDatabase'] + db_manager = Msf::DBManager.new(self) + db_manager.init_db(options) + options[:db_manager] = db_manager + end + + Metasploit::Framework::DataService::DataProxy.new(options) + end + end class FrameworkEventSubscriber diff --git a/lib/msf/core/modules/metadata/store.rb b/lib/msf/core/modules/metadata/store.rb index 3a10a7c8c0..d2a720e0af 100644 --- a/lib/msf/core/modules/metadata/store.rb +++ b/lib/msf/core/modules/metadata/store.rb @@ -104,7 +104,7 @@ module Msf::Modules::Metadata::Store def get_user_store store_dir = ::File.join(Msf::Config.config_directory, "store") - FileUtils.mkdir(store_dir) if !::File.exist?(store_dir) + FileUtils.makedirs(store_dir) if !::File.exist?(store_dir) return ::File.join(store_dir, UserMetaDataFile) end diff --git a/lib/msf/ui/console/command_dispatcher/creds.rb b/lib/msf/ui/console/command_dispatcher/creds.rb index c21e46209d..b5abdb830f 100644 --- a/lib/msf/ui/console/command_dispatcher/creds.rb +++ b/lib/msf/ui/console/command_dispatcher/creds.rb @@ -393,7 +393,6 @@ class Creds } tbl = Rex::Text::Table.new(tbl_opts) - opts = {} opts[:wspace] = framework.db.workspace query = framework.db.creds(opts) diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index 1aa2a19811..5b56d5b7c3 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -89,13 +89,11 @@ module Msf end def cmd_set_data_service(service_id) - data_proxy = Metasploit::Framework::DataService::DataProxy.instance - data_proxy.set_data_service(service_id) + framework.db.set_data_service(service_id) end def cmd_list_data_services() - data_service_manager = Metasploit::Framework::DataService::DataProxy.instance - data_service_manager.print_data_services + framework.db.print_data_services end def cmd_add_data_service(*args) @@ -127,8 +125,7 @@ module Msf endpoint = "#{protocol}://#{host}:#{port}" remote_data_service = Metasploit::Framework::DataService::RemoteHTTPDataService.new(endpoint, https_opts) - data_service_manager = Metasploit::Framework::DataService::DataProxy.instance - data_service_manager.register_data_service(remote_data_service) + framework.db.register_data_service(remote_data_service) end def cmd_add_data_service_help @@ -157,8 +154,7 @@ module Msf end puts 'Reporting test host to data service' - data_service = Metasploit::Framework::DataService::DataProxy.instance - data_service.report_host host + framework.db.report_host host end def cmd_test_data_service_loot(*args) @@ -181,8 +177,7 @@ module Msf end puts 'Reporting test loot to data service' - data_service = Metasploit::Framework::DataService::DataProxy.instance - data_service.report_loot loot + framework.db.report_loot loot end def cmd_perf_test_data_service_loot(*args) @@ -226,11 +221,10 @@ module Msf end puts 'Reporting test loot to data service' - data_service = Metasploit::Framework::DataService::DataProxy.instance start_time = Time.now puts "#{start_time} - Staring loot perf test" loots.each do |loot| - data_service.report_loot loot + framework.db.report_loot loot end end_time = Time.now puts "#{end_time} - Ending loot perf test. Duration was #{end_time - start_time}" @@ -284,9 +278,11 @@ module Msf end framework.db.workspace = workspace elsif deleting and names - framework.db.delete_workspaces(names) + status_msg, error_msg = framework.db.delete_workspaces(names) + print_msgs(status_msg, error_msg) elsif delete_all - framework.db.delete_all_workspaces() + status_msg, error_msg = framework.db.delete_all_workspaces() + print_msgs(status_msg, error_msg) elsif renaming if names.length != 2 print_error("Wrong number of arguments to rename") @@ -2021,6 +2017,18 @@ module Msf end end + private + + def print_msgs(status_msg, error_msg) + status_msg.each do |s| + print_status(s) + end + + error_msg.each do |e| + print_error(e) + end + end + end end end end end diff --git a/lib/msf/ui/console/driver.rb b/lib/msf/ui/console/driver.rb index 829551cf1b..72e10a2b3c 100644 --- a/lib/msf/ui/console/driver.rb +++ b/lib/msf/ui/console/driver.rb @@ -122,7 +122,6 @@ class Driver < Msf::Ui::Driver enstack_dispatcher(dispatcher) end - framework.db.init(framework, opts) if (framework.db.active) require 'msf/ui/console/command_dispatcher/db' enstack_dispatcher(CommandDispatcher::Db) diff --git a/spec/lib/msf/core/auxiliary/cisco_spec.rb b/spec/lib/msf/core/auxiliary/cisco_spec.rb index f9adb0a9d2..c481318da4 100644 --- a/spec/lib/msf/core/auxiliary/cisco_spec.rb +++ b/spec/lib/msf/core/auxiliary/cisco_spec.rb @@ -77,7 +77,7 @@ RSpec.describe Msf::Auxiliary::Cisco do context '#cisco_ios_config_eater' do before(:example) do - expect(aux_cisco).to receive(:myworkspace).and_return(workspace) + expect(aux_cisco).to receive(:myworkspace).at_least(:once).and_return(workspace) end it 'deals with udp ports' do diff --git a/spec/support/shared/contexts/msf/db_manager.rb b/spec/support/shared/contexts/msf/db_manager.rb index 482c939dcd..f6c94dd73c 100644 --- a/spec/support/shared/contexts/msf/db_manager.rb +++ b/spec/support/shared/contexts/msf/db_manager.rb @@ -6,12 +6,12 @@ RSpec.shared_context 'Msf::DBManager' do end let(:db_manager) do - framework.db + framework.db.get_data_service end before(:example) do # already connected due to use_transactional_fixtures, but need some of the side-effects of #connect - framework.db.workspace = framework.db.default_workspace + db_manager.workspace = db_manager.default_workspace allow(db_manager).to receive(:active).and_return(active) end end diff --git a/spec/support/shared/examples/msf/db_manager/host.rb b/spec/support/shared/examples/msf/db_manager/host.rb index 43abeca732..d92e0b4b0c 100644 --- a/spec/support/shared/examples/msf/db_manager/host.rb +++ b/spec/support/shared/examples/msf/db_manager/host.rb @@ -5,7 +5,6 @@ RSpec.shared_examples_for 'Msf::DBManager::Host' do it { is_expected.to respond_to :get_host } it { is_expected.to respond_to :has_host? } it { is_expected.to respond_to :hosts } - it { is_expected.to respond_to :normalize_host } it { is_expected.to respond_to :report_host } it { is_expected.to respond_to :update_host_via_sysinfo } end \ No newline at end of file diff --git a/spec/support/shared/examples/msf/db_manager/session.rb b/spec/support/shared/examples/msf/db_manager/session.rb index 80c67cf116..934cbc3777 100644 --- a/spec/support/shared/examples/msf/db_manager/session.rb +++ b/spec/support/shared/examples/msf/db_manager/session.rb @@ -172,20 +172,6 @@ RSpec.shared_examples_for 'Msf::DBManager::Session' do end context 'with workspace from either :workspace or session' do - it 'should pass normalized host from session as :host to #find_or_create_host' do - normalized_host = double('Normalized Host') - expect(db_manager).to receive(:normalize_host).with(session).and_return(normalized_host) - # stub report_vuln so its use of find_or_create_host and Msf::Util::Host.normalize_host doesn't interfere. - expect(db_manager).to receive(:report_vuln) - - expect(db_manager).to receive(:find_or_create_host).with( - hash_including( - :host => normalized_host - ) - ).and_return(host) - - report_session - end context 'with session responds to arch' do let(:arch) do @@ -515,20 +501,6 @@ RSpec.shared_examples_for 'Msf::DBManager::Session' do end context 'with workspace from either :workspace or session' do - it 'should pass normalized host from session as :host to #find_or_create_host' do - normalized_host = double('Normalized Host') - allow(db_manager).to receive(:normalize_host).with(session).and_return(normalized_host) - # stub report_vuln so its use of find_or_create_host and Msf::Util::Host.normalize_host doesn't interfere. - allow(db_manager).to receive(:report_vuln) - - expect(db_manager).to receive(:find_or_create_host).with( - hash_including( - :host => normalized_host - ) - ).and_return(host) - - report_session - end context 'with session responds to arch' do let(:arch) do