@@ -79,22 +79,23 @@ def report_exploit_failure(opts)
7979
8080 vuln = nil
8181 if rids . present?
82- # Skip vuln lookup entirely when the check result indicates the target
83- # is not vulnerable. A Safe/Unknown check on port 80 should not
84- # attach a VulnAttempt to an unrelated vuln on port 9200 just because
85- # the module refs happen to match.
86- safe_fail_reasons = [ Msf ::Module ::Failure ::NotVulnerable , Msf ::Module ::Failure ::Unknown ]
87- unless safe_fail_reasons . include? ( opts [ :fail_reason ] )
82+ # Only perform vuln lookup when no check_code is present (normal
83+ # exploit flow) or the check result positively indicates vulnerability.
84+ # Safe, Unknown, and Detected results should not associate this attempt
85+ # with an existing vuln. Only key off check_code — fail_reason alone
86+ # is too broad (e.g. Failure::Unknown covers real exploit failures too).
87+ vuln_check_codes = [ Msf ::Exploit ::CheckCode ::Appears . code , Msf ::Exploit ::CheckCode ::Vulnerable . code ]
88+ if opts [ :check_code ] . nil? || vuln_check_codes . include? ( opts [ :check_code ] )
8889 # Try to find an existing vulnerability with the same service & references
8990 # or, if svc is nil, with the same host & references
9091 vuln = find_vuln_by_refs ( rids , host , svc , false )
9192
9293 # Fall back to a host-only lookup when the service-scoped query found
93- # nothing. Vulns created by `check` (via module_command_dispatcher's
94- # report_vuln) often have no associated service, so a service-scoped
95- # query will miss them.
96- if vuln . nil? && svc
97- vuln = find_vuln_by_refs ( rids , host , nil , false )
94+ # nothing. Only match vulns with no associated service to avoid
95+ # misattributing attempts to a vuln on a different service.
96+ if svc && vuln . nil?
97+ fallback_vuln = find_vuln_by_refs ( rids , host , nil , false )
98+ vuln = fallback_vuln if fallback_vuln && fallback_vuln . service_id . nil?
9899 end
99100 end
100101 end
@@ -173,14 +174,19 @@ def do_report_failure_or_success(opts)
173174 # Create a references map from the module list
174175 ref_objs = ::Mdm ::Ref . where ( name : ref_names )
175176
176- # Skip vuln lookup when the result indicates the target is not
177- # vulnerable — avoids attaching a VulnAttempt to an unrelated vuln
178- # on a different port that happens to share the same refs.
179- safe_fail_reasons = [ Msf ::Module ::Failure ::NotVulnerable , Msf ::Module ::Failure ::Unknown ]
180- unless safe_fail_reasons . include? ( freason )
177+ # Only perform vuln lookup when no check_code is present (normal
178+ # exploit flow) or the check result positively indicates vulnerability.
179+ # Safe, Unknown, and Detected results should not associate this attempt
180+ # with an existing vuln. Only key off check_code — fail_reason alone
181+ # is too broad (e.g. Failure::Unknown covers real exploit failures too).
182+ vuln_check_codes = [ Msf ::Exploit ::CheckCode ::Appears . code , Msf ::Exploit ::CheckCode ::Vulnerable . code ]
183+ if opts [ :check_code ] . nil? || vuln_check_codes . include? ( opts [ :check_code ] )
181184 # Try find a matching vulnerability
182185 vuln = find_vuln_by_refs ( ref_objs , host , svc , false )
183- vuln ||= find_vuln_by_refs ( ref_objs , host , nil , false ) if svc && vuln . nil?
186+ if svc && vuln . nil?
187+ fallback_vuln = find_vuln_by_refs ( ref_objs , host , nil , false )
188+ vuln = fallback_vuln if fallback_vuln && fallback_vuln . service_id . nil?
189+ end
184190 end
185191 end
186192
@@ -201,7 +207,7 @@ def do_report_failure_or_success(opts)
201207 # We have match, lets create a vuln_attempt record.
202208 # Skip if the caller already recorded a vuln attempt for this run
203209 # (e.g. Auxiliary::Report#report_vuln sets skip_vuln_attempt via
204- # the vuln_attempt_recorded flag on the module).
210+ # the last_vuln_attempt flag on the module).
205211 if vuln && !opts [ :skip_vuln_attempt ]
206212 attempt_info [ :vuln_id ] = vuln . id
207213 vuln . vuln_attempts . create ( attempt_info )
0 commit comments