2
2
require 'metasploit/framework/data_service/remote/http/data_service_auto_loader'
3
3
require 'net/http'
4
4
require 'net/https'
5
+ require 'uri'
5
6
6
7
#
7
8
# Parent data service for managing metasploit data in/on a separate process/machine over HTTP(s)
@@ -13,7 +14,7 @@ class RemoteHTTPDataService
13
14
include Metasploit ::Framework ::DataService
14
15
include DataServiceAutoLoader
15
16
16
- ONLINE_TEST_URL = "/api/1/msf /online"
17
+ ONLINE_TEST_URL = "/api/v1 /online"
17
18
EXEC_ASYNC = { :exec_async => true }
18
19
GET_REQUEST = 'GET'
19
20
POST_REQUEST = 'POST'
@@ -30,71 +31,94 @@ def initialize(endpoint, https_opts = {})
30
31
end
31
32
32
33
#
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
34
35
#
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 )
37
44
end
38
45
39
46
#
40
47
# POST data to the HTTP endpoint
41
48
#
49
+ # @param path - The URI path to send the request
42
50
# @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.
44
52
#
45
53
# @return A wrapped response (ResponseWrapper), see below.
46
54
#
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 )
49
57
end
50
58
51
59
#
52
60
# GET data from the HTTP endpoint
53
61
#
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.
56
65
#
57
66
# @return A wrapped response (ResponseWrapper), see below.
58
67
#
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 )
61
70
end
62
71
63
72
#
64
73
# Send DELETE request to delete the specified resource from the HTTP endpoint
65
74
#
66
- # @param path - The URI path to send the delete
75
+ # @param path - The URI path to send the request
67
76
# @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.
68
78
#
69
79
# @return A wrapped response (ResponseWrapper), see below.
70
80
#
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 )
73
83
end
74
84
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 )
76
96
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
+
78
101
client = @client_pool . pop ( )
79
102
case request_type
80
103
when GET_REQUEST
81
- request = Net ::HTTP ::Get . new ( path )
104
+ request = Net ::HTTP ::Get . new ( uri . request_uri )
82
105
when POST_REQUEST
83
- request = Net ::HTTP ::Post . new ( path )
106
+ request = Net ::HTTP ::Post . new ( uri . request_uri )
84
107
when DELETE_REQUEST
85
- request = Net ::HTTP ::Delete . new ( path )
108
+ request = Net ::HTTP ::Delete . new ( uri . request_uri )
86
109
else
87
110
raise Exception , 'A request_type must be specified'
88
111
end
89
112
built_request = build_request ( request , data_hash )
90
113
response = client . request ( built_request )
91
114
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 )
98
122
end
99
123
rescue EOFError => e
100
124
puts "ERROR: No data was returned from the server."
@@ -147,9 +171,7 @@ def name
147
171
end
148
172
149
173
def set_header ( key , value )
150
- if ( @headers . nil? )
151
- @headers = Hash . new ( )
152
- end
174
+ @headers = Hash . new ( ) if @headers . nil?
153
175
154
176
@headers [ key ] = value
155
177
end
@@ -199,24 +221,20 @@ def validate_endpoint(endpoint)
199
221
200
222
def append_workspace ( data_hash )
201
223
workspace = data_hash [ :workspace ]
202
- unless ( workspace )
203
- workspace = data_hash . delete ( :wspace )
204
- end
224
+ workspace = data_hash . delete ( :wspace ) unless workspace
205
225
206
- if ( workspace && ( workspace . is_a? ( OpenStruct ) || workspace . is_a? ( ::Mdm ::Workspace ) ) )
226
+ if workspace && ( workspace . is_a? ( OpenStruct ) || workspace . is_a? ( ::Mdm ::Workspace ) )
207
227
data_hash [ :workspace ] = workspace . name
208
228
end
209
229
210
- if ( workspace . nil? )
211
- data_hash [ :workspace ] = current_workspace_name
212
- end
230
+ data_hash [ :workspace ] = current_workspace_name if workspace . nil?
213
231
214
232
data_hash
215
233
end
216
234
217
235
def build_request ( request , data_hash )
218
236
request . content_type = 'application/json'
219
- if ( !data_hash . nil? && !data_hash . empty? )
237
+ if !data_hash . nil? && !data_hash . empty?
220
238
data_hash . each do |k , v |
221
239
if v . is_a? ( Msf ::Session )
222
240
puts "#{ Time . now } - DEBUG: Dropping Msf::Session object before converting to JSON."
@@ -230,7 +248,7 @@ def build_request(request, data_hash)
230
248
request . body = json_body
231
249
end
232
250
233
- if ( !@headers . nil? && !@headers . empty? )
251
+ if !@headers . nil? && !@headers . empty?
234
252
@headers . each do |key , value |
235
253
request [ key ] = value
236
254
end
0 commit comments