@@ -44,11 +44,15 @@ def find_vuln_by_details(details_map, host, service=nil)
44
44
other_vulns . empty? ? nil : other_vulns . first
45
45
end
46
46
47
- def find_vuln_by_refs ( refs , host , service = nil , cve_only = true )
47
+ def find_vuln_by_refs ( refs , host , service = nil , cve_only = true , resource = nil )
48
48
ref_ids = cve_only ? refs . find_all { |ref | ref . name . starts_with? 'CVE-' } : refs
49
49
relation = host . vulns . joins ( :refs )
50
50
if !service . try ( :id ) . nil?
51
- return relation . where ( service_id : service . try ( :id ) , refs : { id : ref_ids } ) . first
51
+ if resource
52
+ return relation . where ( service_id : service . try ( :id ) , refs : { id : ref_ids } , resource : resource ) . first
53
+ else
54
+ return relation . where ( service_id : service . try ( :id ) , refs : { id : ref_ids } ) . first
55
+ end
52
56
end
53
57
return relation . where ( refs : { id : ref_ids } ) . first
54
58
end
@@ -80,12 +84,20 @@ def has_vuln?(name)
80
84
# opts MUST contain
81
85
# +:host+:: the host where this vulnerability resides
82
86
# +:name+:: the friendly name for this vulnerability (title)
87
+ # +:workspace+:: the workspace to report this vulnerability in
83
88
#
84
89
# opts can contain
85
90
# +:info+:: a human readable description of the vuln, free-form text
86
91
# +:refs+:: an array of Ref objects or string names of references
87
92
# +:details+:: a hash with :key pointed to a find criteria hash and the rest containing VulnDetail fields
88
93
# +:sname+:: the name of the service this vulnerability relates to, used to associate it or create it.
94
+ # +:exploited_at+:: a timestamp indicating when this vulnerability was exploited, if applicable
95
+ # +:ref_ids+:: an array of reference IDs to associate with this vulnerability
96
+ # +:service+:: a Mdm::Service object or a Hash with service attributes to associate this vulnerability with
97
+ # +:port+:: the port number of the service this vulnerability relates to, if applicable
98
+ # +:proto+:: the transport layer protocol of the service this vulnerability relates to, if applicable
99
+ # +:details_match+:: a Mdm:VulnDetail with details related to this vulnerability
100
+ # +:resource+:: a resource hash to associate with this vulnerability, such as a URI or pipe name
89
101
#
90
102
def report_vuln ( opts )
91
103
return if not active
@@ -141,7 +153,16 @@ def report_vuln(opts)
141
153
vuln = nil
142
154
143
155
# Identify the associated service
144
- service = opts . delete ( :service )
156
+ service_opt = opts . delete ( :service )
157
+ case service_opt
158
+ when Mdm ::Service
159
+ service = service_opt
160
+ when Hash
161
+ service = report_service ( service_opt . merge ( workspace : wspace , host : host ) )
162
+ else
163
+ dlog ( "Skipping service since it is not a Hash or Mdm::Service: #{ service . class } " )
164
+ service = nil
165
+ end
145
166
146
167
# Treat port zero as no service
147
168
if service or opts [ :port ] . to_i > 0
@@ -160,9 +181,17 @@ def report_vuln(opts)
160
181
sname = opts [ :proto ]
161
182
end
162
183
163
- services = host . services . where ( port : opts [ :port ] . to_i , proto : proto )
164
- services = services . where ( name : sname ) if sname . present?
165
- service = services . first_or_create
184
+ # If sname and proto are not provided, this will assign the first service
185
+ # registered in the database for this host with the given port and proto.
186
+ # This is likely to be the TCP service.
187
+ sopts = {
188
+ workspace : wspace ,
189
+ host : host ,
190
+ port : opts [ :port ] . to_i ,
191
+ proto : proto
192
+ }
193
+ sopts [ :name ] = sname if sname . present?
194
+ service = report_service ( sopts )
166
195
end
167
196
168
197
# Try to find an existing vulnerability with the same service & references
@@ -172,8 +201,12 @@ def report_vuln(opts)
172
201
# prevent dupes of the same vuln found by both local patch and
173
202
# service detection.
174
203
if rids and rids . length > 0
175
- vuln = find_vuln_by_refs ( rids , host , service )
176
- vuln . service = service if vuln
204
+ if opts [ :resource ]
205
+ vuln = find_vuln_by_refs ( rids , host , service , nil , opts [ :resource ] )
206
+ else
207
+ vuln = find_vuln_by_refs ( rids , host , service )
208
+ end
209
+ vuln . service = service if vuln && !vuln . service_id?
177
210
end
178
211
else
179
212
# Try to find an existing vulnerability with the same host & references
@@ -194,9 +227,17 @@ def report_vuln(opts)
194
227
# No matches, so create a new vuln record
195
228
unless vuln
196
229
if service
197
- vuln = service . vulns . find_by_name ( name )
230
+ if opts [ :resource ]
231
+ vuln = service . vulns . find_by ( name : name , resource : opts [ :resource ] )
232
+ else
233
+ vuln = service . vulns . find_by_name ( name )
234
+ end
198
235
else
199
- vuln = host . vulns . find_by_name ( name )
236
+ if opts [ :resource ]
237
+ vuln = host . vulns . find_by ( name : name , resource : opts [ :resource ] )
238
+ else
239
+ vuln = host . vulns . find_by_name ( name )
240
+ end
200
241
end
201
242
202
243
unless vuln
@@ -208,6 +249,7 @@ def report_vuln(opts)
208
249
}
209
250
210
251
vinf [ :service_id ] = service . id if service
252
+ vinf [ :resource ] = opts [ :resource ] if opts [ :resource ]
211
253
vuln = Mdm ::Vuln . create ( vinf )
212
254
213
255
begin
0 commit comments