Skip to content

Commit 2ffd627

Browse files
committed
Merge branch 'goliath' into add_https
2 parents bfcb7f2 + 1c3b43b commit 2ffd627

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+166
-173
lines changed

lib/metasploit/framework/data_service/proxy/core.rb

Lines changed: 30 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
require 'singleton'
21
require 'open3'
32
require 'rex/ui'
43
require 'rex/logging'
5-
require 'msf/core/db_manager'
64
require 'metasploit/framework/data_service/remote/http/core'
75
require 'metasploit/framework/data_service/proxy/data_proxy_auto_loader'
86

@@ -14,11 +12,17 @@ module Metasploit
1412
module Framework
1513
module DataService
1614
class DataProxy
17-
include Singleton
1815
include DataProxyAutoLoader
1916

2017
attr_reader :usable
2118

19+
def initialize(opts = {})
20+
@data_services = {}
21+
@data_service_id = 0
22+
@usable = false
23+
setup(opts)
24+
end
25+
2226
#
2327
# Returns current error state
2428
#
@@ -47,34 +51,6 @@ def active
4751
return false
4852
end
4953

50-
#
51-
# Initializes the data service to be used - primarily on startup
52-
#
53-
def init(framework, opts)
54-
@mutex.synchronize {
55-
if (@initialized)
56-
return
57-
end
58-
59-
begin
60-
if (opts['DisableDatabase'])
61-
@error = 'disabled'
62-
return
63-
elsif (opts['DatabaseRemoteProcess'])
64-
run_remote_db_process(opts)
65-
else
66-
run_local_db_process(framework, opts)
67-
end
68-
@usable = true
69-
@initialized = true
70-
rescue Exception => e
71-
puts "Unable to initialize a dataservice #{e.message}"
72-
return
73-
end
74-
}
75-
76-
end
77-
7854
#
7955
# Registers a data service with the proxy and immediately
8056
# set as primary if online
@@ -130,6 +106,14 @@ def method_missing(method, *args, &block)
130106
end
131107
end
132108

109+
def respond_to?(method_name, include_private=false)
110+
unless @data_service.nil?
111+
return @data_service.respond_to?(method_name, include_private)
112+
end
113+
114+
false
115+
end
116+
133117
#
134118
# Attempt to shutdown the local db process if it exists
135119
#
@@ -144,10 +128,6 @@ def exit_called
144128
end
145129
end
146130

147-
#########
148-
protected
149-
#########
150-
151131
def get_data_service
152132
raise 'No registered data_service' unless @data_service
153133
return @data_service
@@ -157,12 +137,21 @@ def get_data_service
157137
private
158138
#######
159139

160-
def initialize
161-
@data_services = {}
162-
@data_service_id = 0
163-
@usable = false
164-
@initialized = false
165-
@mutex = Mutex.new()
140+
def setup(opts)
141+
begin
142+
db_manager = opts.delete(:db_manager)
143+
if !db_manager.nil?
144+
register_data_service(db_manager, true)
145+
@usable = true
146+
elsif opts['DatabaseRemoteProcess']
147+
run_remote_db_process(opts)
148+
@usable = true
149+
else
150+
@error = 'disabled'
151+
end
152+
rescue Exception => e
153+
puts "Unable to initialize a dataservice #{e.message}"
154+
end
166155
end
167156

168157
def validate(data_service)
@@ -182,15 +171,6 @@ def data_service_exist?(data_service)
182171
end
183172

184173

185-
def run_local_db_process(framework, opts)
186-
puts 'Initializing local db process'
187-
db_manager = Msf::DBManager.new(framework)
188-
if (db_manager.usable and not opts['SkipDatabaseInit'])
189-
register_data_service(db_manager, true)
190-
db_manager.init_db(opts)
191-
end
192-
end
193-
194174
def run_remote_db_process(opts)
195175
# started with no signal to prevent ctrl-c from taking out db
196176
db_script = File.join( Msf::Config.install_root, "msfdb -ns")

lib/metasploit/framework/data_service/remote/http/core.rb

Lines changed: 55 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
require 'metasploit/framework/data_service/remote/http/data_service_auto_loader'
33
require 'net/http'
44
require 'net/https'
5+
require 'uri'
56

67
#
78
# Parent data service for managing metasploit data in/on a separate process/machine over HTTP(s)
@@ -13,7 +14,7 @@ class RemoteHTTPDataService
1314
include Metasploit::Framework::DataService
1415
include DataServiceAutoLoader
1516

16-
ONLINE_TEST_URL = "/api/1/msf/online"
17+
ONLINE_TEST_URL = "/api/v1/online"
1718
EXEC_ASYNC = { :exec_async => true }
1819
GET_REQUEST = 'GET'
1920
POST_REQUEST = 'POST'
@@ -30,71 +31,94 @@ def initialize(endpoint, https_opts = {})
3031
end
3132

3233
#
33-
# POST data and don't wait for the endpoint to process the data before getting a response
34+
# POST data to the HTTP endpoint and don't wait for the endpoint to process the data before getting a response
3435
#
35-
def post_data_async(path, data_hash)
36-
make_request(POST_REQUEST, path, data_hash.merge(EXEC_ASYNC))
36+
# @param path - The URI path to send the request
37+
# @param data_hash - A hash representation of the object to be posted. Cannot be nil or empty.
38+
# @param query - A hash representation of the URI query data. Key-value pairs will be URL-encoded.
39+
#
40+
# @return A wrapped response (ResponseWrapper), see below.
41+
#
42+
def post_data_async(path, data_hash, query = nil)
43+
make_request(POST_REQUEST, path, data_hash.merge(EXEC_ASYNC), query)
3744
end
3845

3946
#
4047
# POST data to the HTTP endpoint
4148
#
49+
# @param path - The URI path to send the request
4250
# @param data_hash - A hash representation of the object to be posted. Cannot be nil or empty.
43-
# @param path - The URI path to post to
51+
# @param query - A hash representation of the URI query data. Key-value pairs will be URL-encoded.
4452
#
4553
# @return A wrapped response (ResponseWrapper), see below.
4654
#
47-
def post_data(path, data_hash)
48-
make_request(POST_REQUEST, path, data_hash)
55+
def post_data(path, data_hash, query = nil)
56+
make_request(POST_REQUEST, path, data_hash, query)
4957
end
5058

5159
#
5260
# GET data from the HTTP endpoint
5361
#
54-
# @param path - The URI path to post to
55-
# @param data_hash - A hash representation of the object to be posted. Can be nil or empty.
62+
# @param path - The URI path to send the request
63+
# @param data_hash - A hash representation of the object to be included. Can be nil or empty.
64+
# @param query - A hash representation of the URI query data. Key-value pairs will be URL-encoded.
5665
#
5766
# @return A wrapped response (ResponseWrapper), see below.
5867
#
59-
def get_data(path, data_hash = nil)
60-
make_request(GET_REQUEST, path, data_hash)
68+
def get_data(path, data_hash = nil, query = nil)
69+
make_request(GET_REQUEST, path, data_hash, query)
6170
end
6271

6372
#
6473
# Send DELETE request to delete the specified resource from the HTTP endpoint
6574
#
66-
# @param path - The URI path to send the delete
75+
# @param path - The URI path to send the request
6776
# @param data_hash - A hash representation of the object to be deleted. Cannot be nil or empty.
77+
# @param query - A hash representation of the URI query data. Key-value pairs will be URL-encoded.
6878
#
6979
# @return A wrapped response (ResponseWrapper), see below.
7080
#
71-
def delete_data(path, data_hash)
72-
make_request(DELETE_REQUEST, path, data_hash)
81+
def delete_data(path, data_hash, query = nil)
82+
make_request(DELETE_REQUEST, path, data_hash, query)
7383
end
7484

75-
def make_request(request_type, path, data_hash = nil)
85+
#
86+
# Make the specified request_type
87+
#
88+
# @param request_type - A string representation of the HTTP method
89+
# @param path - The URI path to send the request
90+
# @param data_hash - A hash representation of the object to be included in the request. Cannot be nil or empty.
91+
# @param query - A hash representation of the URI query data. Key-value pairs will be URL-encoded.
92+
#
93+
# @return A wrapped response (ResponseWrapper)
94+
#
95+
def make_request(request_type, path, data_hash = nil, query = nil)
7696
begin
77-
puts "#{Time.now} - HTTP #{request_type} request to #{path} with #{data_hash ? data_hash : "nil"}"
97+
query_str = (!query.nil? && !query.empty?) ? URI.encode_www_form(query) : nil
98+
uri = URI::HTTP::build({path: path, query: query_str})
99+
puts "#{Time.now} - HTTP #{request_type} request to #{uri.request_uri} with #{data_hash ? data_hash : "nil"}"
100+
78101
client = @client_pool.pop()
79102
case request_type
80103
when GET_REQUEST
81-
request = Net::HTTP::Get.new(path)
104+
request = Net::HTTP::Get.new(uri.request_uri)
82105
when POST_REQUEST
83-
request = Net::HTTP::Post.new(path)
106+
request = Net::HTTP::Post.new(uri.request_uri)
84107
when DELETE_REQUEST
85-
request = Net::HTTP::Delete.new(path)
108+
request = Net::HTTP::Delete.new(uri.request_uri)
86109
else
87110
raise Exception, 'A request_type must be specified'
88111
end
89112
built_request = build_request(request, data_hash)
90113
response = client.request(built_request)
91114

92-
if response.code == "200"
93-
# puts 'request sent successfully'
94-
return SuccessResponse.new(response)
95-
else
96-
puts "HTTP #{request_type} request: #{path} failed with code: #{response.code} message: #{response.body}"
97-
return FailedResponse.new(response)
115+
case response
116+
when Net::HTTPOK
117+
# puts 'request sent successfully'
118+
return SuccessResponse.new(response)
119+
else
120+
puts "HTTP #{request_type} request: #{uri.request_uri} failed with code: #{response.code} message: #{response.body}"
121+
return FailedResponse.new(response)
98122
end
99123
rescue EOFError => e
100124
puts "ERROR: No data was returned from the server."
@@ -147,9 +171,7 @@ def name
147171
end
148172

149173
def set_header(key, value)
150-
if (@headers.nil?)
151-
@headers = Hash.new()
152-
end
174+
@headers = Hash.new() if @headers.nil?
153175

154176
@headers[key] = value
155177
end
@@ -199,24 +221,20 @@ def validate_endpoint(endpoint)
199221

200222
def append_workspace(data_hash)
201223
workspace = data_hash[:workspace]
202-
unless (workspace)
203-
workspace = data_hash.delete(:wspace)
204-
end
224+
workspace = data_hash.delete(:wspace) unless workspace
205225

206-
if (workspace && (workspace.is_a?(OpenStruct) || workspace.is_a?(::Mdm::Workspace)))
226+
if workspace && (workspace.is_a?(OpenStruct) || workspace.is_a?(::Mdm::Workspace))
207227
data_hash[:workspace] = workspace.name
208228
end
209229

210-
if (workspace.nil?)
211-
data_hash[:workspace] = current_workspace_name
212-
end
230+
data_hash[:workspace] = current_workspace_name if workspace.nil?
213231

214232
data_hash
215233
end
216234

217235
def build_request(request, data_hash)
218236
request.content_type = 'application/json'
219-
if (!data_hash.nil? && !data_hash.empty?)
237+
if !data_hash.nil? && !data_hash.empty?
220238
data_hash.each do |k,v|
221239
if v.is_a?(Msf::Session)
222240
puts "#{Time.now} - DEBUG: Dropping Msf::Session object before converting to JSON."
@@ -230,7 +248,7 @@ def build_request(request, data_hash)
230248
request.body = json_body
231249
end
232250

233-
if (!@headers.nil? && !@headers.empty?)
251+
if !@headers.nil? && !@headers.empty?
234252
@headers.each do |key, value|
235253
request[key] = value
236254
end

lib/metasploit/framework/data_service/remote/http/remote_credential_data_service.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
module RemoteCredentialDataService
44
include ResponseDataHelper
55

6-
CREDENTIAL_API_PATH = '/api/1/msf/credential'
6+
CREDENTIAL_API_PATH = '/api/v1/credentials'
77
# "MDM_CLASS" is a little misleading since it is not in that repo but trying to keep naming consistent across DataServices
88
CREDENTIAL_MDM_CLASS = 'Metasploit::Credential::Core'
99

lib/metasploit/framework/data_service/remote/http/remote_event_data_service.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module RemoteEventDataService
2-
EVENT_API_PATH = '/api/1/msf/event'
2+
EVENT_API_PATH = '/api/v1/events'
33

44
def report_event(opts)
55
self.post_data_async(EVENT_API_PATH, opts)

lib/metasploit/framework/data_service/remote/http/remote_exploit_data_service.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module RemoteExploitDataService
2-
EXPLOIT_API_PATH = '/api/1/msf/exploit'
2+
EXPLOIT_API_PATH = '/api/v1/exploits'
33

44
def report_exploit_attempt(host, opts)
55
opts[:host] = host

lib/metasploit/framework/data_service/remote/http/remote_host_data_service.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
module RemoteHostDataService
44
include ResponseDataHelper
55

6-
HOST_API_PATH = '/api/1/msf/host'
6+
HOST_API_PATH = '/api/v1/hosts'
77
HOST_SEARCH_PATH = HOST_API_PATH + "/search"
88
HOST_MDM_CLASS = 'Mdm::Host'
99

lib/metasploit/framework/data_service/remote/http/remote_loot_data_service.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
module RemoteLootDataService
44
include ResponseDataHelper
55

6-
LOOT_API_PATH = '/api/1/msf/loot'
6+
LOOT_API_PATH = '/api/v1/loots'
77
LOOT_MDM_CLASS = 'Mdm::Loot'
88

99
def loot(opts = {})

lib/metasploit/framework/data_service/remote/http/remote_nmap_data_service.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
module RemoteNmapDataService
44
include ResponseDataHelper
55

6-
NMAP_PATH = '/api/1/msf/nmap'
6+
NMAP_PATH = '/api/v1/nmaps'
77

88
def import_nmap_xml_file(opts)
99
filename = opts[:filename]

lib/metasploit/framework/data_service/remote/http/remote_note_data_service.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
module RemoteNoteDataService
44
include ResponseDataHelper
55

6-
NOTE_API_PATH = '/api/1/msf/note'
6+
NOTE_API_PATH = '/api/v1/notes'
77

88
def report_note(opts)
99
self.post_data_async(NOTE_API_PATH, opts)

lib/metasploit/framework/data_service/remote/http/remote_service_data_service.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module RemoteServiceDataService
2-
SERVICE_API_PATH = '/api/1/msf/service'
2+
SERVICE_API_PATH = '/api/v1/services'
33

44
def report_service(opts)
55
self.post_data_async(SERVICE_API_PATH, opts)

0 commit comments

Comments
 (0)