@@ -40,7 +40,7 @@ type UserDeviceFinding struct {
4040 Mitigations []string
4141}
4242
43- func getUniqueDeviceID (hostInfo models.DomainAPIVulnerabilityHostInfoV2 ) (string , error ) {
43+ func getUniqueDeviceID (hostInfo models.DomainAPIVulnerabilityHostFacetV2 ) (string , error ) {
4444 b , err := json .Marshal (& hostInfo )
4545 if err != nil {
4646 return "" , err
@@ -118,11 +118,21 @@ func appendUnique(main, adder []string) []string {
118118 return main
119119}
120120
121- func remove (a []string , i int ) []string {
122- a [i ] = a [len (a )- 1 ] // Copy last element to index i.
123- a [len (a )- 1 ] = "" // Erase last element (write zero value).
124- a = a [:len (a )- 1 ] // Truncate slice.
125- return a
121+ func getSeverityScore (severity string ) (int , error ) {
122+ switch strings .TrimSpace (strings .ToLower (severity )) {
123+ case "" :
124+ return 0 , nil
125+ case "low" :
126+ return 0 , nil
127+ case "medium" :
128+ return 1 , nil
129+ case "high" :
130+ return 2 , nil
131+ case "critical" :
132+ return 3 , nil
133+ }
134+
135+ return - 1 , errors .New ("unknown severity: " + severity )
126136}
127137
128138func GetMessages (config * config.Config , ctx context.Context ) (results map [string ]FalconResult , err error ) {
@@ -140,11 +150,12 @@ func GetMessages(config *config.Config, ctx context.Context) (results map[string
140150 return nil , errors .Wrap (err , "could not initialize Falcon client" )
141151 }
142152
143- queryResult , err := client .SpotlightVulnerabilities .QueryVulnerabilities (
144- & spotlight_vulnerabilities.QueryVulnerabilitiesParams {
153+ queryResult , err := client .SpotlightVulnerabilities .CombinedQueryVulnerabilities (
154+ & spotlight_vulnerabilities.CombinedQueryVulnerabilitiesParams {
145155 Context : ctx ,
146156 Filter : "status:'open'" ,
147157 Limit : & falconAPIMaxRecords ,
158+ Facet : []string {"host_info" , "cve" , "remediation" },
148159 },
149160 )
150161 if err != nil {
@@ -155,137 +166,148 @@ func GetMessages(config *config.Config, ctx context.Context) (results map[string
155166 return nil , errors .New ("QueryVulnerabilities result was nil" )
156167 }
157168
158- var vulnIDs []string
159- vulnIDs = append (vulnIDs , queryResult .GetPayload ().Resources ... )
160-
161- if len (vulnIDs ) == 0 {
162- return results , nil
163- }
164-
165- logrus .WithField ("vulns" , len (vulnIDs )).Info ("found vulnerabilities" )
166-
167- getResult , err := client .SpotlightVulnerabilities .GetVulnerabilities (
168- & spotlight_vulnerabilities.GetVulnerabilitiesParams {
169- Ids : vulnIDs ,
170- Context : context .Background (),
171- },
172- )
173- if err != nil || getResult == nil {
174- return nil , errors .Wrap (err , "could not get Falcon vulnerabilities" )
175- }
176-
177- if len (getResult .GetPayload ().Resources ) != len (vulnIDs ) {
178- logrus .Warn ("result payload not as large as vuln list" )
179- }
180-
181169 var hostTags []string
182170 devices := map [string ]UserDevice {}
183171
184- var mitigationIDs []string
185-
186- for _ , vuln := range getResult .GetPayload ().Resources {
172+ minExpertAIScore := 0
173+ if newScore , err := getSeverityScore (config .Falcon .MinExprtAISeverity ); err != nil {
174+ return nil , errors .Wrap (err , "unknown minimum exprtai severity specified" )
175+ } else { minExpertAIScore = newScore }
187176
188- if len (vuln .Remediation .Ids ) == 0 && config .Falcon .SkipNoMitigation {
189- logrus .WithField ("app" , * vuln .App .ProductNameVersion ).
190- Debug ("skipping vulnerability without remediation" )
177+ for _ , vuln := range queryResult .GetPayload ().Resources {
191178
179+ if vuln .Apps == nil {
192180 continue
193181 }
194182
195- if * vuln .Cve .ID != "" && len (config .Falcon .SkipCVEs ) > 0 {
196- vulnIgnore := false
183+ for _ , vulnApp := range vuln .Apps {
197184
198- for _ , cve := range config .Falcon .SkipCVEs {
199- if strings .EqualFold (cve , * vuln .Cve .ID ) {
200- vulnIgnore = true
201- break
202- }
203- }
185+ if (vulnApp .Remediation == nil || len (vulnApp .Remediation .Ids ) == 0 ) && config .Falcon .SkipNoMitigation {
186+ logrus .WithField ("rem" , fmt .Sprintf ("%+v" , vulnApp .Remediation )).Debug ("rem" )
187+
188+ logrus .WithField ("app" , vulnApp .ProductNameVersion ).
189+ Debug ("skipping vulnerability without remediation" )
204190
205- if vulnIgnore {
206- logrus .WithField ("cve" , * vuln .Cve .ID ).WithField ("host" , * vuln .HostInfo .Hostname ).
207- Warn ("skipping CVE" )
208191 continue
209192 }
210- }
211193
212- mitigationIDs = appendUnique (mitigationIDs , vuln .Remediation .Ids )
194+ if * vuln .Cve .ID != "" && len (config .Falcon .SkipCVEs ) > 0 {
195+ vulnIgnore := false
213196
214- uniqueDeviceID , err := getUniqueDeviceID (* vuln .HostInfo )
215- if err != nil {
216- logrus .WithError (err ).Error ("could not calculate unique device id" )
197+ for _ , cve := range config .Falcon .SkipCVEs {
198+ if strings .EqualFold (cve , * vuln .Cve .ID ) {
199+ vulnIgnore = true
200+ break
201+ }
202+ }
217203
218- continue
219- }
204+ if vulnIgnore {
205+ logrus .WithField ("cve" , * vuln .Cve .ID ).
206+ WithField ("host" , * vuln .HostInfo .Hostname ).
207+ Warn ("skipping CVE" )
208+ continue
209+ }
210+ }
211+
212+ uniqueDeviceID , err := getUniqueDeviceID (* vuln .HostInfo )
213+ if err != nil {
214+ logrus .WithError (err ).Error ("could not calculate unique device id" )
220215
221- if config .Falcon .MinCVEBaseScore > 0 {
222- if int (* vuln .Cve .BaseScore ) < config .Falcon .MinCVEBaseScore {
223- logrus .WithField ("cve_score" , * vuln .Cve .BaseScore ).Debug ("skipping vulnerability" )
224216 continue
225217 }
226- }
227218
228- if len (config .Falcon .SkipSeverities ) > 0 {
229- vulnSev := strings .ToLower (* vuln .Cve .Severity )
230- skip := false
219+ if config .Falcon .MinCVEBaseScore > 0 {
220+ if int (vuln .Cve .BaseScore ) < config .Falcon .MinCVEBaseScore {
221+ logrus .WithField ("cve_score" , vuln .Cve .BaseScore ).Debug ("skipping vulnerability" )
222+ continue
223+ }
224+ }
231225
232- for _ , sev := range config .Falcon .SkipSeverities {
233- if strings .EqualFold (sev , vulnSev ) {
234- logrus .WithField ("host" , * vuln .HostInfo .Hostname ).WithField ("cve_score" , * vuln .Cve .BaseScore ).
235- WithField ("severity" , * vuln .Cve .Severity ).WithField ("cve" , * vuln .Cve .ID ).
236- Debug ("skipping vulnerability" )
237- skip = true
238- break
226+ if config .Falcon .MinExprtAISeverity != "" {
227+ vulnExpertAISevScore , err := getSeverityScore (config .Falcon .MinExprtAISeverity )
228+ if err != nil {
229+ logrus .WithField ("exprtai_score" , vuln .Cve .ExprtRating ).WithError (err ).
230+ Error ("unknown exprtai score" )
231+ } else {
232+ if vulnExpertAISevScore < minExpertAIScore {
233+ logrus .WithField ("min_exprtai_severity" , config .Falcon .MinExprtAISeverity ).
234+ WithField ("exprtai_severity" , vuln .Cve .ExprtRating ).Debug ("skipping vulnerability" )
235+ continue
236+ }
239237 }
240238 }
241239
242- if skip { continue }
243- }
240+ if len (config .Falcon .SkipSeverities ) > 0 {
241+ vulnSev := strings .ToLower (vuln .Cve .Severity )
242+ skip := false
243+
244+ for _ , sev := range config .Falcon .SkipSeverities {
245+ if strings .EqualFold (sev , vulnSev ) {
246+ logrus .WithField ("host" , * vuln .HostInfo .Hostname ).WithField ("cve_score" , vuln .Cve .BaseScore ).
247+ WithField ("severity" , vuln .Cve .Severity ).WithField ("cve" , * vuln .Cve .ID ).
248+ Debug ("skipping vulnerability" )
249+ skip = true
250+ break
251+ }
252+ }
253+
254+ if skip {
255+ continue
256+ }
257+ }
244258
245- logrus .WithField ("host" , * vuln .HostInfo .Hostname ).WithField ("cve_score" , * vuln .Cve .BaseScore ).
246- WithField ("severity" , * vuln .Cve .Severity ).WithField ("cve" , * vuln .Cve .ID ).
247- Debug ("adding vulnerability" )
259+ logrus .WithField ("host" , * vuln .HostInfo .Hostname ).WithField ("cve_score" , vuln .Cve .BaseScore ).
260+ WithField ("severity" , vuln .Cve .Severity ).WithField ("cve" , * vuln .Cve .ID ).
261+ Debug ("adding vulnerability" )
248262
249- deviceFinding := UserDeviceFinding {
250- ProductName : * vuln .App .ProductNameVersion ,
251- CveID : * vuln .Cve .ID ,
252- CveSeverity : * vuln .Cve .Severity ,
253- TimestampFound : * vuln .CreatedTimestamp ,
254- Mitigations : vuln .Remediation .Ids ,
255- }
263+ deviceFinding := UserDeviceFinding {
264+ ProductName : * vulnApp .ProductNameVersion ,
265+ CveID : * vuln .Cve .ID ,
266+ CveSeverity : vuln .Cve .Severity ,
267+ TimestampFound : * vuln .CreatedTimestamp ,
268+ }
256269
257- if _ , ok := devices [uniqueDeviceID ]; ! ok {
258- devices [uniqueDeviceID ] = UserDevice {
259- MachineName : fmt .Sprintf (
260- "%s %s" ,
261- * vuln .HostInfo .OsVersion ,
262- * vuln .HostInfo .Hostname ,
263- ),
264- Tags : vuln .HostInfo .Tags ,
265- Findings : []UserDeviceFinding {},
270+ for _ , mitigation := range vuln .Remediation .Entities {
271+ if strings .HasPrefix (strings .ToLower (* mitigation .Action ), "no fix available for " ) {
272+ continue
273+ }
274+
275+ deviceFinding .Mitigations = appendUnique (deviceFinding .Mitigations , []string {* mitigation .Action })
276+ }
277+
278+ if _ , ok := devices [uniqueDeviceID ]; ! ok {
279+ devices [uniqueDeviceID ] = UserDevice {
280+ MachineName : fmt .Sprintf (
281+ "%s %s" ,
282+ * vuln .HostInfo .OsVersion ,
283+ * vuln .HostInfo .Hostname ,
284+ ),
285+ Tags : vuln .HostInfo .Tags ,
286+ Findings : []UserDeviceFinding {},
287+ }
266288 }
267- }
268289
269- device := devices [uniqueDeviceID ]
290+ device := devices [uniqueDeviceID ]
270291
271- findingExists := false
292+ findingExists := false
272293
273- for _ , finding := range device .Findings {
274- if strings .EqualFold (finding .ProductName , deviceFinding .ProductName ) {
275- findingExists = true
276- break
294+ for _ , finding := range device .Findings {
295+ if strings .EqualFold (finding .ProductName , deviceFinding .ProductName ) {
296+ findingExists = true
297+ break
298+ }
277299 }
278- }
279300
280- if ! findingExists {
281- device .Findings = append (device .Findings , deviceFinding )
282- }
301+ if ! findingExists {
302+ device .Findings = append (device .Findings , deviceFinding )
303+ }
283304
284- device .Tags = appendUnique (device .Tags , vuln .HostInfo .Tags )
305+ device .Tags = appendUnique (device .Tags , vuln .HostInfo .Tags )
285306
286- devices [uniqueDeviceID ] = device
307+ devices [uniqueDeviceID ] = device
287308
288- hostTags = append (hostTags , device .Tags ... )
309+ hostTags = append (hostTags , device .Tags ... )
310+ }
289311 }
290312
291313 if len (devices ) == 0 {
@@ -296,43 +318,6 @@ func GetMessages(config *config.Config, ctx context.Context) (results map[string
296318 return nil , errors .New ("no tags found on decices" )
297319 }
298320
299- logrus .WithField ("remediations" , len (mitigationIDs )).Debug ("retrieving remediations" )
300-
301- remResp , err := client .SpotlightVulnerabilities .GetRemediationsV2 (& spotlight_vulnerabilities.GetRemediationsV2Params {
302- Ids : mitigationIDs ,
303- Context : ctx ,
304- })
305-
306- if err != nil {
307- return nil , errors .Wrap (err , "could not retrieve remediations" )
308- }
309-
310- remediations := make (map [string ]string )
311-
312- for _ , remRes := range remResp .GetPayload ().Resources {
313- logrus .Tracef ("%s -> %s" , * remRes .ID , * remRes .Action )
314- remediations [* remRes .ID ] = * remRes .Action
315- }
316-
317- // remove useless mitigations that start with 'no fix available for'
318- for a , device := range devices {
319- for b , finding := range device .Findings {
320- for c , rem := range finding .Mitigations {
321- remText , remFound := remediations [rem ]
322-
323- if ! remFound || strings .HasPrefix (strings .ToLower (remText ), "no fix available for" ) {
324- logrus .WithField ("rem" , rem ).WithField ("rem_text" , remText ).WithField ("device" , device .MachineName ).
325- Warn ("skipping mitigation" )
326-
327- devices [a ].Findings [b ].Mitigations = remove (finding .Mitigations , c )
328- continue
329- }
330-
331- finding .Mitigations [c ] = remText
332- }
333- }
334- }
335-
336321 logrus .WithField ("devices" , len (devices )).Info ("found vulnerable devices" )
337322
338323 for _ , device := range devices {
0 commit comments