Class: Msf::ExploitDriver

Inherits:
Object
  • Object
show all
Defined in:
lib/msf/core/exploit_driver.rb

Overview

This class drives the exploitation process from start to finish for a given exploit module instance. It’s responsible for payload generation, encoding, and padding as well as initialization handlers and finally launching the exploit.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(framework) ⇒ ExploitDriver

Initializes the exploit driver using the supplied framework instance.



18
19
20
21
22
23
24
25
26
# File 'lib/msf/core/exploit_driver.rb', line 18

def initialize(framework)
  self.payload                = nil
  self.exploit                = nil
  self.use_job                = false
  self.job_id                 = nil
  self.force_wait_for_session = false
  self.keep_handler           = false
  self.semaphore              = Mutex.new
end

Instance Attribute Details

#exploitObject

:nodoc:



191
192
193
# File 'lib/msf/core/exploit_driver.rb', line 191

def exploit
  @exploit
end

#force_wait_for_sessionObject

:nodoc:



199
200
201
# File 'lib/msf/core/exploit_driver.rb', line 199

def force_wait_for_session
  @force_wait_for_session
end

#job_idObject

The identifier of the job this exploit is launched as, if it’s run as a job.



198
199
200
# File 'lib/msf/core/exploit_driver.rb', line 198

def job_id
  @job_id
end

#keep_handlerObject

:nodoc:



201
202
203
# File 'lib/msf/core/exploit_driver.rb', line 201

def keep_handler
  @keep_handler
end

#payloadObject

:nodoc:



192
193
194
# File 'lib/msf/core/exploit_driver.rb', line 192

def payload
  @payload
end

#semaphoreObject

To synchronize threads cleaning up the exploit and the handler



204
205
206
# File 'lib/msf/core/exploit_driver.rb', line 204

def semaphore
  @semaphore
end

#sessionObject

:nodoc:



200
201
202
# File 'lib/msf/core/exploit_driver.rb', line 200

def session
  @session
end

#use_jobObject

:nodoc:



193
194
195
# File 'lib/msf/core/exploit_driver.rb', line 193

def use_job
  @use_job
end

Instance Method Details

#compatible_payload?(payload) ⇒ Boolean

Checks to see if the supplied payload is compatible with the current exploit. Assumes that target_idx is valid.

Returns:

  • (Boolean)


54
55
56
# File 'lib/msf/core/exploit_driver.rb', line 54

def compatible_payload?(payload)
  !exploit.compatible_payloads.find { |refname, _| refname == payload.refname }.nil?
end

#job_cleanup_proc(ctx) ⇒ Object (protected)

Clean up the exploit and the handler after the job completes.



267
268
269
270
271
272
273
274
275
276
277
# File 'lib/msf/core/exploit_driver.rb', line 267

def job_cleanup_proc(ctx)
  exploit, payload = ctx

  # Ensure that, no matter what, clean up of the handler occurs
  semaphore.synchronize { payload.stop_handler }

  exploit.framework.events.on_module_complete(exploit)

  # Allow the exploit to cleanup after itself, that messy bugger.
  semaphore.synchronize { exploit.cleanup }
end

#job_run_proc(ctx) ⇒ Object (protected)

Job run proc, sets up the exploit and kicks it off.



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/msf/core/exploit_driver.rb', line 211

def job_run_proc(ctx)
  begin
    exploit, payload = ctx
    # Default session wait time..
    delay = payload.wfs_delay + exploit.wfs_delay
    delay = nil if exploit.passive?

    # Set the exploit up the bomb
    exploit.setup

    exploit.framework.events.on_module_run(exploit)

    # Launch the exploit
    exploit.exploit

  rescue ::Exception => e
    if [::RuntimeError, ::Interrupt].include?(e.class)
      # Wait for session, but don't wait long.
      delay = 0.01
    end

    fail_reason = exploit.handle_exception(e)
  end

  # Start bind handlers after exploit completion
  payload.start_handler if exploit.handler_bind?

  # Wait the payload to acquire a session if this isn't a passive-style
  # exploit.
  return if not delay

  if (force_wait_for_session == true) or
    (exploit.passive? == false and exploit.handler_enabled?)
    begin
      self.session = payload.wait_for_session(delay)
    rescue ::Interrupt
      # Don't let interrupt pass upward
    end
  end

  return self.session if self.session

  if exploit.fail_reason == Msf::Exploit::Failure::None
    exploit.fail_reason = Msf::Exploit::Failure::PayloadFailed
    exploit.fail_detail = "No session created"
    exploit.report_failure
  end

  if fail_reason && fail_reason == Msf::Exploit::Failure::UserInterrupt
    raise ::Interrupt
  end
end

#runObject

Kicks off an exploitation attempt and performs the following four major operations:

- Generates the payload
- Initializes & monitors the handler
- Launches the exploit
- Cleans up the handler


124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/msf/core/exploit_driver.rb', line 124

def run
  # First thing's first -- validate the state.  Make sure all requirement
  # parameters are set, including those that are derived from the
  # datastore.
  validate()

  # After validation has occurred, it's time to set some values on the
  # exploit instance and begin preparing the payload
  exploit.datastore['TARGET'] = target_idx

  # Default the session to nil
  self.session = nil

  # Explicitly clear the module's job_id in case it was set in a previous
  # run
  exploit.job_id = nil

  # If we are being instructed to run as a job then let's create that job
  # like a good person.
  if (use_job or exploit.passive?)
    # Since references to the exploit and payload will hang around for
    # awhile in the job, make sure we copy them so further changes to
    # the datastore don't alter settings in existing jobs
    e = exploit.replicant
    p = payload.replicant

    # Assign the correct exploit instance to the payload
    p.assoc_exploit = e

    # Generate the encoded version of the supplied payload for the
    # newly copied exploit module instance
    e.generate_payload(p)
    ctx = [ e, p ]

    e.job_id = e.framework.jobs.start_bg_job(
      "Exploit: #{e.refname}",
      ctx,
      Proc.new { |ctx_| job_run_proc(ctx_) },
      Proc.new { |ctx_| job_cleanup_proc(ctx_) }
    )
    self.job_id = e.job_id
  else
    # Generate the encoded version of the supplied payload on the
    # exploit module instance
    exploit.generate_payload(payload)

    # No need to copy since we aren't creating a job.  We wait until
    # they're finished running to do anything else with them, so
    # nothing should be able to modify their datastore or other
    # settings until after they're done.
    ctx = [ exploit, payload ]

    begin
      job_run_proc(ctx)
    rescue ::Interrupt
      job_cleanup_proc(ctx)
      raise $!
    ensure
      # For multi exploit targets.
      # Keep the payload handler until last target or interrupt
      job_cleanup_proc(ctx) unless keep_handler
    end
  end

  return session
end

#target_idxObject

This method returns the currently selected target index.



46
47
48
# File 'lib/msf/core/exploit_driver.rb', line 46

def target_idx
  @target_idx
end

#target_idx=(target_idx) ⇒ Object

Specification of the exploit target index.



31
32
33
34
35
36
37
38
39
40
41
# File 'lib/msf/core/exploit_driver.rb', line 31

def target_idx=(target_idx)
  if (target_idx)
    # Make sure the target index is valid
    if (target_idx >= exploit.targets.length)
      raise Rex::ArgumentError, "Invalid target index.", caller
    end
  end

   # Set the active target
  @target_idx = target_idx
end

#validateObject

Makes sure everything’s in tip-top condition prior to launching the exploit. For things that aren’t good to go, an exception is thrown.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/msf/core/exploit_driver.rb', line 68

def validate
  # First, validate that a target has been selected
  if (target_idx == nil)
    raise MissingTargetError,
      "A payload cannot be selected until a target is specified.",
      caller
  end

  # Next, validate that a payload has been selected
  if (payload == nil)
    raise MissingPayloadError,
      "A payload has not been selected.", caller
  end

  # Make sure the payload is compatible after all
  unless compatible_payload?(payload)
    raise IncompatiblePayloadError.new(payload.refname), "#{payload.refname} is not a compatible payload.", caller
  end

  unless exploit.respond_to?(:allow_no_cleanup) && exploit.allow_no_cleanup
    # Being able to cleanup requires a session to be created from a handler, and for that
    # session to be able to be able to clean up files
    can_cleanup = payload.handler_klass != Msf::Handler::None && payload&.session&.can_cleanup_files
    if exploit.needs_cleanup && !can_cleanup
      raise IncompatiblePayloadError.new(payload.refname), "#{payload.refname} cannot cleanup files created during exploit. To run anyway, set AllowNoCleanup to true"
    end

    if exploit.needs_cleanup && !exploit.handler_enabled?
      raise ValidationError.new('Cannot cleanup files created during exploit if payload handler is disabled. To run anyway, set AllowNoCleanup to true')
    end
  end

  # Associate the payload instance with the exploit
  payload.assoc_exploit = exploit

  # Finally, validate options on the exploit module to ensure that things
  # are ready to operate as they should.
  exploit.options.validate(exploit.datastore)

  # Validate the payload's options.  The payload's datastore is
  # most likely shared against the exploit's datastore, but in case it
  # isn't.
  payload.options.validate(payload.datastore)

  return true
end