CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/msf/core/exploit_driver.rb
Views: 1904
1
# -*- coding: binary -*-
2
3
module Msf
4
5
###
6
#
7
# This class drives the exploitation process from start to finish for a given
8
# exploit module instance. It's responsible for payload generation, encoding,
9
# and padding as well as initialization handlers and finally launching the
10
# exploit.
11
#
12
###
13
class ExploitDriver
14
15
#
16
# Initializes the exploit driver using the supplied framework instance.
17
#
18
def initialize(framework)
19
self.payload = nil
20
self.exploit = nil
21
self.use_job = false
22
self.job_id = nil
23
self.force_wait_for_session = false
24
self.keep_handler = false
25
self.semaphore = Mutex.new
26
end
27
28
#
29
# Specification of the exploit target index.
30
#
31
def target_idx=(target_idx)
32
if (target_idx)
33
# Make sure the target index is valid
34
if (target_idx >= exploit.targets.length)
35
raise Rex::ArgumentError, "Invalid target index.", caller
36
end
37
end
38
39
# Set the active target
40
@target_idx = target_idx
41
end
42
43
#
44
# This method returns the currently selected target index.
45
#
46
def target_idx
47
@target_idx
48
end
49
50
#
51
# Checks to see if the supplied payload is compatible with the
52
# current exploit. Assumes that target_idx is valid.
53
#
54
def compatible_payload?(payload)
55
!exploit.compatible_payloads.find { |refname, _| refname == payload.refname }.nil?
56
end
57
58
##
59
#
60
# Exploit execution
61
#
62
##
63
64
#
65
# Makes sure everything's in tip-top condition prior to launching the
66
# exploit. For things that aren't good to go, an exception is thrown.
67
#
68
def validate
69
# First, validate that a target has been selected
70
if (target_idx == nil)
71
raise MissingTargetError,
72
"A payload cannot be selected until a target is specified.",
73
caller
74
end
75
76
# Next, validate that a payload has been selected
77
if (payload == nil)
78
raise MissingPayloadError,
79
"A payload has not been selected.", caller
80
end
81
82
# Make sure the payload is compatible after all
83
unless compatible_payload?(payload)
84
raise IncompatiblePayloadError.new(payload.refname), "#{payload.refname} is not a compatible payload.", caller
85
end
86
87
unless exploit.respond_to?(:allow_no_cleanup) && exploit.allow_no_cleanup
88
# Being able to cleanup requires a session to be created from a handler, and for that
89
# session to be able to be able to clean up files
90
can_cleanup = payload.handler_klass != Msf::Handler::None && payload&.session&.can_cleanup_files
91
if exploit.needs_cleanup && !can_cleanup
92
raise IncompatiblePayloadError.new(payload.refname), "#{payload.refname} cannot cleanup files created during exploit. To run anyway, set AllowNoCleanup to true"
93
end
94
95
if exploit.needs_cleanup && !exploit.handler_enabled?
96
raise ValidationError.new('Cannot cleanup files created during exploit if payload handler is disabled. To run anyway, set AllowNoCleanup to true')
97
end
98
end
99
100
# Associate the payload instance with the exploit
101
payload.assoc_exploit = exploit
102
103
# Finally, validate options on the exploit module to ensure that things
104
# are ready to operate as they should.
105
exploit.options.validate(exploit.datastore)
106
107
# Validate the payload's options. The payload's datastore is
108
# most likely shared against the exploit's datastore, but in case it
109
# isn't.
110
payload.options.validate(payload.datastore)
111
112
return true
113
end
114
115
#
116
# Kicks off an exploitation attempt and performs the following four major
117
# operations:
118
#
119
# - Generates the payload
120
# - Initializes & monitors the handler
121
# - Launches the exploit
122
# - Cleans up the handler
123
#
124
def run
125
# First thing's first -- validate the state. Make sure all requirement
126
# parameters are set, including those that are derived from the
127
# datastore.
128
validate()
129
130
# After validation has occurred, it's time to set some values on the
131
# exploit instance and begin preparing the payload
132
exploit.datastore['TARGET'] = target_idx
133
134
# Default the session to nil
135
self.session = nil
136
137
# Explicitly clear the module's job_id in case it was set in a previous
138
# run
139
exploit.job_id = nil
140
141
# If we are being instructed to run as a job then let's create that job
142
# like a good person.
143
if (use_job or exploit.passive?)
144
# Since references to the exploit and payload will hang around for
145
# awhile in the job, make sure we copy them so further changes to
146
# the datastore don't alter settings in existing jobs
147
e = exploit.replicant
148
p = payload.replicant
149
150
# Assign the correct exploit instance to the payload
151
p.assoc_exploit = e
152
153
# Generate the encoded version of the supplied payload for the
154
# newly copied exploit module instance
155
e.generate_payload(p)
156
ctx = [ e, p ]
157
158
e.job_id = e.framework.jobs.start_bg_job(
159
"Exploit: #{e.refname}",
160
ctx,
161
Proc.new { |ctx_| job_run_proc(ctx_) },
162
Proc.new { |ctx_| job_cleanup_proc(ctx_) }
163
)
164
self.job_id = e.job_id
165
else
166
# Generate the encoded version of the supplied payload on the
167
# exploit module instance
168
exploit.generate_payload(payload)
169
170
# No need to copy since we aren't creating a job. We wait until
171
# they're finished running to do anything else with them, so
172
# nothing should be able to modify their datastore or other
173
# settings until after they're done.
174
ctx = [ exploit, payload ]
175
176
begin
177
job_run_proc(ctx)
178
rescue ::Interrupt
179
job_cleanup_proc(ctx)
180
raise $!
181
ensure
182
# For multi exploit targets.
183
# Keep the payload handler until last target or interrupt
184
job_cleanup_proc(ctx) unless keep_handler
185
end
186
end
187
188
return session
189
end
190
191
attr_accessor :exploit # :nodoc:
192
attr_accessor :payload # :nodoc:
193
attr_accessor :use_job # :nodoc:
194
#
195
# The identifier of the job this exploit is launched as, if it's run as a
196
# job.
197
#
198
attr_accessor :job_id
199
attr_accessor :force_wait_for_session # :nodoc:
200
attr_accessor :session # :nodoc:
201
attr_accessor :keep_handler # :nodoc:
202
203
# To synchronize threads cleaning up the exploit and the handler
204
attr_accessor :semaphore
205
206
protected
207
208
#
209
# Job run proc, sets up the exploit and kicks it off.
210
#
211
def job_run_proc(ctx)
212
begin
213
exploit, payload = ctx
214
# Default session wait time..
215
delay = payload.wfs_delay + exploit.wfs_delay
216
delay = nil if exploit.passive?
217
218
# Set the exploit up the bomb
219
exploit.setup
220
221
exploit.framework.events.on_module_run(exploit)
222
223
# Launch the exploit
224
exploit.exploit
225
226
rescue ::Exception => e
227
if [::RuntimeError, ::Interrupt].include?(e.class)
228
# Wait for session, but don't wait long.
229
delay = 0.01
230
end
231
232
fail_reason = exploit.handle_exception(e)
233
end
234
235
# Start bind handlers after exploit completion
236
payload.start_handler if exploit.handler_bind?
237
238
# Wait the payload to acquire a session if this isn't a passive-style
239
# exploit.
240
return if not delay
241
242
if (force_wait_for_session == true) or
243
(exploit.passive? == false and exploit.handler_enabled?)
244
begin
245
self.session = payload.wait_for_session(delay)
246
rescue ::Interrupt
247
# Don't let interrupt pass upward
248
end
249
end
250
251
return self.session if self.session
252
253
if exploit.fail_reason == Msf::Exploit::Failure::None
254
exploit.fail_reason = Msf::Exploit::Failure::PayloadFailed
255
exploit.fail_detail = "No session created"
256
exploit.report_failure
257
end
258
259
if fail_reason && fail_reason == Msf::Exploit::Failure::UserInterrupt
260
raise ::Interrupt
261
end
262
end
263
264
#
265
# Clean up the exploit and the handler after the job completes.
266
#
267
def job_cleanup_proc(ctx)
268
exploit, payload = ctx
269
270
# Ensure that, no matter what, clean up of the handler occurs
271
semaphore.synchronize { payload.stop_handler }
272
273
exploit.framework.events.on_module_complete(exploit)
274
275
# Allow the exploit to cleanup after itself, that messy bugger.
276
semaphore.synchronize { exploit.cleanup }
277
end
278
279
end
280
281
end
282
283
284