1
+ # frozen_string_literal: true
1
2
# -*- coding: binary -*-
2
3
4
+ #
5
+ # Rex
6
+ #
7
+
3
8
require 'rex/ui/text/output/buffer/stdout'
4
9
5
10
module Msf
@@ -12,6 +17,16 @@ module CommandDispatcher
12
17
class Jobs
13
18
include Msf ::Ui ::Console ::CommandDispatcher
14
19
20
+ @@handler_opts = Rex ::Parser ::Arguments . new (
21
+ "-h" => [ false , "Help Banner" ] ,
22
+ "-x" => [ false , "Shut the Handler down after a session is established" ] ,
23
+ "-p" => [ true , "The payload to configure the handler for" ] ,
24
+ "-P" => [ true , "The RPORT/LPORT to configure the handler for" ] ,
25
+ "-H" => [ true , "The RHOST/LHOST to configure the handler for" ] ,
26
+ "-e" => [ true , "An Encoder to use for Payload Stage Encoding" ] ,
27
+ "-n" => [ true , "The custom name to give the handler job" ]
28
+ )
29
+
15
30
@@jobs_opts = Rex ::Parser ::Arguments . new (
16
31
"-h" => [ false , "Help banner." ] ,
17
32
"-k" => [ true , "Terminate jobs by job ID and/or range." ] ,
@@ -26,6 +41,7 @@ def commands
26
41
"jobs" => "Displays and manages jobs" ,
27
42
"rename_job" => "Rename a job" ,
28
43
"kill" => "Kill a job" ,
44
+ "handler" => "Start a payload handler as job"
29
45
}
30
46
end
31
47
@@ -75,7 +91,7 @@ def cmd_rename_job(*args)
75
91
# @param words [Array<String>] the previously completed words on the command line. words is always
76
92
# at least 1 when tab completion has reached this stage since the command itself has been completed
77
93
78
- def cmd_rename_job_tabs ( str , words )
94
+ def cmd_rename_job_tabs ( _str , words )
79
95
return [ ] if words . length > 1
80
96
framework . jobs . keys
81
97
end
@@ -94,49 +110,49 @@ def cmd_jobs_help
94
110
def cmd_jobs ( *args )
95
111
# Make the default behavior listing all jobs if there were no options
96
112
# or the only option is the verbose flag
97
- args . unshift ( "-l" ) if args . length == 0 || args == [ "-v" ]
113
+ args . unshift ( "-l" ) if args . empty? || args == [ "-v" ]
98
114
99
115
verbose = false
100
116
dump_list = false
101
117
dump_info = false
102
118
job_id = nil
103
119
104
120
# Parse the command options
105
- @@jobs_opts . parse ( args ) do |opt , idx , val |
121
+ @@jobs_opts . parse ( args ) do |opt , _idx , val |
106
122
case opt
107
- when "-v"
108
- verbose = true
109
- when "-l"
110
- dump_list = true
123
+ when "-v"
124
+ verbose = true
125
+ when "-l"
126
+ dump_list = true
111
127
# Terminate the supplied job ID(s)
112
- when "-k"
113
- job_list = build_range_array ( val )
114
- if job_list . blank?
115
- print_error ( "Please specify valid job identifier(s)" )
116
- return false
117
- end
118
- print_status ( "Stopping the following job(s): #{ job_list . join ( ', ' ) } " )
119
- job_list . map ( &:to_s ) . each do |job |
120
- if framework . jobs . has_key? ( job )
121
- print_status ( "Stopping job #{ job } " )
122
- framework . jobs . stop_job ( job )
123
- else
124
- print_error ( "Invalid job identifier: #{ job } " )
125
- end
126
- end
127
- when "-K"
128
- print_line ( "Stopping all jobs..." )
129
- framework . jobs . each_key do |i |
130
- framework . jobs . stop_job ( i )
131
- end
132
- when "-i"
133
- # Defer printing anything until the end of option parsing
134
- # so we can check for the verbose flag.
135
- dump_info = true
136
- job_id = val
137
- when "-h"
138
- cmd_jobs_help
128
+ when "-k"
129
+ job_list = build_range_array ( val )
130
+ if job_list . blank?
131
+ print_error ( "Please specify valid job identifier(s)" )
139
132
return false
133
+ end
134
+ print_status ( "Stopping the following job(s): #{ job_list . join ( ', ' ) } " )
135
+ job_list . map ( &:to_s ) . each do |job |
136
+ if framework . jobs . key? ( job )
137
+ print_status ( "Stopping job #{ job } " )
138
+ framework . jobs . stop_job ( job )
139
+ else
140
+ print_error ( "Invalid job identifier: #{ job } " )
141
+ end
142
+ end
143
+ when "-K"
144
+ print_line ( "Stopping all jobs..." )
145
+ framework . jobs . each_key do |i |
146
+ framework . jobs . stop_job ( i )
147
+ end
148
+ when "-i"
149
+ # Defer printing anything until the end of option parsing
150
+ # so we can check for the verbose flag.
151
+ dump_info = true
152
+ job_id = val
153
+ when "-h"
154
+ cmd_jobs_help
155
+ return false
140
156
end
141
157
end
142
158
@@ -157,7 +173,7 @@ def cmd_jobs(*args)
157
173
158
174
if verbose
159
175
mod_opt = Serializer ::ReadableText . dump_advanced_options ( mod , ' ' )
160
- if mod_opt && mod_opt . length > 0
176
+ if mod_opt && ! mod_opt . empty?
161
177
print_line ( "\n Module advanced options:\n \n #{ mod_opt } \n " )
162
178
end
163
179
end
@@ -174,10 +190,8 @@ def cmd_jobs(*args)
174
190
# @param words [Array<String>] the previously completed words on the command line. words is always
175
191
# at least 1 when tab completion has reached this stage since the command itself has been completed
176
192
177
- def cmd_jobs_tabs ( str , words )
178
- if words . length == 1
179
- return @@jobs_opts . fmt . keys
180
- end
193
+ def cmd_jobs_tabs ( _str , words )
194
+ return @@jobs_opts . fmt . keys if words . length == 1
181
195
182
196
if words . length == 2 && ( @@jobs_opts . fmt [ words [ 1 ] ] || [ false ] ) [ 0 ]
183
197
return framework . jobs . keys
@@ -204,10 +218,122 @@ def cmd_kill(*args)
204
218
# @param words [Array<String>] the previously completed words on the command line. words is always
205
219
# at least 1 when tab completion has reached this stage since the command itself has been completed
206
220
207
- def cmd_kill_tabs ( str , words )
221
+ def cmd_kill_tabs ( _str , words )
208
222
return [ ] if words . length > 1
209
223
framework . jobs . keys
210
224
end
225
+
226
+ def cmd_handler_help
227
+ print_line "Usage: handler [options]"
228
+ print_line
229
+ print_line "Spin up a Payload Handler as background job."
230
+ print @@handler_opts . usage
231
+ end
232
+
233
+ # Allows the user to setup a payload handler as a background job from a single command.
234
+ def cmd_handler ( *args )
235
+ # Display the help banner if no arguments were passed
236
+ if args . empty?
237
+ cmd_handler_help
238
+ return
239
+ end
240
+
241
+ exit_on_session = false
242
+ payload_module = nil
243
+ port = nil
244
+ host = nil
245
+ job_name = nil
246
+ stage_encoder = nil
247
+
248
+ # Parse the command options
249
+ @@handler_opts . parse ( args ) do |opt , _idx , val |
250
+ case opt
251
+ when "-x"
252
+ exit_on_session = true
253
+ when "-p"
254
+ payload_module = framework . payloads . create ( val )
255
+ if payload_module . nil?
256
+ print_error "Invalid Payload Name Supplied!"
257
+ return
258
+ end
259
+ when "-P"
260
+ port = val
261
+ when "-H"
262
+ host = val
263
+ when "-n"
264
+ job_name = val
265
+ when "-e"
266
+ encoder_module = framework . encoders . create ( val )
267
+ if encoder_module . nil?
268
+ print_error "Invalid Encoder Name Supplied"
269
+ end
270
+ stage_encoder = encoder_module . refname
271
+ when "-h"
272
+ cmd_handler_help
273
+ return
274
+ end
275
+ end
276
+
277
+ # If we are missing any of the required options, inform the user about each
278
+ # missing options, and not just one. Then exit so they can try again.
279
+ print_error "You must select a payload with -p <payload>" if payload_module . nil?
280
+ print_error "You must select a port(RPORT/LPORT) with -P <port number>" if port . nil?
281
+ print_error "You must select a host(RHOST/LHOST) with -H <hostname or address>" if host . nil?
282
+ if payload_module . nil? || port . nil? || host . nil?
283
+ print_error "Please supply missing arguments and try again."
284
+ return
285
+ end
286
+
287
+ handler = framework . modules . create ( 'exploit/multi/handler' )
288
+ payload_datastore = payload_module . datastore
289
+
290
+ # Set The RHOST or LHOST for the payload
291
+ if payload_datastore . has_key? "LHOST"
292
+ payload_datastore [ 'LHOST' ] = host
293
+ elsif payload_datastore . has_key? "RHOST"
294
+ payload_datastore [ 'RHOST' ] = host
295
+ else
296
+ print_error "Could not determine how to set Host on this payload..."
297
+ return
298
+ end
299
+
300
+ # Set the RPORT or LPORT for the payload
301
+ if payload_datastore . has_key? "LPORT"
302
+ payload_datastore [ 'LPORT' ] = port
303
+ elsif payload_datastore . has_key? "RPORT"
304
+ payload_datastore [ 'RPORT' ] = port
305
+ else
306
+ print_error "Could not determine how to set Port on this payload..."
307
+ return
308
+ end
309
+
310
+ # Set StageEncoder if selected
311
+ if stage_encoder . present?
312
+ payload_datastore [ "EnableStageEncoding" ] = true
313
+ payload_datastore [ "StageEncoder" ] = stage_encoder
314
+ end
315
+
316
+ # Merge payload datastore options into the handler options
317
+ handler_opts = {
318
+ 'Payload' => payload_module . refname ,
319
+ 'LocalInput' => driver . input ,
320
+ 'LocalOutput' => driver . output ,
321
+ 'ExitOnSession' => exit_on_session ,
322
+ 'RunAsJob' => true
323
+ }
324
+ handler . datastore . reverse_merge! ( payload_datastore )
325
+
326
+ # Launch our Handler and get the Job ID
327
+ handler . exploit_simple ( handler_opts )
328
+ job_id = handler . job_id
329
+
330
+ # Customise the job name if the user asked for it
331
+ if job_name . present?
332
+ framework . jobs [ job_id . to_s ] . send ( :name= , job_name )
333
+ end
334
+
335
+ print_status "Payload Handler Started as Job #{ job_id } "
336
+ end
211
337
end
212
338
end
213
339
end
0 commit comments