From 4ab98cfe54bedcce7880cc03b1c52d5a91811860 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Unbekandt?= Date: Fri, 15 Dec 2017 17:17:15 +0100 Subject: [PATCH 1/6] vulnsrc_rhel: one vulnerability by CVE Get one vulnerability by CVE_ID for RHEL instead of one by RHSA_ID so we can have NVD metadata added to the vulnerabilities. Fixes #495 --- ext/vulnsrc/rhel/rhel.go | 28 ++++++++++------------------ ext/vulnsrc/rhel/rhel_test.go | 10 +++++----- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/ext/vulnsrc/rhel/rhel.go b/ext/vulnsrc/rhel/rhel.go index 481beabf..b5da99be 100644 --- a/ext/vulnsrc/rhel/rhel.go +++ b/ext/vulnsrc/rhel/rhel.go @@ -70,6 +70,7 @@ type definition struct { type reference struct { Source string `xml:"source,attr"` URI string `xml:"ref_url,attr"` + ID string `xml:"ref_id,attr"` } type criteria struct { @@ -198,8 +199,6 @@ func parseRHSA(ovalReader io.Reader) (vulnerabilities []database.VulnerabilityWi if len(pkgs) > 0 { vulnerability := database.VulnerabilityWithAffected{ Vulnerability: database.Vulnerability{ - Name: name(definition), - Link: link(definition), Severity: severity(definition), Description: description(definition), }, @@ -207,7 +206,15 @@ func parseRHSA(ovalReader io.Reader) (vulnerabilities []database.VulnerabilityWi for _, p := range pkgs { vulnerability.Affected = append(vulnerability.Affected, p) } - vulnerabilities = append(vulnerabilities, vulnerability) + + // One vulnerability by CVE + for _, reference := range definition.References { + if reference.Source == "CVE" { + vulnerability.Name = reference.ID + vulnerability.Link = reference.URI + vulnerabilities = append(vulnerabilities, vulnerability) + } + } } } @@ -358,21 +365,6 @@ func description(def definition) (desc string) { return } -func name(def definition) string { - return strings.TrimSpace(def.Title[:strings.Index(def.Title, ": ")]) -} - -func link(def definition) (link string) { - for _, reference := range def.References { - if reference.Source == "RHSA" { - link = reference.URI - break - } - } - - return -} - func severity(def definition) database.Severity { switch strings.TrimSpace(def.Title[strings.LastIndex(def.Title, "(")+1 : len(def.Title)-1]) { case "Low": diff --git a/ext/vulnsrc/rhel/rhel_test.go b/ext/vulnsrc/rhel/rhel_test.go index e91ec502..86136a78 100644 --- a/ext/vulnsrc/rhel/rhel_test.go +++ b/ext/vulnsrc/rhel/rhel_test.go @@ -33,8 +33,8 @@ func TestRHELParser(t *testing.T) { testFile, _ := os.Open(path + "/testdata/fetcher_rhel_test.1.xml") vulnerabilities, err := parseRHSA(testFile) if assert.Nil(t, err) && assert.Len(t, vulnerabilities, 1) { - assert.Equal(t, "RHSA-2015:1193", vulnerabilities[0].Name) - assert.Equal(t, "https://rhn.redhat.com/errata/RHSA-2015-1193.html", vulnerabilities[0].Link) + assert.Equal(t, "CVE-2015-0252", vulnerabilities[0].Name) + assert.Equal(t, "https://access.redhat.com/security/cve/CVE-2015-0252", vulnerabilities[0].Link) assert.Equal(t, database.MediumSeverity, vulnerabilities[0].Severity) assert.Equal(t, `Xerces-C is a validating XML parser written in a portable subset of C++. A flaw was found in the way the Xerces-C XML parser processed certain XML documents. A remote attacker could provide specially crafted XML input that, when parsed by an application using Xerces-C, would cause that application to crash.`, vulnerabilities[0].Description) @@ -76,9 +76,9 @@ func TestRHELParser(t *testing.T) { // Test parsing testdata/fetcher_rhel_test.2.xml testFile, _ = os.Open(path + "/testdata/fetcher_rhel_test.2.xml") vulnerabilities, err = parseRHSA(testFile) - if assert.Nil(t, err) && assert.Len(t, vulnerabilities, 1) { - assert.Equal(t, "RHSA-2015:1207", vulnerabilities[0].Name) - assert.Equal(t, "https://rhn.redhat.com/errata/RHSA-2015-1207.html", vulnerabilities[0].Link) + if assert.Nil(t, err) && assert.Len(t, vulnerabilities, 17) { + assert.Equal(t, "CVE-2015-2722", vulnerabilities[0].Name) + assert.Equal(t, "https://access.redhat.com/security/cve/CVE-2015-2722", vulnerabilities[0].Link) assert.Equal(t, database.CriticalSeverity, vulnerabilities[0].Severity) assert.Equal(t, `Mozilla Firefox is an open source web browser. XULRunner provides the XUL Runtime environment for Mozilla Firefox. Several flaws were found in the processing of malformed web content. A web page containing malicious content could cause Firefox to crash or, potentially, execute arbitrary code with the privileges of the user running Firefox.`, vulnerabilities[0].Description) From ac86a3674094f93b71e8736392b7a4707fa972fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Unbekandt?= Date: Thu, 21 Dec 2017 10:55:55 +0100 Subject: [PATCH 2/6] vulnsrc_rhel: rhsa_ID by default If no CVE is present, create a vulnerability with rhsa ID --- ext/vulnsrc/rhel/rhel.go | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/ext/vulnsrc/rhel/rhel.go b/ext/vulnsrc/rhel/rhel.go index b5da99be..54cb97cb 100644 --- a/ext/vulnsrc/rhel/rhel.go +++ b/ext/vulnsrc/rhel/rhel.go @@ -197,6 +197,8 @@ func parseRHSA(ovalReader io.Reader) (vulnerabilities []database.VulnerabilityWi for _, definition := range ov.Definitions { pkgs := toFeatures(definition.Criteria) if len(pkgs) > 0 { + + // Init vulnerability vulnerability := database.VulnerabilityWithAffected{ Vulnerability: database.Vulnerability{ Severity: severity(definition), @@ -207,11 +209,15 @@ func parseRHSA(ovalReader io.Reader) (vulnerabilities []database.VulnerabilityWi vulnerability.Affected = append(vulnerability.Affected, p) } - // One vulnerability by CVE - for _, reference := range definition.References { - if reference.Source == "CVE" { - vulnerability.Name = reference.ID - vulnerability.Link = reference.URI + // Only RHSA is present + if len(definition.References) == 1 { + vulnerability.Name = rhsaName(definition) + vulnerability.Link = definition.References[0].URI + vulnerabilities = append(vulnerabilities, vulnerability) + } else { + for _, reference := range definition.References[1:] { + vulnerability.Name = name(reference) + vulnerability.Link = link(reference) vulnerabilities = append(vulnerabilities, vulnerability) } } @@ -380,3 +386,15 @@ func severity(def definition) database.Severity { return database.UnknownSeverity } } + +func name(ref reference) string { + return ref.ID +} + +func link(ref reference) string { + return ref.URI +} + +func rhsaName(def definition) string { + return strings.TrimSpace(def.Title[:strings.Index(def.Title, ": ")]) +} From 4e4e98f328309d1c0a470388d198fa37c27e47d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Unbekandt?= Date: Fri, 22 Dec 2017 10:48:22 +0100 Subject: [PATCH 3/6] vulnsrc_rhel: minor changes Code reorganisation --- ext/vulnsrc/rhel/rhel.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/ext/vulnsrc/rhel/rhel.go b/ext/vulnsrc/rhel/rhel.go index 54cb97cb..da54df18 100644 --- a/ext/vulnsrc/rhel/rhel.go +++ b/ext/vulnsrc/rhel/rhel.go @@ -201,6 +201,8 @@ func parseRHSA(ovalReader io.Reader) (vulnerabilities []database.VulnerabilityWi // Init vulnerability vulnerability := database.VulnerabilityWithAffected{ Vulnerability: database.Vulnerability{ + Name: rhsaName(definition), + Link: rhsaLink(definition), Severity: severity(definition), Description: description(definition), }, @@ -211,13 +213,12 @@ func parseRHSA(ovalReader io.Reader) (vulnerabilities []database.VulnerabilityWi // Only RHSA is present if len(definition.References) == 1 { - vulnerability.Name = rhsaName(definition) vulnerability.Link = definition.References[0].URI vulnerabilities = append(vulnerabilities, vulnerability) } else { for _, reference := range definition.References[1:] { - vulnerability.Name = name(reference) - vulnerability.Link = link(reference) + vulnerability.Name = reference.ID + vulnerability.Link = reference.URI vulnerabilities = append(vulnerabilities, vulnerability) } } @@ -387,14 +388,13 @@ func severity(def definition) database.Severity { } } -func name(ref reference) string { - return ref.ID -} - -func link(ref reference) string { - return ref.URI -} - func rhsaName(def definition) string { return strings.TrimSpace(def.Title[:strings.Index(def.Title, ": ")]) } + +func rhsaLink(def definition) (link string) { + if len(def.References) > 0 { + link = def.References[0].URI + } + return +} From 8b3338ef56b060e27bc3d81124f52bbded315f1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Unbekandt?= Date: Fri, 22 Dec 2017 11:23:58 +0100 Subject: [PATCH 4/6] vulnsrc_rhel: minor changes delete a useless line --- ext/vulnsrc/rhel/rhel.go | 1 - 1 file changed, 1 deletion(-) diff --git a/ext/vulnsrc/rhel/rhel.go b/ext/vulnsrc/rhel/rhel.go index da54df18..c5fdb968 100644 --- a/ext/vulnsrc/rhel/rhel.go +++ b/ext/vulnsrc/rhel/rhel.go @@ -213,7 +213,6 @@ func parseRHSA(ovalReader io.Reader) (vulnerabilities []database.VulnerabilityWi // Only RHSA is present if len(definition.References) == 1 { - vulnerability.Link = definition.References[0].URI vulnerabilities = append(vulnerabilities, vulnerability) } else { for _, reference := range definition.References[1:] { From a90db713a2722a80db33e47343c4a4d417f48a0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Unbekandt?= Date: Thu, 26 Jul 2018 15:46:06 +0200 Subject: [PATCH 5/6] vulnsrc_rhel: add test Add test for multiple CVE --- ext/vulnsrc/rhel/rhel.go | 15 +++--- ext/vulnsrc/rhel/rhel_test.go | 86 ++++++++++++++++++++--------------- 2 files changed, 59 insertions(+), 42 deletions(-) diff --git a/ext/vulnsrc/rhel/rhel.go b/ext/vulnsrc/rhel/rhel.go index c5fdb968..e87e48bd 100644 --- a/ext/vulnsrc/rhel/rhel.go +++ b/ext/vulnsrc/rhel/rhel.go @@ -214,13 +214,16 @@ func parseRHSA(ovalReader io.Reader) (vulnerabilities []database.VulnerabilityWi // Only RHSA is present if len(definition.References) == 1 { vulnerabilities = append(vulnerabilities, vulnerability) - } else { - for _, reference := range definition.References[1:] { - vulnerability.Name = reference.ID - vulnerability.Link = reference.URI - vulnerabilities = append(vulnerabilities, vulnerability) - } + continue } + + // Create one vulnerability by CVE + for _, reference := range definition.References[1:] { + vulnerability.Name = reference.ID + vulnerability.Link = reference.URI + vulnerabilities = append(vulnerabilities, vulnerability) + } + } } diff --git a/ext/vulnsrc/rhel/rhel_test.go b/ext/vulnsrc/rhel/rhel_test.go index 86136a78..3d5340d4 100644 --- a/ext/vulnsrc/rhel/rhel_test.go +++ b/ext/vulnsrc/rhel/rhel_test.go @@ -15,6 +15,7 @@ package rhel import ( + "fmt" "os" "path/filepath" "runtime" @@ -25,7 +26,55 @@ import ( "github.com/stretchr/testify/assert" ) -func TestRHELParser(t *testing.T) { +func TestRHELParserMultipleCVE(t *testing.T) { + _, filename, _, _ := runtime.Caller(0) + path := filepath.Join(filepath.Dir(filename)) + + // Test parsing testdata/fetcher_rhel_test.2.xml + testFile, _ := os.Open(path + "/testdata/fetcher_rhel_test.2.xml") + vulnerabilities, err := parseRHSA(testFile) + + // Expected + expectedCve := []string{"CVE-2015-2722", "CVE-2015-2724", "CVE-2015-2725", "CVE-2015-2727", "CVE-2015-2728", + "CVE-2015-2729", "CVE-2015-2731", "CVE-2015-2733", "CVE-2015-2734", "CVE-2015-2735", "CVE-2015-2736", + "CVE-2015-2737", "CVE-2015-2738", "CVE-2015-2739", "CVE-2015-2740", "CVE-2015-2741", "CVE-2015-2743", + } + expectedFeatures := []database.AffectedFeature{ + { + Namespace: database.Namespace{ + Name: "centos:6", + VersionFormat: rpm.ParserName, + }, + FeatureName: "firefox", + FixedInVersion: "0:38.1.0-1.el6_6", + AffectedVersion: "0:38.1.0-1.el6_6", + }, + { + Namespace: database.Namespace{ + Name: "centos:7", + VersionFormat: rpm.ParserName, + }, + FeatureName: "firefox", + FixedInVersion: "0:38.1.0-1.el7_1", + AffectedVersion: "0:38.1.0-1.el7_1", + }, + } + + if assert.Nil(t, err) && assert.Len(t, vulnerabilities, len(expectedCve)) { + + for i, vulnerability := range vulnerabilities { + assert.Equal(t, expectedCve[i], vulnerability.Name) + assert.Equal(t, fmt.Sprintf("https://access.redhat.com/security/cve/%s", expectedCve[i]), vulnerability.Link) + assert.Equal(t, database.CriticalSeverity, vulnerability.Severity) + assert.Equal(t, `Mozilla Firefox is an open source web browser. XULRunner provides the XUL Runtime environment for Mozilla Firefox. Several flaws were found in the processing of malformed web content. A web page containing malicious content could cause Firefox to crash or, potentially, execute arbitrary code with the privileges of the user running Firefox.`, vulnerability.Description) + + for _, expectedFeature := range expectedFeatures { + assert.Contains(t, vulnerability.Affected, expectedFeature) + } + } + } +} +func TestRHELParserOneCVE(t *testing.T) { _, filename, _, _ := runtime.Caller(0) path := filepath.Join(filepath.Dir(filename)) @@ -72,39 +121,4 @@ func TestRHELParser(t *testing.T) { assert.Contains(t, vulnerabilities[0].Affected, expectedFeature) } } - - // Test parsing testdata/fetcher_rhel_test.2.xml - testFile, _ = os.Open(path + "/testdata/fetcher_rhel_test.2.xml") - vulnerabilities, err = parseRHSA(testFile) - if assert.Nil(t, err) && assert.Len(t, vulnerabilities, 17) { - assert.Equal(t, "CVE-2015-2722", vulnerabilities[0].Name) - assert.Equal(t, "https://access.redhat.com/security/cve/CVE-2015-2722", vulnerabilities[0].Link) - assert.Equal(t, database.CriticalSeverity, vulnerabilities[0].Severity) - assert.Equal(t, `Mozilla Firefox is an open source web browser. XULRunner provides the XUL Runtime environment for Mozilla Firefox. Several flaws were found in the processing of malformed web content. A web page containing malicious content could cause Firefox to crash or, potentially, execute arbitrary code with the privileges of the user running Firefox.`, vulnerabilities[0].Description) - - expectedFeatures := []database.AffectedFeature{ - { - Namespace: database.Namespace{ - Name: "centos:6", - VersionFormat: rpm.ParserName, - }, - FeatureName: "firefox", - FixedInVersion: "0:38.1.0-1.el6_6", - AffectedVersion: "0:38.1.0-1.el6_6", - }, - { - Namespace: database.Namespace{ - Name: "centos:7", - VersionFormat: rpm.ParserName, - }, - FeatureName: "firefox", - FixedInVersion: "0:38.1.0-1.el7_1", - AffectedVersion: "0:38.1.0-1.el7_1", - }, - } - - for _, expectedFeature := range expectedFeatures { - assert.Contains(t, vulnerabilities[0].Affected, expectedFeature) - } - } } From c4ffa0c370e793546dd51ea25fc98961c2d25970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Unbekandt?= Date: Fri, 27 Jul 2018 11:48:41 +0200 Subject: [PATCH 6/6] vulnsrc_rhel: cve impact use the specific CVE's impact field instead of the RHSA's one --- ext/vulnsrc/rhel/rhel.go | 28 ++++++++++----- ext/vulnsrc/rhel/rhel_test.go | 7 +++- .../rhel/testdata/fetcher_rhel_test.2.xml | 34 +++++++++---------- 3 files changed, 43 insertions(+), 26 deletions(-) diff --git a/ext/vulnsrc/rhel/rhel.go b/ext/vulnsrc/rhel/rhel.go index e87e48bd..b35f5639 100644 --- a/ext/vulnsrc/rhel/rhel.go +++ b/ext/vulnsrc/rhel/rhel.go @@ -65,6 +65,8 @@ type definition struct { Description string `xml:"metadata>description"` References []reference `xml:"metadata>reference"` Criteria criteria `xml:"criteria"` + Severity string `xml:"metadata>advisory>severity"` + Cves []cve `xml:"metadata>advisory>cve"` } type reference struct { @@ -73,6 +75,12 @@ type reference struct { ID string `xml:"ref_id,attr"` } +type cve struct { + Impact string `xml:"impact,attr"` + Href string `xml:"href,attr"` + ID string `xml:",chardata"` +} + type criteria struct { Operator string `xml:"operator,attr"` Criterias []*criteria `xml:"criteria"` @@ -203,7 +211,7 @@ func parseRHSA(ovalReader io.Reader) (vulnerabilities []database.VulnerabilityWi Vulnerability: database.Vulnerability{ Name: rhsaName(definition), Link: rhsaLink(definition), - Severity: severity(definition), + Severity: severity(definition.Severity), Description: description(definition), }, } @@ -218,12 +226,16 @@ func parseRHSA(ovalReader io.Reader) (vulnerabilities []database.VulnerabilityWi } // Create one vulnerability by CVE - for _, reference := range definition.References[1:] { - vulnerability.Name = reference.ID - vulnerability.Link = reference.URI + for _, currentCve := range definition.Cves { + vulnerability.Name = currentCve.ID + vulnerability.Link = currentCve.Href + if currentCve.Impact != "" { + vulnerability.Severity = severity(currentCve.Impact) + } else { + vulnerability.Severity = severity(definition.Severity) + } vulnerabilities = append(vulnerabilities, vulnerability) } - } } @@ -374,8 +386,8 @@ func description(def definition) (desc string) { return } -func severity(def definition) database.Severity { - switch strings.TrimSpace(def.Title[strings.LastIndex(def.Title, "(")+1 : len(def.Title)-1]) { +func severity(sev string) database.Severity { + switch strings.Title(sev) { case "Low": return database.LowSeverity case "Moderate": @@ -385,7 +397,7 @@ func severity(def definition) database.Severity { case "Critical": return database.CriticalSeverity default: - log.Warningf("could not determine vulnerability severity from: %s.", def.Title) + log.Warningf("could not determine vulnerability severity from: %s.", sev) return database.UnknownSeverity } } diff --git a/ext/vulnsrc/rhel/rhel_test.go b/ext/vulnsrc/rhel/rhel_test.go index 3d5340d4..5ac3e108 100644 --- a/ext/vulnsrc/rhel/rhel_test.go +++ b/ext/vulnsrc/rhel/rhel_test.go @@ -39,6 +39,11 @@ func TestRHELParserMultipleCVE(t *testing.T) { "CVE-2015-2729", "CVE-2015-2731", "CVE-2015-2733", "CVE-2015-2734", "CVE-2015-2735", "CVE-2015-2736", "CVE-2015-2737", "CVE-2015-2738", "CVE-2015-2739", "CVE-2015-2740", "CVE-2015-2741", "CVE-2015-2743", } + expectedSeverity := []database.Severity{database.CriticalSeverity, database.HighSeverity, database.HighSeverity, + database.MediumSeverity, database.MediumSeverity, database.MediumSeverity, database.CriticalSeverity, + database.CriticalSeverity, database.CriticalSeverity, database.CriticalSeverity, database.CriticalSeverity, + database.CriticalSeverity, database.CriticalSeverity, database.CriticalSeverity, database.CriticalSeverity, + database.MediumSeverity, database.MediumSeverity} expectedFeatures := []database.AffectedFeature{ { Namespace: database.Namespace{ @@ -65,7 +70,7 @@ func TestRHELParserMultipleCVE(t *testing.T) { for i, vulnerability := range vulnerabilities { assert.Equal(t, expectedCve[i], vulnerability.Name) assert.Equal(t, fmt.Sprintf("https://access.redhat.com/security/cve/%s", expectedCve[i]), vulnerability.Link) - assert.Equal(t, database.CriticalSeverity, vulnerability.Severity) + assert.Equal(t, expectedSeverity[i], vulnerability.Severity) assert.Equal(t, `Mozilla Firefox is an open source web browser. XULRunner provides the XUL Runtime environment for Mozilla Firefox. Several flaws were found in the processing of malformed web content. A web page containing malicious content could cause Firefox to crash or, potentially, execute arbitrary code with the privileges of the user running Firefox.`, vulnerability.Description) for _, expectedFeature := range expectedFeatures { diff --git a/ext/vulnsrc/rhel/testdata/fetcher_rhel_test.2.xml b/ext/vulnsrc/rhel/testdata/fetcher_rhel_test.2.xml index 32f5aa5d..ed1816be 100644 --- a/ext/vulnsrc/rhel/testdata/fetcher_rhel_test.2.xml +++ b/ext/vulnsrc/rhel/testdata/fetcher_rhel_test.2.xml @@ -50,23 +50,23 @@ Firefox. Copyright 2015 Red Hat, Inc. - CVE-2015-2722 - CVE-2015-2724 - CVE-2015-2725 - CVE-2015-2727 - CVE-2015-2728 - CVE-2015-2729 - CVE-2015-2731 - CVE-2015-2733 - CVE-2015-2734 - CVE-2015-2735 - CVE-2015-2736 - CVE-2015-2737 - CVE-2015-2738 - CVE-2015-2739 - CVE-2015-2740 - CVE-2015-2741 - CVE-2015-2743 + CVE-2015-2722 + CVE-2015-2724 + CVE-2015-2725 + CVE-2015-2727 + CVE-2015-2728 + CVE-2015-2729 + CVE-2015-2731 + CVE-2015-2733 + CVE-2015-2734 + CVE-2015-2735 + CVE-2015-2736 + CVE-2015-2737 + CVE-2015-2738 + CVE-2015-2739 + CVE-2015-2740 + CVE-2015-2741 + CVE-2015-2743 CVE-2015-2724 CVE-2015-2725 Mozilla: Miscellaneous memory safety hazards (rv:31.8 / rv:38.1) (MFSA 2015-59) CVE-2015-2727 Mozilla: Local files or privileged URLs in pages can be opened into new tabs (MFSA 2015-60) CVE-2015-2728 Mozilla: Type confusion in Indexed Database Manager (MFSA 2015-61)