Skip to content

Commit ec3aecb

Browse files
committed
Land rapid7#5958, fix VulnAttempt creation
MSP-13233 Still needs styleguide cleanup.
2 parents 30cb93b + 0bb03db commit ec3aecb

File tree

5 files changed

+93
-86
lines changed

5 files changed

+93
-86
lines changed

lib/msf/base/simple/exploit.rb

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,90 @@ def self.exploit_simple(oexploit, opts, &block)
154154
nil
155155
end
156156

157+
158+
def setup_fail_detail_from_exception e
159+
# Build a user-friendly error message
160+
msg = "#{e}"
161+
unless e.class == Msf::Exploit::Failed
162+
msg = "#{e.class} #{e}"
163+
end
164+
165+
self.error = e
166+
167+
# Record the detailed reason
168+
self.fail_detail ||= e.to_s
169+
msg
170+
end
171+
172+
#
173+
# Handle the exception
174+
#
175+
def handle_exception e
176+
msg = setup_fail_detail_from_exception e
177+
178+
case e
179+
when Msf::Exploit::Complete
180+
# Nothing to show in this case
181+
return
182+
183+
when Msf::Exploit::Failed
184+
self.print_error("Exploit aborted due to failure: #{self.fail_reason}: #{msg}")
185+
186+
# The caller should have already set self.fail_reason
187+
if self.fail_reason == Msf::Exploit::Failure::None
188+
self.fail_reason = Msf::Exploit::Failure::Unknown
189+
end
190+
191+
when Rex::ConnectionError
192+
self.fail_reason = Msf::Exploit::Failure::Unreachable
193+
self.print_error("Exploit failed [#{self.fail_reason}]: #{msg}")
194+
elog("Exploit failed (#{self.refname}): #{msg}", 'core', LEV_0)
195+
dlog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_3)
196+
197+
when Timeout::Error
198+
self.fail_reason = Msf::Exploit::Failure::TimeoutExpired
199+
self.print_error("Exploit failed [#{self.fail_reason}]: #{msg}")
200+
elog("Exploit failed (#{self.refname}): #{msg}", 'core', LEV_0)
201+
dlog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_3)
202+
else
203+
204+
# Compare as a string since not all error classes may be loaded
205+
case msg
206+
when /access.denied|Login Failed/i # Covers SMB as well as some generic errors
207+
self.fail_reason = Msf::Exploit::Failure::NoAccess
208+
when /connection reset/i
209+
self.fail_reason = Msf::Exploit::Failure::Disconnected
210+
when /connection timed out|SSL_connect|unreachable|connection was refused/i
211+
self.fail_reason = Msf::Exploit::Failure::Unreachable
212+
when /unable.*target/i
213+
self.fail_reason = Msf::Exploit::Failure::NoTarget
214+
when /execution expired/i
215+
self.fail_reason = Msf::Exploit::Failure::TimeoutExpired
216+
when /(doesn.t|not).*vulnerable|may.*patched/i
217+
self.fail_reason = Msf::Exploit::Failure::NotVulnerable
218+
end
219+
220+
# The caller should have already set self.fail_reason
221+
if self.fail_reason == Msf::Exploit::Failure::None
222+
self.fail_reason = Msf::Exploit::Failure::Unknown
223+
end
224+
225+
if self.fail_reason == Msf::Exploit::Failure::Unknown
226+
self.print_error("Exploit failed: #{msg}")
227+
else
228+
self.print_error("Exploit failed [#{self.fail_reason}]: #{msg}")
229+
end
230+
231+
elog("Exploit failed (#{self.refname}): #{msg}", 'core', LEV_0)
232+
dlog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_3)
233+
end
234+
235+
# Record the error to various places
236+
self.framework.events.on_module_error(self, msg)
237+
238+
# Report the failure (and attempt) in the database
239+
self.report_failure
240+
end
157241
#
158242
# Calls the class method.
159243
#

lib/msf/core/db_manager/exploit_attempt.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ def do_report_failure_or_success(opts)
119119
username = opts[:username]
120120
mname = opts[:module]
121121

122+
122123
if vuln.nil?
123124
ref_names = mrefs.map { |ref|
124125
if ref.respond_to?(:ctx_id) and ref.respond_to?(:ctx_val)

lib/msf/core/db_manager/vuln.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ def find_vuln_by_details(details_map, host, service=nil)
4646

4747
def find_vuln_by_refs(refs, host, service=nil)
4848
ref_ids = refs.find_all { |ref| ref.name.starts_with? 'CVE-'}
49-
host.vulns.includes(:refs).where(service_id: service.try(:id), refs: { id: ref_ids}).first
49+
relation = host.vulns.includes(:refs)
50+
relation.where(service_id: service.try(:id), refs: { id: ref_ids}).first || relation.where(refs: { id: ref_ids}).first
5051
end
5152

5253
def get_vuln(wspace, host, service, name, data='')

lib/msf/core/exploit.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1260,7 +1260,6 @@ def fail_with(reason,msg=nil)
12601260
end
12611261

12621262
def report_failure
1263-
12641263
return unless framework.db and framework.db.active
12651264

12661265
info = {
@@ -1293,6 +1292,7 @@ def report_failure
12931292
)
12941293
end
12951294

1295+
12961296
framework.db.report_exploit_failure(info)
12971297
end
12981298

lib/msf/core/exploit_driver.rb

Lines changed: 5 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ def validate
113113
# - Cleans up the handler
114114
#
115115
def run
116-
117116
# First thing's first -- validate the state. Make sure all requirement
118117
# parameters are set, including those that are derived from the
119118
# datastore.
@@ -164,6 +163,7 @@ def run
164163
# nothing should be able to modify their datastore or other
165164
# settings until after they're done.
166165
ctx = [ exploit, payload ]
166+
167167
job_run_proc(ctx)
168168
job_cleanup_proc(ctx)
169169
end
@@ -187,18 +187,15 @@ def run
187187

188188
protected
189189

190-
191-
192190
#
193191
# Job run proc, sets up the exploit and kicks it off.
194192
#
195193
def job_run_proc(ctx)
196-
# Default session wait time..
197-
delay = payload.wfs_delay + exploit.wfs_delay
198-
delay = nil if exploit.passive?
199-
200194
begin
201195
exploit, payload = ctx
196+
# Default session wait time..
197+
delay = payload.wfs_delay + exploit.wfs_delay
198+
delay = nil if exploit.passive?
202199

203200
# Set the exploit up the bomb
204201
exploit.setup
@@ -208,88 +205,12 @@ def job_run_proc(ctx)
208205
# Launch the exploit
209206
exploit.exploit
210207

211-
212-
213208
rescue ::Exception => e
214-
215209
if [::RuntimeError, ::Interrupt].include?(e.class)
216210
# Wait for session, but don't wait long.
217211
delay = 0.01
218212
end
219-
220-
# Build a user-friendly error message
221-
msg = "#{e}"
222-
unless e.class == Msf::Exploit::Failed
223-
msg = "#{e.class} #{e}"
224-
end
225-
226-
exploit.error = e
227-
228-
# Record the detailed reason
229-
exploit.fail_detail ||= e.to_s
230-
231-
case e
232-
when Msf::Exploit::Complete
233-
# Nothing to show in this case
234-
return
235-
236-
when Msf::Exploit::Failed
237-
exploit.print_error("Exploit aborted due to failure: #{exploit.fail_reason}: #{msg}")
238-
239-
# The caller should have already set exploit.fail_reason
240-
if exploit.fail_reason == Msf::Exploit::Failure::None
241-
exploit.fail_reason = Msf::Exploit::Failure::Unknown
242-
end
243-
244-
when Rex::ConnectionError
245-
exploit.fail_reason = Msf::Exploit::Failure::Unreachable
246-
exploit.print_error("Exploit failed [#{exploit.fail_reason}]: #{msg}")
247-
elog("Exploit failed (#{exploit.refname}): #{msg}", 'core', LEV_0)
248-
dlog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_3)
249-
250-
when Timeout::Error
251-
exploit.fail_reason = Msf::Exploit::Failure::TimeoutExpired
252-
exploit.print_error("Exploit failed [#{exploit.fail_reason}]: #{msg}")
253-
elog("Exploit failed (#{exploit.refname}): #{msg}", 'core', LEV_0)
254-
dlog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_3)
255-
else
256-
257-
# Compare as a string since not all error classes may be loaded
258-
case msg
259-
when /access.denied|Login Failed/i # Covers SMB as well as some generic errors
260-
exploit.fail_reason = Msf::Exploit::Failure::NoAccess
261-
when /connection reset/i
262-
exploit.fail_reason = Msf::Exploit::Failure::Disconnected
263-
when /connection timed out|SSL_connect|unreachable|connection was refused/i
264-
exploit.fail_reason = Msf::Exploit::Failure::Unreachable
265-
when /unable.*target/i
266-
exploit.fail_reason = Msf::Exploit::Failure::NoTarget
267-
when /execution expired/i
268-
exploit.fail_reason = Msf::Exploit::Failure::TimeoutExpired
269-
when /(doesn.t|not).*vulnerable|may.*patched/i
270-
exploit.fail_reason = Msf::Exploit::Failure::NotVulnerable
271-
end
272-
273-
# The caller should have already set exploit.fail_reason
274-
if exploit.fail_reason == Msf::Exploit::Failure::None
275-
exploit.fail_reason = Msf::Exploit::Failure::Unknown
276-
end
277-
278-
if exploit.fail_reason == Msf::Exploit::Failure::Unknown
279-
exploit.print_error("Exploit failed: #{msg}")
280-
else
281-
exploit.print_error("Exploit failed [#{exploit.fail_reason}]: #{msg}")
282-
end
283-
284-
elog("Exploit failed (#{exploit.refname}): #{msg}", 'core', LEV_0)
285-
dlog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_3)
286-
end
287-
288-
# Record the error to various places
289-
exploit.framework.events.on_module_error(exploit, msg)
290-
291-
# Report the failure (and attempt) in the database
292-
exploit.report_failure
213+
exploit.handle_exception e
293214
end
294215

295216
# Wait the payload to acquire a session if this isn't a passive-style

0 commit comments

Comments
 (0)