diff --git a/lib/msf/core/rpc/v10/constants.rb b/lib/msf/core/rpc/v10/constants.rb index 9417fddf12ae0..5aed62f0ac24c 100644 --- a/lib/msf/core/rpc/v10/constants.rb +++ b/lib/msf/core/rpc/v10/constants.rb @@ -6,16 +6,31 @@ module RPC class Exception < RuntimeError - attr_accessor :code, :message + attr_accessor :code, :message, :http_msg # Initializes Exception. # # @param [Integer] code An error code. # @param [String] message An error message. # @return [void] - def initialize(code, message) + def initialize(code, message, http_msg = nil) self.code = code self.message = message + self.http_msg = http_msg + self.http_msg ||= case self.code + when 400 + 'Bad Request' + when 401 + 'Unauthorized' + when 403 + 'Forbidden' + when 404 + 'Not Found' + when 500 + 'Internal Server Error' + else + 'Unknown Error' + end end end diff --git a/lib/msf/core/rpc/v10/rpc_db.rb b/lib/msf/core/rpc/v10/rpc_db.rb index 7e0d92697e340..b7309d5adf9fb 100644 --- a/lib/msf/core/rpc/v10/rpc_db.rb +++ b/lib/msf/core/rpc/v10/rpc_db.rb @@ -371,6 +371,10 @@ def rpc_del_creds(xopts) # # @param [Hash] xopts Options: # @option xopts [String] :workspace Name of the workspace. + # @option xopts [String] :addresses Host addresses + # @option xopts [Boolean] :only_up If true, return hosts that are up. + # @option xopts [Integer] :limit Maximum number of hosts to return. + # @option xopts [Integer] :offset return the hosts starting at index `offset`. # @raise [Msf::RPC::ServerException] You might get one of these errors: # * 500 ActiveRecord::ConnectionNotEstablished. Try: rpc.call('console.create'). # * 500 Database not loaded. Try: rpc.call('console.create') @@ -432,7 +436,7 @@ def rpc_hosts(xopts) # @option xopts [Integer] :limit Limit. # @option xopts [Integer] :offset Offset. # @option xopts [String] :proto Protocol. - # @option xopts [String] :address Address. + # @option xopts [String] :address Host address. # @option xopts [String] :ports Port range. # @option xopts [String] :names Names (Use ',' as the separator). # @raise [Msf::RPC::ServerException] You might get one of these errors: @@ -494,6 +498,7 @@ def rpc_services( xopts) # @option xopts [String] :proto Protocol. # @option xopts [String] :address Address. # @option xopts [String] :ports Port range. + # @option xopts [String] :names Exploit that was used. # @raise [Msf::RPC::ServerException] You might get one of these errors: # * 500 ActiveRecord::ConnectionNotEstablished. Try: rpc.call('console.create'). # * 500 Database not loaded. Try: rpc.call('console.create') @@ -517,7 +522,7 @@ def rpc_vulns(xopts) conditions = {} conditions["hosts.address"] = opts[:address] if opts[:address] conditions[:name] = opts[:names].strip().split(",") if opts[:names] - conditions["services.port"] = Rex::Socket.portspec_to_portlist(opts[:ports]) if opts[:port] + conditions["services.port"] = Rex::Socket.portspec_to_portlist(opts[:ports]) if opts[:ports] conditions["services.proto"] = opts[:proto] if opts[:proto] ret = {} @@ -1113,7 +1118,6 @@ def rpc_report_note(xopts) # @param [Hash] xopts Filters for the search. See below: # @option xopts [String] :workspace Name of the workspace. # @option xopts [String] :address Host address. - # @option xopts [String] :names Names (separated by ','). # @option xopts [String] :ntype Note type. # @option xopts [String] :proto Protocol. # @option xopts [String] :ports Port change. @@ -1139,7 +1143,6 @@ def rpc_notes(xopts) conditions = {} conditions["hosts.address"] = opts[:address] if opts[:address] - conditions[:name] = opts[:names].strip().split(",") if opts[:names] conditions[:ntype] = opts[:ntype] if opts[:ntype] conditions["services.port"] = Rex::Socket.portspec_to_portlist(opts[:ports]) if opts[:ports] conditions["services.proto"] = opts[:proto] if opts[:proto] diff --git a/lib/msf/core/rpc/v10/rpc_module.rb b/lib/msf/core/rpc/v10/rpc_module.rb index 87a21bd36cf25..c11967b317bdf 100644 --- a/lib/msf/core/rpc/v10/rpc_module.rb +++ b/lib/msf/core/rpc/v10/rpc_module.rb @@ -221,7 +221,7 @@ def rpc_info(mtype, mname) res['license'] = m.license res['filepath'] = m.file_path res['arch'] = m.arch.map { |x| x.to_s } - res['platform'] = m.platform.platforms.map { |x| x.to_s } + res['platform'] = m.platform.platforms.map { |x| x.respond_to?(:realname) ? x.realname : x.to_s } res['authors'] = m.author.map { |a| a.to_s } res['privileged'] = m.privileged? res['check'] = m.has_check? @@ -279,16 +279,17 @@ def rpc_info(mtype, mname) res end - def module_short_info(m) - res = {} - res['type'] = m.type - res['name'] = m.name - res['fullname'] = m.fullname - res['rank'] = RankingName[m.rank].to_s - res['disclosuredate'] = m.disclosure_date.nil? ? "" : m.disclosure_date.strftime("%Y-%m-%d") - res - end - + # returns a list of module names that match the search string. + # + # @param match [string] the search string. + # @return [hash] a list of modules. it contains the following key: + # * 'type' [string] The module type (exploit, auxiliary, post, payload, etc.) + # * 'name' [string] The module name + # * 'fullname' [string] The full module path + # * 'rank' [string] The module rank (excellent, great, good, normal, etc.) + # * 'disclosuredate' [string] The module disclosure date (YYYY-MM-DD) + # @example here's how you would use this from the client: + # rpc.call('module.search', 'smb type:exploit') def rpc_search(match) matches = [] self.framework.search(match).each do |m| @@ -853,6 +854,17 @@ def _run_payload(mod, opts) end end + def module_short_info(m) + res = {} + res['type'] = m.type + res['name'] = m.name + res['fullname'] = m.fullname + res['rank'] = RankingName[m.rank].to_s + res['disclosuredate'] = m.disclosure_date.nil? ? "" : m.disclosure_date.strftime("%Y-%m-%d") + res + end + + end end diff --git a/lib/msf/core/rpc/v10/service.rb b/lib/msf/core/rpc/v10/service.rb index 81dfbbb990642..70653e927f68e 100644 --- a/lib/msf/core/rpc/v10/service.rb +++ b/lib/msf/core/rpc/v10/service.rb @@ -83,6 +83,12 @@ def on_request_uri(cli, req) elog('RPC Exception', error: e) res.body = process_exception(e).to_msgpack res.code = e.code + res.message = e.http_msg + rescue ::Exception => e + elog('Unknown Exception', error: e) + res.body = process_exception(e).to_msgpack + res.code = 500 + res.message = 'Internal Server Error' end cli.send_response(res) end @@ -145,9 +151,6 @@ def process(req) self.handlers[group].send(mname, *msg) end - rescue ::Exception => e - elog('RPC Exception', error: e) - process_exception(e) ensure Thread.current[:rpc_token] = nil end diff --git a/msfrpcd b/msfrpcd index af3111f539ea8..eaec0b9e73cb1 100755 --- a/msfrpcd +++ b/msfrpcd @@ -100,6 +100,15 @@ def start_rpc_service(opts, frameworkOpts, foreground) # Create an instance of the framework $framework = Msf::Simple::Framework.create(frameworkOpts) + if !$framework.db || !$framework.db.active + if $framework.db.error == "disabled" + $stderr.puts "Database support has been disabled" + else + error_msg = "#{$framework.db.error.class.is_a?(String) ? "#{$framework.db.error.class} " : nil}#{$framework.db.error}" + $stderr.puts "No database support: #{error_msg}" + end + end + # Run the plugin instance in the foreground. begin $framework.plugins.load("#{RPC_TYPE.downcase}rpc", opts).run