From fc100563dd12844e2eb727cc383fdf29ea59b5d1 Mon Sep 17 00:00:00 2001 From: Andrew Pollock Date: Fri, 17 Mar 2023 17:42:21 +1100 Subject: [PATCH] Deduplicate affected versions (#1133) This adds some preliminary test coverage to `ExtractVersionInfo` and avoids adding duplicates to`AffectedVersion`, preventing duplicate commit hashes getting added further downstream when they are mapped. This highlights the potential need to look more holistically at the nodes when extracting versions, because each one could be for a completely different CPE... --- vulnfeeds/cves/versions.go | 9 +- vulnfeeds/cves/versions_test.go | 96 +++++++++++ vulnfeeds/test_data/nvdcve-1.1-test-data.json | 155 +++++++++++++++++- 3 files changed, 257 insertions(+), 3 deletions(-) diff --git a/vulnfeeds/cves/versions.go b/vulnfeeds/cves/versions.go index 6bc05123e7f..bd73baebdb2 100644 --- a/vulnfeeds/cves/versions.go +++ b/vulnfeeds/cves/versions.go @@ -435,11 +435,16 @@ func ExtractVersionInfo(cve CVEItem, validVersions []string) (v VersionInfo, not } gotVersions = true - v.AffectedVersions = append(v.AffectedVersions, AffectedVersion{ + possibleNewAffectedVersion := AffectedVersion{ Introduced: introduced, Fixed: fixed, LastAffected: lastaffected, - }) + } + if slices.Contains(v.AffectedVersions, possibleNewAffectedVersion) { + // Avoid appending duplicates + continue + } + v.AffectedVersions = append(v.AffectedVersions, possibleNewAffectedVersion) } } if !gotVersions { diff --git a/vulnfeeds/cves/versions_test.go b/vulnfeeds/cves/versions_test.go index 6b62d8e6a27..951245881e3 100644 --- a/vulnfeeds/cves/versions_test.go +++ b/vulnfeeds/cves/versions_test.go @@ -1,10 +1,32 @@ package cves import ( + "encoding/json" + "log" + "os" "reflect" "testing" + + "github.com/go-test/deep" ) +// Helper function to load in a specific CVE from sample data. +func loadTestData(CVEID string) CVEItem { + file, err := os.Open("../test_data/nvdcve-1.1-test-data.json") + if err != nil { + log.Fatalf("Failed to load test data") + } + var nvdCves NVDCVE + json.NewDecoder(file).Decode(&nvdCves) + for _, item := range nvdCves.CVEItems { + if item.CVE.CVEDataMeta.ID == CVEID { + return item + } + } + log.Fatalf("test data doesn't contain specified %q", CVEID) + return CVEItem{} +} + func TestParseCPE(t *testing.T) { tests := []struct { description string @@ -452,3 +474,77 @@ func TestNormalizeVersion(t *testing.T) { } } } + +func TestExtractVersionInfo(t *testing.T) { + tests := []struct { + description string + inputCVEItem CVEItem + inputValidVersions []string + expectedVersionInfo VersionInfo + expectedNotes []string + }{ + { + description: "A CVE with multiple affected versions", + inputCVEItem: loadTestData("CVE-2022-32746"), + inputValidVersions: []string{}, + expectedVersionInfo: VersionInfo{ + FixCommits: []GitCommit(nil), + LimitCommits: []GitCommit(nil), + LastAffectedCommits: []GitCommit(nil), + AffectedVersions: []AffectedVersion{ + AffectedVersion{ + Introduced: "4.16.0", + Fixed: "4.16.4", + LastAffected: "", + }, + AffectedVersion{ + Introduced: "4.15.0", + Fixed: "4.15.9", + LastAffected: "", + }, + AffectedVersion{ + Introduced: "4.3.0", + Fixed: "4.14.14", + LastAffected: "", + }, + }, + }, + expectedNotes: []string{}, + }, + { + description: "A CVE with duplicate affected versions squashed", + inputCVEItem: loadTestData("CVE-2022-0090"), + inputValidVersions: []string{}, + expectedVersionInfo: VersionInfo{ + FixCommits: []GitCommit(nil), + LimitCommits: []GitCommit(nil), + LastAffectedCommits: []GitCommit(nil), + AffectedVersions: []AffectedVersion{ + AffectedVersion{ + Introduced: "14.6.0", + Fixed: "14.6.1", + LastAffected: "", + }, + AffectedVersion{ + Introduced: "14.5.0", + Fixed: "14.5.3", + LastAffected: "", + }, + AffectedVersion{ + Introduced: "", + Fixed: "14.4.5", + LastAffected: "", + }, + }, + }, + expectedNotes: []string{}, + }, + } + + for _, tc := range tests { + gotVersionInfo, _ := ExtractVersionInfo(tc.inputCVEItem, tc.inputValidVersions) + if diff := deep.Equal(gotVersionInfo, tc.expectedVersionInfo); diff != nil { + t.Errorf("test %q: VersionInfo for %#v was incorrect: %s", tc.description, tc.inputCVEItem, diff) + } + } +} diff --git a/vulnfeeds/test_data/nvdcve-1.1-test-data.json b/vulnfeeds/test_data/nvdcve-1.1-test-data.json index 0811ed611f1..ef3d0b219e8 100644 --- a/vulnfeeds/test_data/nvdcve-1.1-test-data.json +++ b/vulnfeeds/test_data/nvdcve-1.1-test-data.json @@ -5,6 +5,159 @@ "CVE_data_numberOfCVEs" : "660", "CVE_data_timestamp" : "2022-08-31T05:00Z", "CVE_Items" : [ + { + "cve": { + "data_type": "CVE", + "data_format": "MITRE", + "data_version": "4.0", + "CVE_data_meta": { + "ID": "CVE-2022-0090", + "ASSIGNER": "cve@gitlab.com" + }, + "problemtype": { + "problemtype_data": [ + { + "description": [ + { + "lang": "en", + "value": "CWE-269" + } + ] + } + ] + }, + "references": { + "reference_data": [ + { + "url": "https://hackerone.com/reports/1415964", + "name": "https://hackerone.com/reports/1415964", + "refsource": "MISC", + "tags": [ + "Permissions Required" + ] + }, + { + "url": "https://gitlab.com/gitlab-org/cves/-/blob/master/2022/CVE-2022-0090.json", + "name": "https://gitlab.com/gitlab-org/cves/-/blob/master/2022/CVE-2022-0090.json", + "refsource": "CONFIRM", + "tags": [ + "Third Party Advisory" + ] + }, + { + "url": "https://gitlab.com/gitlab-org/gitaly/-/issues/3948", + "name": "https://gitlab.com/gitlab-org/gitaly/-/issues/3948", + "refsource": "MISC", + "tags": [ + "Broken Link" + ] + } + ] + }, + "description": { + "description_data": [ + { + "lang": "en", + "value": "An issue has been discovered affecting GitLab versions prior to 14.4.5, between 14.5.0 and 14.5.3, and between 14.6.0 and 14.6.1. GitLab is configured in a way that it doesn't ignore replacement references with git sub-commands, allowing a malicious user to spoof the contents of their commits in the UI." + } + ] + } + }, + "configurations": { + "CVE_data_version": "4.0", + "nodes": [ + { + "operator": "OR", + "children": [], + "cpe_match": [ + { + "vulnerable": true, + "cpe23Uri": "cpe:2.3:a:gitlab:gitlab:*:*:*:*:community:*:*:*", + "versionStartIncluding": "14.6.0", + "versionEndExcluding": "14.6.1", + "cpe_name": [] + }, + { + "vulnerable": true, + "cpe23Uri": "cpe:2.3:a:gitlab:gitlab:*:*:*:*:enterprise:*:*:*", + "versionStartIncluding": "14.6.0", + "versionEndExcluding": "14.6.1", + "cpe_name": [] + }, + { + "vulnerable": true, + "cpe23Uri": "cpe:2.3:a:gitlab:gitlab:*:*:*:*:community:*:*:*", + "versionStartIncluding": "14.5.0", + "versionEndExcluding": "14.5.3", + "cpe_name": [] + }, + { + "vulnerable": true, + "cpe23Uri": "cpe:2.3:a:gitlab:gitlab:*:*:*:*:enterprise:*:*:*", + "versionStartIncluding": "14.5.0", + "versionEndExcluding": "14.5.3", + "cpe_name": [] + }, + { + "vulnerable": true, + "cpe23Uri": "cpe:2.3:a:gitlab:gitlab:*:*:*:*:community:*:*:*", + "versionEndExcluding": "14.4.5", + "cpe_name": [] + }, + { + "vulnerable": true, + "cpe23Uri": "cpe:2.3:a:gitlab:gitlab:*:*:*:*:enterprise:*:*:*", + "versionEndExcluding": "14.4.5", + "cpe_name": [] + } + ] + } + ] + }, + "impact": { + "baseMetricV3": { + "cvssV3": { + "version": "3.1", + "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N", + "attackVector": "NETWORK", + "attackComplexity": "LOW", + "privilegesRequired": "LOW", + "userInteraction": "NONE", + "scope": "UNCHANGED", + "confidentialityImpact": "NONE", + "integrityImpact": "HIGH", + "availabilityImpact": "NONE", + "baseScore": 6.5, + "baseSeverity": "MEDIUM" + }, + "exploitabilityScore": 2.8, + "impactScore": 3.6 + }, + "baseMetricV2": { + "cvssV2": { + "version": "2.0", + "vectorString": "AV:N/AC:L/Au:N/C:N/I:P/A:N", + "accessVector": "NETWORK", + "accessComplexity": "LOW", + "authentication": "NONE", + "confidentialityImpact": "NONE", + "integrityImpact": "PARTIAL", + "availabilityImpact": "NONE", + "baseScore": 5 + }, + "severity": "MEDIUM", + "exploitabilityScore": 10, + "impactScore": 2.9, + "acInsufInfo": false, + "obtainAllPrivilege": false, + "obtainUserPrivilege": false, + "obtainOtherPrivilege": false, + "userInteractionRequired": false + } + }, + "publishedDate": "2022-01-18T17:15Z", + "lastModifiedDate": "2022-01-25T14:49Z" + }, { "cve" : { "data_type" : "CVE", @@ -41183,4 +41336,4 @@ "publishedDate" : "2022-08-23T04:15Z", "lastModifiedDate" : "2022-08-24T14:26Z" } ] -} \ No newline at end of file +}