From aab46f5658cf5a75262945033cb41d93af5f2131 Mon Sep 17 00:00:00 2001 From: Kate Murphy Date: Tue, 16 Oct 2018 18:42:15 -0400 Subject: [PATCH 1/7] ext: Parse NVD JSON feed instead of XML The JSON feed provides some values that are not available in the XML feed such as CVSSv3. --- ext/vulnmdsrc/nvd/{xml.go => json.go} | 57 +++++++++++++++++---------- ext/vulnmdsrc/nvd/nvd.go | 15 +++---- 2 files changed, 45 insertions(+), 27 deletions(-) rename ext/vulnmdsrc/nvd/{xml.go => json.go} (62%) diff --git a/ext/vulnmdsrc/nvd/xml.go b/ext/vulnmdsrc/nvd/json.go similarity index 62% rename from ext/vulnmdsrc/nvd/xml.go rename to ext/vulnmdsrc/nvd/json.go index 31ca35a2..306bfc27 100644 --- a/ext/vulnmdsrc/nvd/xml.go +++ b/ext/vulnmdsrc/nvd/json.go @@ -22,27 +22,39 @@ import ( ) type nvd struct { - Entries []nvdEntry `xml:"entry"` + Entries []nvdEntry `json:"CVE_Items"` } type nvdEntry struct { - Name string `xml:"http://scap.nist.gov/schema/vulnerability/0.4 cve-id"` - CVSS nvdCVSS `xml:"http://scap.nist.gov/schema/vulnerability/0.4 cvss"` - PublishedDateTime string `xml:"http://scap.nist.gov/schema/vulnerability/0.4 published-datetime"` + CVE nvdCVE `json:"cve"` + Impact nvdImpact `json:"impact"` + PublishedDateTime string `json:"publishedDate"` } -type nvdCVSS struct { - BaseMetrics nvdCVSSBaseMetrics `xml:"http://scap.nist.gov/schema/cvss-v2/0.2 base_metrics"` +type nvdCVE struct { + Metadata nvdCVEMetadata `json:"CVE_data_meta"` } -type nvdCVSSBaseMetrics struct { - Score float64 `xml:"score"` - AccessVector string `xml:"access-vector"` - AccessComplexity string `xml:"access-complexity"` - Authentication string `xml:"authentication"` - ConfImpact string `xml:"confidentiality-impact"` - IntegImpact string `xml:"integrity-impact"` - AvailImpact string `xml:"availability-impact"` +type nvdCVEMetadata struct { + CVEID string `json:"ID"` +} + +type nvdImpact struct { + BaseMetricV2 nvdBaseMetricV2 `json:"baseMetricV2"` +} + +type nvdBaseMetricV2 struct { + CVSSv2 nvdCVSSv2 `json:"cvssV2"` +} + +type nvdCVSSv2 struct { + Score float64 `json:"baseScore"` + AccessVector string `json:"accessVector"` + AccessComplexity string `json:"accessComplexity"` + Authentication string `json:"authentication"` + ConfImpact string `json:"confidentialityImpact"` + IntegImpact string `json:"integrityImpact"` + AvailImpact string `json:"availabilityImpact"` } var vectorValuesToLetters map[string]string @@ -56,8 +68,8 @@ func init() { vectorValuesToLetters["MEDIUM"] = "M" vectorValuesToLetters["LOW"] = "L" vectorValuesToLetters["NONE"] = "N" - vectorValuesToLetters["SINGLE_INSTANCE"] = "S" - vectorValuesToLetters["MULTIPLE_INSTANCES"] = "M" + vectorValuesToLetters["SINGLE"] = "S" + vectorValuesToLetters["MULTIPLE"] = "M" vectorValuesToLetters["PARTIAL"] = "P" vectorValuesToLetters["COMPLETE"] = "C" } @@ -66,18 +78,23 @@ func (n nvdEntry) Metadata() *NVDMetadata { metadata := &NVDMetadata{ CVSSv2: NVDmetadataCVSSv2{ PublishedDateTime: n.PublishedDateTime, - Vectors: n.CVSS.BaseMetrics.String(), - Score: n.CVSS.BaseMetrics.Score, + Vectors: n.Impact.BaseMetricV2.CVSSv2.String(), + Score: n.Impact.BaseMetricV2.CVSSv2.Score, }, } if metadata.CVSSv2.Vectors == "" { return nil } + return metadata } -func (n nvdCVSSBaseMetrics) String() string { +func (n nvdEntry) Name() string { + return n.CVE.Metadata.CVEID +} + +func (n nvdCVSSv2) String() string { var str string addVec(&str, "AV", n.AccessVector) addVec(&str, "AC", n.AccessComplexity) @@ -94,7 +111,7 @@ func addVec(str *string, vec, val string) { if let, ok := vectorValuesToLetters[val]; ok { *str = fmt.Sprintf("%s%s:%s/", *str, vec, let) } else { - log.WithFields(log.Fields{"value": val, "vector": vec}).Warning("unknown value for CVSSv2 vector") + log.WithFields(log.Fields{"value": val, "vector": vec}).Warning("unknown value for CVSS vector") } } } diff --git a/ext/vulnmdsrc/nvd/nvd.go b/ext/vulnmdsrc/nvd/nvd.go index 96f93587..19f8dc1d 100644 --- a/ext/vulnmdsrc/nvd/nvd.go +++ b/ext/vulnmdsrc/nvd/nvd.go @@ -19,7 +19,7 @@ package nvd import ( "bufio" "compress/gzip" - "encoding/xml" + "encoding/json" "errors" "fmt" "io" @@ -39,8 +39,8 @@ import ( ) const ( - dataFeedURL string = "https://nvd.nist.gov/feeds/xml/cve/2.0/nvdcve-2.0-%s.xml.gz" - dataFeedMetaURL string = "https://nvd.nist.gov/feeds/xml/cve/2.0/nvdcve-2.0-%s.meta" + dataFeedURL string = "https://nvd.nist.gov/feeds/json/cve/1.0/nvdcve-1.0-%s.json.gz" + dataFeedMetaURL string = "https://nvd.nist.gov/feeds/json/cve/1.0/nvdcve-1.0-%s.meta" appenderName string = "NVD" @@ -96,8 +96,9 @@ func (a *appender) BuildCache(datastore database.Datastore) error { return commonerr.ErrCouldNotParse } var nvd nvd + r := bufio.NewReader(f) - if err = xml.NewDecoder(r).Decode(&nvd); err != nil { + if err := json.NewDecoder(r).Decode(&nvd); err != nil { f.Close() log.WithError(err).WithField(logDataFeedName, dataFeedName).Error("could not decode NVD data feed") return commonerr.ErrCouldNotParse @@ -107,7 +108,7 @@ func (a *appender) BuildCache(datastore database.Datastore) error { for _, nvdEntry := range nvd.Entries { // Create metadata entry. if metadata := nvdEntry.Metadata(); metadata != nil { - a.metadata[nvdEntry.Name] = *metadata + a.metadata[nvdEntry.Name()] = *metadata } } f.Close() @@ -154,7 +155,8 @@ func getDataFeeds(dataFeedHashes map[string]string, localPath string) (map[strin // Create map containing the name and filename for every data feed. dataFeedReaders := make(map[string]string) for _, dataFeedName := range dataFeedNames { - fileName := filepath.Join(localPath, fmt.Sprintf("%s.xml", dataFeedName)) + fileName := filepath.Join(localPath, fmt.Sprintf("%s.json", dataFeedName)) + if h, ok := dataFeedHashes[dataFeedName]; ok && h == dataFeedHashes[dataFeedName] { // The hash is known, the disk should contains the feed. Try to read from it. if localPath != "" { @@ -177,7 +179,6 @@ func getDataFeeds(dataFeedHashes map[string]string, localPath string) (map[strin } func downloadFeed(dataFeedName, fileName string) error { - // Download data feed. r, err := httputil.GetWithUserAgent(fmt.Sprintf(dataFeedURL, dataFeedName)) if err != nil { From 14277a8f5d95799bb651c194785dd04e75a08ee1 Mon Sep 17 00:00:00 2001 From: Kate Murphy Date: Tue, 16 Oct 2018 18:52:27 -0400 Subject: [PATCH 2/7] ext: Add JSON NVD parsing tests --- ext/vulnmdsrc/nvd/nvd.go | 31 ++++--- ext/vulnmdsrc/nvd/nvd_test.go | 93 +++++++++++++++++++ ext/vulnmdsrc/nvd/testdata/nvd_test.json | 92 ++++++++++++++++++ .../testdata/nvd_test_incorrect_format.json | 1 + 4 files changed, 205 insertions(+), 12 deletions(-) create mode 100644 ext/vulnmdsrc/nvd/nvd_test.go create mode 100644 ext/vulnmdsrc/nvd/testdata/nvd_test.json create mode 100644 ext/vulnmdsrc/nvd/testdata/nvd_test_incorrect_format.json diff --git a/ext/vulnmdsrc/nvd/nvd.go b/ext/vulnmdsrc/nvd/nvd.go index 19f8dc1d..9ff44201 100644 --- a/ext/vulnmdsrc/nvd/nvd.go +++ b/ext/vulnmdsrc/nvd/nvd.go @@ -95,23 +95,30 @@ func (a *appender) BuildCache(datastore database.Datastore) error { log.WithError(err).WithField(logDataFeedName, dataFeedName).Error("could not open NVD data file") return commonerr.ErrCouldNotParse } - var nvd nvd r := bufio.NewReader(f) - if err := json.NewDecoder(r).Decode(&nvd); err != nil { - f.Close() - log.WithError(err).WithField(logDataFeedName, dataFeedName).Error("could not decode NVD data feed") - return commonerr.ErrCouldNotParse + if err := a.parseDataFeed(r); err != nil { + log.WithError(err).WithField(logDataFeedName, dataFeedName).Error("could not parse NVD data file") + return err } + f.Close() + } - // For each entry of this data feed: - for _, nvdEntry := range nvd.Entries { - // Create metadata entry. - if metadata := nvdEntry.Metadata(); metadata != nil { - a.metadata[nvdEntry.Name()] = *metadata - } + return nil +} + +func (a *appender) parseDataFeed(r io.Reader) error { + var nvd nvd + + if err := json.NewDecoder(r).Decode(&nvd); err != nil { + return commonerr.ErrCouldNotParse + } + + for _, nvdEntry := range nvd.Entries { + // Create metadata entry. + if metadata := nvdEntry.Metadata(); metadata != nil { + a.metadata[nvdEntry.Name()] = *metadata } - f.Close() } return nil diff --git a/ext/vulnmdsrc/nvd/nvd_test.go b/ext/vulnmdsrc/nvd/nvd_test.go new file mode 100644 index 00000000..700b91dd --- /dev/null +++ b/ext/vulnmdsrc/nvd/nvd_test.go @@ -0,0 +1,93 @@ +// Copyright 2018 clair authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package nvd + +import ( + "os" + "path/filepath" + "runtime" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNVDParser(t *testing.T) { + _, filename, _, _ := runtime.Caller(0) + path := filepath.Join(filepath.Dir(filename)) + + dataFilePath := filepath.Join(path, "/testdata/nvd_test.json") + testData, err := os.Open(dataFilePath) + if err != nil { + t.Fatalf("Error opening %q: %v", dataFilePath, err) + } + defer testData.Close() + + a := &appender{} + a.metadata = make(map[string]NVDMetadata) + + err = a.parseDataFeed(testData) + if err != nil { + t.Fatalf("Error parsing %q: %v", dataFilePath, err) + } + + var gotMetadata, wantMetadata NVDMetadata + + // Items without CVSSv2 aren't returned. + assert.Len(t, a.metadata, 2) + gotMetadata, ok := a.metadata["CVE-2002-0001"] + assert.False(t, ok) + + // Item with only CVSSv2. + gotMetadata, ok = a.metadata["CVE-2012-0001"] + assert.True(t, ok) + wantMetadata = NVDMetadata{ + CVSSv2: NVDmetadataCVSSv2{ + Vectors: "AV:N/AC:L/Au:S/C:P/I:N/A:N", + Score: 4.0, + }, + } + assert.Equal(t, wantMetadata, gotMetadata) + + // Item with both CVSSv2 and CVSSv3 has CVSSv2 information returned. + gotMetadata, ok = a.metadata["CVE-2018-0001"] + assert.True(t, ok) + wantMetadata = NVDMetadata{ + CVSSv2: NVDmetadataCVSSv2{ + Vectors: "AV:N/AC:L/Au:N/C:P/I:P/A:P", + Score: 7.5, + }, + } + assert.Equal(t, wantMetadata, gotMetadata) +} + +func TestNVDParserErrors(t *testing.T) { + _, filename, _, _ := runtime.Caller(0) + path := filepath.Join(filepath.Dir(filename)) + + dataFilePath := filepath.Join(path, "/testdata/nvd_test_incorrect_format.json") + testData, err := os.Open(dataFilePath) + if err != nil { + t.Fatalf("Error opening %q: %v", dataFilePath, err) + } + defer testData.Close() + + a := &appender{} + a.metadata = make(map[string]NVDMetadata) + + err = a.parseDataFeed(testData) + if err == nil { + t.Fatalf("Expected error parsing NVD data file: %q", dataFilePath) + } +} diff --git a/ext/vulnmdsrc/nvd/testdata/nvd_test.json b/ext/vulnmdsrc/nvd/testdata/nvd_test.json new file mode 100644 index 00000000..eb878741 --- /dev/null +++ b/ext/vulnmdsrc/nvd/testdata/nvd_test.json @@ -0,0 +1,92 @@ +{ + "CVE_Items" : [ { + "_comment": "A CVE without CVSSv2 or CVSSv3", + "cve" : { + "data_type" : "CVE", + "data_format" : "MITRE", + "data_version" : "4.0", + "CVE_data_meta" : { + "ID" : "CVE-2002-0001" + } + }, + "impact" : { }, + "publishedDate" : "2018-01-10T22:29Z" + }, { + "_comment": "A CVE with only CVSSv2", + "cve" : { + "CVE_data_meta" : { + "ID" : "CVE-2012-0001" + } + }, + "impact" : { + "baseMetricV3" : { }, + "baseMetricV2" : { + "cvssV2" : { + "version" : "2.0", + "vectorString" : "(AV:N/AC:L/Au:S/C:P/I:N/A:N)", + "accessVector" : "NETWORK", + "accessComplexity" : "LOW", + "authentication" : "SINGLE", + "confidentialityImpact" : "PARTIAL", + "integrityImpact" : "NONE", + "availabilityImpact" : "NONE", + "baseScore" : 4.0 + }, + "severity" : "MEDIUM", + "exploitabilityScore" : 8.0, + "impactScore" : 2.9, + "obtainAllPrivilege" : false, + "obtainUserPrivilege" : false, + "obtainOtherPrivilege" : false, + "userInteractionRequired" : false + } + } + }, { + "_comment": "A CVE with standard CVSSv2 and CVSSv3", + "cve" : { + "CVE_data_meta" : { + "ID" : "CVE-2018-0001" + } + }, + "impact" : { + "baseMetricV3" : { + "cvssV3" : { + "version" : "3.0", + "vectorString" : "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + "attackVector" : "NETWORK", + "attackComplexity" : "LOW", + "privilegesRequired" : "NONE", + "userInteraction" : "NONE", + "scope" : "UNCHANGED", + "confidentialityImpact" : "HIGH", + "integrityImpact" : "HIGH", + "availabilityImpact" : "HIGH", + "baseScore" : 9.8, + "baseSeverity" : "CRITICAL" + }, + "exploitabilityScore" : 3.9, + "impactScore" : 5.9 + }, + "baseMetricV2" : { + "cvssV2" : { + "version" : "2.0", + "vectorString" : "(AV:N/AC:L/Au:N/C:P/I:P/A:P)", + "accessVector" : "NETWORK", + "accessComplexity" : "LOW", + "authentication" : "NONE", + "confidentialityImpact" : "PARTIAL", + "integrityImpact" : "PARTIAL", + "availabilityImpact" : "PARTIAL", + "baseScore" : 7.5 + }, + "severity" : "HIGH", + "exploitabilityScore" : 10.0, + "impactScore" : 6.4, + "obtainAllPrivilege" : false, + "obtainUserPrivilege" : false, + "obtainOtherPrivilege" : false, + "userInteractionRequired" : false + } + } + } ] +} diff --git a/ext/vulnmdsrc/nvd/testdata/nvd_test_incorrect_format.json b/ext/vulnmdsrc/nvd/testdata/nvd_test_incorrect_format.json new file mode 100644 index 00000000..0aa25d8d --- /dev/null +++ b/ext/vulnmdsrc/nvd/testdata/nvd_test_incorrect_format.json @@ -0,0 +1 @@ +Not a JSON file. From b81e4454fbb7f3dcec4a2dd6064820bf0c6321f2 Mon Sep 17 00:00:00 2001 From: Kate Murphy Date: Tue, 16 Oct 2018 19:08:17 -0400 Subject: [PATCH 3/7] ext: Parse CVSSv3 data from JSON NVD feed --- ext/vulnmdsrc/nvd/json.go | 45 +++++++++++++++++++++++++++++++++++ ext/vulnmdsrc/nvd/nvd.go | 6 +++++ ext/vulnmdsrc/nvd/nvd_test.go | 4 ++++ 3 files changed, 55 insertions(+) diff --git a/ext/vulnmdsrc/nvd/json.go b/ext/vulnmdsrc/nvd/json.go index 306bfc27..03b549c5 100644 --- a/ext/vulnmdsrc/nvd/json.go +++ b/ext/vulnmdsrc/nvd/json.go @@ -41,6 +41,7 @@ type nvdCVEMetadata struct { type nvdImpact struct { BaseMetricV2 nvdBaseMetricV2 `json:"baseMetricV2"` + BaseMetricV3 nvdBaseMetricV3 `json:"baseMetricV3"` } type nvdBaseMetricV2 struct { @@ -57,6 +58,22 @@ type nvdCVSSv2 struct { AvailImpact string `json:"availabilityImpact"` } +type nvdBaseMetricV3 struct { + CVSSv3 nvdCVSSv3 `json:"cvssV3"` +} + +type nvdCVSSv3 struct { + Score float64 `json:"baseScore"` + AttackVector string `json:"attackVector"` + AttackComplexity string `json:"attackComplexity"` + PrivilegesRequired string `json:"privilegesRequired"` + UserInteraction string `json:"userInteraction"` + Scope string `json:"scope"` + ConfImpact string `json:"confidentialityImpact"` + IntegImpact string `json:"integrityImpact"` + AvailImpact string `json:"availabilityImpact"` +} + var vectorValuesToLetters map[string]string func init() { @@ -72,6 +89,12 @@ func init() { vectorValuesToLetters["MULTIPLE"] = "M" vectorValuesToLetters["PARTIAL"] = "P" vectorValuesToLetters["COMPLETE"] = "C" + + // CVSSv3 only + vectorValuesToLetters["PHYSICAL"] = "P" + vectorValuesToLetters["REQUIRED"] = "R" + vectorValuesToLetters["CHANGED"] = "C" + vectorValuesToLetters["UNCHANGED"] = "U" } func (n nvdEntry) Metadata() *NVDMetadata { @@ -81,6 +104,10 @@ func (n nvdEntry) Metadata() *NVDMetadata { Vectors: n.Impact.BaseMetricV2.CVSSv2.String(), Score: n.Impact.BaseMetricV2.CVSSv2.Score, }, + CVSSv3: NVDmetadataCVSSv3{ + Vectors: n.Impact.BaseMetricV3.CVSSv3.String(), + Score: n.Impact.BaseMetricV3.CVSSv3.Score, + }, } if metadata.CVSSv2.Vectors == "" { @@ -106,6 +133,24 @@ func (n nvdCVSSv2) String() string { return str } +func (n nvdCVSSv3) String() string { + var str string + addVec(&str, "AV", n.AttackVector) + addVec(&str, "AC", n.AttackComplexity) + addVec(&str, "PR", n.PrivilegesRequired) + addVec(&str, "UI", n.UserInteraction) + addVec(&str, "S", n.Scope) + addVec(&str, "C", n.ConfImpact) + addVec(&str, "I", n.IntegImpact) + addVec(&str, "A", n.AvailImpact) + str = strings.TrimSuffix(str, "/") + + if len(str) > 0 { + return fmt.Sprintf("CVSS:3.0/%s", str) + } + return str +} + func addVec(str *string, vec, val string) { if val != "" { if let, ok := vectorValuesToLetters[val]; ok { diff --git a/ext/vulnmdsrc/nvd/nvd.go b/ext/vulnmdsrc/nvd/nvd.go index 9ff44201..a4438a24 100644 --- a/ext/vulnmdsrc/nvd/nvd.go +++ b/ext/vulnmdsrc/nvd/nvd.go @@ -55,6 +55,7 @@ type appender struct { type NVDMetadata struct { CVSSv2 NVDmetadataCVSSv2 + CVSSv3 NVDmetadataCVSSv3 } type NVDmetadataCVSSv2 struct { @@ -63,6 +64,11 @@ type NVDmetadataCVSSv2 struct { Score float64 } +type NVDmetadataCVSSv3 struct { + Vectors string + Score float64 +} + func init() { vulnmdsrc.RegisterAppender(appenderName, &appender{}) } diff --git a/ext/vulnmdsrc/nvd/nvd_test.go b/ext/vulnmdsrc/nvd/nvd_test.go index 700b91dd..7bd24af9 100644 --- a/ext/vulnmdsrc/nvd/nvd_test.go +++ b/ext/vulnmdsrc/nvd/nvd_test.go @@ -68,6 +68,10 @@ func TestNVDParser(t *testing.T) { Vectors: "AV:N/AC:L/Au:N/C:P/I:P/A:P", Score: 7.5, }, + CVSSv3: NVDmetadataCVSSv3{ + Vectors: "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + Score: 9.8, + }, } assert.Equal(t, wantMetadata, gotMetadata) } From 699d1143e5ab2a673d0f83249f3268cfebaf3e57 Mon Sep 17 00:00:00 2001 From: Jimmy Zelinskie Date: Thu, 18 Oct 2018 18:47:37 -0400 Subject: [PATCH 4/7] ext: fixup incorrect copyright year --- ext/vulnmdsrc/nvd/json.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/vulnmdsrc/nvd/json.go b/ext/vulnmdsrc/nvd/json.go index 03b549c5..00146cc7 100644 --- a/ext/vulnmdsrc/nvd/json.go +++ b/ext/vulnmdsrc/nvd/json.go @@ -1,4 +1,4 @@ -// Copyright 2017 clair authors +// Copyright 2018 clair authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. From 8efc3e40382287e88714fdcf634a79e6347b6157 Mon Sep 17 00:00:00 2001 From: Jimmy Zelinskie Date: Thu, 18 Oct 2018 18:48:07 -0400 Subject: [PATCH 5/7] ext: remove unneeded use of init() --- ext/vulnmdsrc/nvd/json.go | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/ext/vulnmdsrc/nvd/json.go b/ext/vulnmdsrc/nvd/json.go index 00146cc7..37663786 100644 --- a/ext/vulnmdsrc/nvd/json.go +++ b/ext/vulnmdsrc/nvd/json.go @@ -74,7 +74,25 @@ type nvdCVSSv3 struct { AvailImpact string `json:"availabilityImpact"` } -var vectorValuesToLetters map[string]string +var vectorValuesToLetters = map[string]string{ + "NETWORK": "N", + "ADJACENT_NETWORK": "A", + "LOCAL": "L", + "HIGH": "H", + "MEDIUM": "M", + "LOW": "L", + "NONE": "N", + "SINGLE": "S", + "MULTIPLE": "M", + "PARTIAL": "P", + "COMPLETE": "C", + + // CVSSv3 only + "PHYSICAL": "P", + "REQUIRED": "R", + "CHANGED": "C", + "UNCHANGED": "U", +} func init() { vectorValuesToLetters = make(map[string]string) From 4f0da12b123ec543a58936c0f7226254e411cc00 Mon Sep 17 00:00:00 2001 From: Kate Murphy Date: Fri, 19 Oct 2018 10:44:23 -0400 Subject: [PATCH 6/7] ext: pass through CVSSv3 impact and exploitability score --- ext/vulnmdsrc/nvd/json.go | 10 +++++++--- ext/vulnmdsrc/nvd/nvd.go | 6 ++++-- ext/vulnmdsrc/nvd/nvd_test.go | 6 ++++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/ext/vulnmdsrc/nvd/json.go b/ext/vulnmdsrc/nvd/json.go index 37663786..ea32667b 100644 --- a/ext/vulnmdsrc/nvd/json.go +++ b/ext/vulnmdsrc/nvd/json.go @@ -59,7 +59,9 @@ type nvdCVSSv2 struct { } type nvdBaseMetricV3 struct { - CVSSv3 nvdCVSSv3 `json:"cvssV3"` + CVSSv3 nvdCVSSv3 `json:"cvssV3"` + ExploitabilityScore float64 `json:"exploitabilityScore"` + ImpactScore float64 `json:"impactScore"` } type nvdCVSSv3 struct { @@ -123,8 +125,10 @@ func (n nvdEntry) Metadata() *NVDMetadata { Score: n.Impact.BaseMetricV2.CVSSv2.Score, }, CVSSv3: NVDmetadataCVSSv3{ - Vectors: n.Impact.BaseMetricV3.CVSSv3.String(), - Score: n.Impact.BaseMetricV3.CVSSv3.Score, + Vectors: n.Impact.BaseMetricV3.CVSSv3.String(), + Score: n.Impact.BaseMetricV3.CVSSv3.Score, + ExploitabilityScore: n.Impact.BaseMetricV3.ExploitabilityScore, + ImpactScore: n.Impact.BaseMetricV3.ImpactScore, }, } diff --git a/ext/vulnmdsrc/nvd/nvd.go b/ext/vulnmdsrc/nvd/nvd.go index a4438a24..3037a97b 100644 --- a/ext/vulnmdsrc/nvd/nvd.go +++ b/ext/vulnmdsrc/nvd/nvd.go @@ -65,8 +65,10 @@ type NVDmetadataCVSSv2 struct { } type NVDmetadataCVSSv3 struct { - Vectors string - Score float64 + Vectors string + Score float64 + ExploitabilityScore float64 + ImpactScore float64 } func init() { diff --git a/ext/vulnmdsrc/nvd/nvd_test.go b/ext/vulnmdsrc/nvd/nvd_test.go index 7bd24af9..95285f8d 100644 --- a/ext/vulnmdsrc/nvd/nvd_test.go +++ b/ext/vulnmdsrc/nvd/nvd_test.go @@ -69,8 +69,10 @@ func TestNVDParser(t *testing.T) { Score: 7.5, }, CVSSv3: NVDmetadataCVSSv3{ - Vectors: "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", - Score: 9.8, + Vectors: "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + Score: 9.8, + ExploitabilityScore: 3.9, + ImpactScore: 5.9, }, } assert.Equal(t, wantMetadata, gotMetadata) From 081ae34af146365146cf4548a8a0afa293e15695 Mon Sep 17 00:00:00 2001 From: Kate Murphy Date: Fri, 19 Oct 2018 15:00:00 -0400 Subject: [PATCH 7/7] ext: remove duplicate vectorValuesToLetters definition --- ext/vulnmdsrc/nvd/json.go | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/ext/vulnmdsrc/nvd/json.go b/ext/vulnmdsrc/nvd/json.go index ea32667b..161b5a11 100644 --- a/ext/vulnmdsrc/nvd/json.go +++ b/ext/vulnmdsrc/nvd/json.go @@ -96,27 +96,6 @@ var vectorValuesToLetters = map[string]string{ "UNCHANGED": "U", } -func init() { - vectorValuesToLetters = make(map[string]string) - vectorValuesToLetters["NETWORK"] = "N" - vectorValuesToLetters["ADJACENT_NETWORK"] = "A" - vectorValuesToLetters["LOCAL"] = "L" - vectorValuesToLetters["HIGH"] = "H" - vectorValuesToLetters["MEDIUM"] = "M" - vectorValuesToLetters["LOW"] = "L" - vectorValuesToLetters["NONE"] = "N" - vectorValuesToLetters["SINGLE"] = "S" - vectorValuesToLetters["MULTIPLE"] = "M" - vectorValuesToLetters["PARTIAL"] = "P" - vectorValuesToLetters["COMPLETE"] = "C" - - // CVSSv3 only - vectorValuesToLetters["PHYSICAL"] = "P" - vectorValuesToLetters["REQUIRED"] = "R" - vectorValuesToLetters["CHANGED"] = "C" - vectorValuesToLetters["UNCHANGED"] = "U" -} - func (n nvdEntry) Metadata() *NVDMetadata { metadata := &NVDMetadata{ CVSSv2: NVDmetadataCVSSv2{