Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 11 additions & 22 deletions detector/detector.go
Original file line number Diff line number Diff line change
Expand Up @@ -397,12 +397,12 @@ func DetectWordPressCves(r *models.ScanResult, wpCnf config.WpScanConf) error {
return nil
}

// FillCvesWithGoCVEDictionary fills CVE detail with VulnCheck, JVN, Fortinet
// FillCvesWithGoCVEDictionary fills CVE detail with VulnCheck, JVN
// (NVD CveContent, EUVD, and MITRE are filled by the vuls2 enrich path instead, as are the US-CERT
// alerts; Cisco and Palo Alto are detected by vuls2, which always emits a CveContent and
// additionally a DistroAdvisory when the matched root carries advisories (Cisco roots always do;
// Palo Alto's PAN-SA roots do — their advisory fallback yields both a DistroAdvisory and an
// advisory-derived CveContent — while its plain CVE roots yield a CveContent only); only the
// alerts; Cisco, Palo Alto, and Fortinet are detected by vuls2, which always emits a CveContent and
// additionally a DistroAdvisory when the matched root carries advisories (Cisco and Fortinet roots
// always do; Palo Alto's PAN-SA roots do — their advisory fallback yields both a DistroAdvisory and
// an advisory-derived CveContent — while its plain CVE roots yield a CveContent only); only the
// JP-CERT alerts, derived from JVN, still come from here)
func FillCvesWithGoCVEDictionary(r *models.ScanResult, cnf config.GoCveDictConf, logOpts logging.LogOpts) (err error) {
cveIDs := make([]string, 0, len(r.ScannedCves))
Expand All @@ -428,7 +428,6 @@ func FillCvesWithGoCVEDictionary(r *models.ScanResult, cnf config.GoCveDictConf,
for _, d := range ds {
vulnchecks := models.ConvertVulncheckToModel(d.CveID, d.Vulnchecks)
jvns := models.ConvertJvnToModel(d.CveID, d.Jvns)
fortinets := models.ConvertFortinetToModel(d.CveID, d.Fortinets)

alerts := fillCertAlerts(&d)
for cveID, vinfo := range r.ScannedCves {
Expand All @@ -444,7 +443,7 @@ func FillCvesWithGoCVEDictionary(r *models.ScanResult, cnf config.GoCveDictConf,
for _, con := range vulnchecks {
vinfo.CveContents[con.Type] = append(vinfo.CveContents[con.Type], con)
}
for _, cons := range [][]models.CveContent{jvns, fortinets} {
for _, cons := range [][]models.CveContent{jvns} {
for _, con := range cons {
if !con.Empty() {
if !slices.ContainsFunc(vinfo.CveContents[con.Type], func(e models.CveContent) bool {
Expand Down Expand Up @@ -542,29 +541,18 @@ func detectCpeURIsCvesWithGoCVEDictionary(r *models.ScanResult, cpes []Cpe, cnf
for _, detail := range details {
// Skip detections carried by no dictionary-remaining DETECTION
// source. The list mirrors go-cve-dictionary's GetByCpeURI
// admission gate minus the vuls2-migrated sources (NVD, Cisco, and
// Palo Alto), so NVD-only / Cisco-only / Palo Alto-only detections
// disappear here — vuls2 re-detects them from its own data. EUVD /
// admission gate minus the vuls2-migrated sources (NVD, Cisco,
// Palo Alto, and Fortinet), so detections carried only by those
// sources disappear here — vuls2 re-detects them from its own data. EUVD /
// MITRE contents can ride along on a detail but are never a
// detection basis (gocve neither matches nor admits on them, and
// getMaxConfidence has no tier for them), so they do not keep
// a detail alive.
if !detail.HasJvn() && !detail.HasFortinet() && !detail.HasVulncheck() {
if !detail.HasJvn() && !detail.HasVulncheck() {
continue
}

advisories := []models.DistroAdvisory{}
if detail.HasFortinet() {
for _, fortinet := range detail.Fortinets {
advisories = append(advisories, models.DistroAdvisory{
AdvisoryID: fortinet.AdvisoryID,
Issued: fortinet.PublishedDate,
Updated: fortinet.LastModifiedDate,
Description: fortinet.Summary,
})
}
}

// JVN advisories are redundant for CVEs that NVD also covers.
if !detail.HasNvd() && detail.HasJvn() {
for _, jvn := range detail.Jvns {
Expand All @@ -586,6 +574,7 @@ func detectCpeURIsCvesWithGoCVEDictionary(r *models.ScanResult, cpes []Cpe, cnf
detail.Nvds = nil
detail.Ciscos = nil
detail.Paloaltos = nil
detail.Fortinets = nil
maxConfidence := getMaxConfidence(detail)

if val, ok := r.ScannedCves[detail.CveID]; ok {
Expand Down
16 changes: 10 additions & 6 deletions detector/vuls2/vendor.go
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ func advisoryReference(e ecosystemTypes.Ecosystem, s sourceTypes.SourceID, da mo
Source: "JVN",
RefID: da.AdvisoryID,
}, nil
case sourceTypes.Fortinet:
case sourceTypes.FortinetCVRF, sourceTypes.FortinetCSAF:
return models.Reference{
Link: fmt.Sprintf("https://www.fortiguard.com/psirt/%s", da.AdvisoryID),
Source: "FORTINET",
Expand Down Expand Up @@ -642,6 +642,10 @@ func cveContentSourceLink(ccType models.CveContentType, v vulnerabilityTypes.Vul
// Palo Alto publishes a page per CVE, so the source link is keyed by the
// CVE ID (which is the vulnerability content ID, e.g. CVE-2022-0778).
return fmt.Sprintf("https://security.paloaltonetworks.com/%s", v.Content.ID)
case models.Fortinet:
// Fortinet content lives in the PSIRT advisory, whose ID is the root ID
// (e.g. FG-IR-24-041), so the per-CVE source link points at that page.
return fmt.Sprintf("https://www.fortiguard.com/psirt/%s", rootID)
case models.RedHat, models.RedHatAPI:
return fmt.Sprintf("https://access.redhat.com/security/cve/%s", v.Content.ID)
case models.Oracle:
Expand Down Expand Up @@ -696,9 +700,9 @@ func compareSourceID(e ecosystemTypes.Ecosystem, a, b sourceTypes.SourceID) int
case ecosystemTypes.EcosystemTypeCPE:
preferenceFn := func(sourceID sourceTypes.SourceID) int {
switch sourceID {
case sourceTypes.NVDAPICVE, sourceTypes.JVNFeedDetail, sourceTypes.Fortinet, sourceTypes.PaloAltoCSAF, sourceTypes.CiscoCSAF:
case sourceTypes.NVDAPICVE, sourceTypes.JVNFeedDetail, sourceTypes.FortinetCSAF, sourceTypes.PaloAltoCSAF, sourceTypes.CiscoCSAF:
return 5
case sourceTypes.NVDFeedCVEv2, sourceTypes.JVNFeedRSS, sourceTypes.PaloAltoJSON, sourceTypes.CiscoCVRF:
case sourceTypes.NVDFeedCVEv2, sourceTypes.JVNFeedRSS, sourceTypes.FortinetCVRF, sourceTypes.PaloAltoJSON, sourceTypes.CiscoCVRF:
return 4
case sourceTypes.NVDFeedCVEv1:
return 3
Expand Down Expand Up @@ -879,7 +883,7 @@ func toCveContentType(e ecosystemTypes.Ecosystem, s sourceTypes.SourceID) models
return models.Nvd
case sourceTypes.JVNFeedRSS, sourceTypes.JVNFeedDetail:
return models.Jvn
case sourceTypes.Fortinet:
case sourceTypes.FortinetCVRF, sourceTypes.FortinetCSAF:
return models.Fortinet
case sourceTypes.PaloAltoCSAF, sourceTypes.PaloAltoJSON, sourceTypes.PaloAltoList:
return models.Paloalto
Expand Down Expand Up @@ -1042,7 +1046,7 @@ func toVuls0Confidence(e ecosystemTypes.Ecosystem, s sourceTypes.SourceID, sd so
return models.NvdVendorProductMatch
case sourceTypes.JVNFeedRSS, sourceTypes.JVNFeedDetail:
return models.JvnVendorProductMatch
case sourceTypes.Fortinet:
case sourceTypes.FortinetCVRF, sourceTypes.FortinetCSAF:
return models.FortinetVendorProductMatch
case sourceTypes.PaloAltoCSAF, sourceTypes.PaloAltoJSON, sourceTypes.PaloAltoList:
return models.PaloaltoVendorProductMatch
Expand All @@ -1067,7 +1071,7 @@ func toVuls0Confidence(e ecosystemTypes.Ecosystem, s sourceTypes.SourceID, sd so
// VendorProductMatch branch above. Mapped to JvnVendorProductMatch
// for safety should that demotion ever change.
return models.JvnVendorProductMatch
case sourceTypes.Fortinet:
case sourceTypes.FortinetCVRF, sourceTypes.FortinetCSAF:
return models.FortinetExactVersionMatch
case sourceTypes.PaloAltoCSAF, sourceTypes.PaloAltoJSON, sourceTypes.PaloAltoList:
return models.PaloaltoExactVersionMatch
Expand Down
Loading
Loading