From 5c64079891a01a61e9412f792ee5579d201dd3e4 Mon Sep 17 00:00:00 2001 From: Rahul Yadav Date: Wed, 21 Apr 2021 21:30:32 +0530 Subject: [PATCH 1/5] Added NVD CPE details --- pkg/types/types.go | 1 + pkg/vulnsrc/nvd/nvd.go | 8 ++++++-- pkg/vulnsrc/nvd/nvd_test.go | 1 + pkg/vulnsrc/nvd/types.go | 1 + 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/pkg/types/types.go b/pkg/types/types.go index 306990d7..0290d57a 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -95,6 +95,7 @@ type VulnerabilityDetail struct { Description string `json:",omitempty"` PublishedDate *time.Time `json:",omitempty"` LastModifiedDate *time.Time `json:",omitempty"` + CPEDetails string `json:",omitempty"` } type AdvisoryDetail struct { diff --git a/pkg/vulnsrc/nvd/nvd.go b/pkg/vulnsrc/nvd/nvd.go index 1f3684ef..b1d573c9 100644 --- a/pkg/vulnsrc/nvd/nvd.go +++ b/pkg/vulnsrc/nvd/nvd.go @@ -92,7 +92,6 @@ func (vs VulnSrc) commit(tx *bolt.Tx, items []Item) error { publishedDate, _ := time.Parse("2006-01-02T15:04Z", item.PublishedDate) lastModifiedDate, _ := time.Parse("2006-01-02T15:04Z", item.LastModifiedDate) - vuln := types.VulnerabilityDetail{ CvssScore: item.Impact.BaseMetricV2.CvssV2.BaseScore, CvssVector: item.Impact.BaseMetricV2.CvssV2.VectorString, @@ -107,7 +106,12 @@ func (vs VulnSrc) commit(tx *bolt.Tx, items []Item) error { PublishedDate: &publishedDate, LastModifiedDate: &lastModifiedDate, } - + if item.Configurations != nil { + configurationString, err := json.Marshal(item.Configurations) + if err == nil { + vuln.CPEDetails = string(configurationString) + } + } if err := vs.dbc.PutVulnerabilityDetail(tx, cveID, vulnerability.Nvd, vuln); err != nil { return err } diff --git a/pkg/vulnsrc/nvd/nvd_test.go b/pkg/vulnsrc/nvd/nvd_test.go index 7ffb1073..007797c5 100644 --- a/pkg/vulnsrc/nvd/nvd_test.go +++ b/pkg/vulnsrc/nvd/nvd_test.go @@ -41,6 +41,7 @@ func TestVulnSrc_Update(t *testing.T) { References: []string{"https://source.android.com/security/bulletin/2020-01-01"}, LastModifiedDate: utils.MustTimeParse("2020-01-01T01:01:00Z"), PublishedDate: utils.MustTimeParse("2001-01-01T01:01:00Z"), + CPEDetails: `{"CVE_data_version":"4.0","nodes":[{"cpe_match":[{"cpe23Uri":"cpe:2.3:o:google:android:8.0:*:*:*:*:*:*:*","vulnerable":true},{"cpe23Uri":"cpe:2.3:o:google:android:8.1:*:*:*:*:*:*:*","vulnerable":true},{"cpe23Uri":"cpe:2.3:o:google:android:9.0:*:*:*:*:*:*:*","vulnerable":true},{"cpe23Uri":"cpe:2.3:o:google:android:10.0:*:*:*:*:*:*:*","vulnerable":true}],"operator":"OR"}]}`, }, }, { diff --git a/pkg/vulnsrc/nvd/types.go b/pkg/vulnsrc/nvd/types.go index dd5429de..280273b2 100644 --- a/pkg/vulnsrc/nvd/types.go +++ b/pkg/vulnsrc/nvd/types.go @@ -5,6 +5,7 @@ type NVD struct { } type Item struct { + Configurations interface{} Cve Cve Impact Impact LastModifiedDate string `json:"lastModifiedDate"` From ec571c9d7289c7f63b6d92f3e6a19a482cef1bf3 Mon Sep 17 00:00:00 2001 From: Rahul Yadav Date: Wed, 21 Apr 2021 23:43:12 +0530 Subject: [PATCH 2/5] Added fixed schema for CPE details --- pkg/types/types.go | 17 ++- pkg/vulnsrc/nvd/nvd.go | 7 +- pkg/vulnsrc/nvd/nvd_test.go | 73 ++++++++++- .../testdata/vuln-list/nvd/CVE-2021-0109.json | 115 ++++++++++++++++++ pkg/vulnsrc/nvd/types.go | 37 +++++- pkg/vulnsrc/vulnerability/vulnerability.go | 6 +- 6 files changed, 247 insertions(+), 8 deletions(-) create mode 100644 pkg/vulnsrc/nvd/testdata/vuln-list/nvd/CVE-2021-0109.json diff --git a/pkg/types/types.go b/pkg/types/types.go index 0290d57a..0ae2f294 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -95,7 +95,21 @@ type VulnerabilityDetail struct { Description string `json:",omitempty"` PublishedDate *time.Time `json:",omitempty"` LastModifiedDate *time.Time `json:",omitempty"` - CPEDetails string `json:",omitempty"` + CPEDetails CPEDetails `json:",omitempty"` +} + +type CPEDetails struct { + CveDataVersion string `json:"CVE_data_version"` + Nodes []Node `json:"nodes,omitempty"` +} + +type Node struct { + Children []Node `json:"children,omitempty"` + Operator string `json:"operator,omitempty"` + CPEMatch []Node `json:"cpe_match,omitempty"` + Cpe23Uri string `json:"cpe23Uri,omitempty"` + VersionEndExcluding string `json:"versionEndExcluding,omitempty"` + Vulnerable *bool `json:"vulnerable,omitempty"` } type AdvisoryDetail struct { @@ -127,6 +141,7 @@ type Vulnerability struct { References []string `json:",omitempty"` PublishedDate *time.Time `json:",omitempty"` LastModifiedDate *time.Time `json:",omitempty"` + CPEDetails CPEDetails `json:",omitempty"` } type VulnSrc interface { diff --git a/pkg/vulnsrc/nvd/nvd.go b/pkg/vulnsrc/nvd/nvd.go index b1d573c9..7f9a9dfd 100644 --- a/pkg/vulnsrc/nvd/nvd.go +++ b/pkg/vulnsrc/nvd/nvd.go @@ -106,10 +106,9 @@ func (vs VulnSrc) commit(tx *bolt.Tx, items []Item) error { PublishedDate: &publishedDate, LastModifiedDate: &lastModifiedDate, } - if item.Configurations != nil { - configurationString, err := json.Marshal(item.Configurations) - if err == nil { - vuln.CPEDetails = string(configurationString) + if item.Configurations.CveDataVersion != "" { + if err := mapConfigurationsToCPEDetails(item.Configurations, &vuln.CPEDetails); err != nil { + log.Printf("error mapping cpe details: %v\n", err) } } if err := vs.dbc.PutVulnerabilityDetail(tx, cveID, vulnerability.Nvd, vuln); err != nil { diff --git a/pkg/vulnsrc/nvd/nvd_test.go b/pkg/vulnsrc/nvd/nvd_test.go index 007797c5..58fa74e2 100644 --- a/pkg/vulnsrc/nvd/nvd_test.go +++ b/pkg/vulnsrc/nvd/nvd_test.go @@ -41,7 +41,78 @@ func TestVulnSrc_Update(t *testing.T) { References: []string{"https://source.android.com/security/bulletin/2020-01-01"}, LastModifiedDate: utils.MustTimeParse("2020-01-01T01:01:00Z"), PublishedDate: utils.MustTimeParse("2001-01-01T01:01:00Z"), - CPEDetails: `{"CVE_data_version":"4.0","nodes":[{"cpe_match":[{"cpe23Uri":"cpe:2.3:o:google:android:8.0:*:*:*:*:*:*:*","vulnerable":true},{"cpe23Uri":"cpe:2.3:o:google:android:8.1:*:*:*:*:*:*:*","vulnerable":true},{"cpe23Uri":"cpe:2.3:o:google:android:9.0:*:*:*:*:*:*:*","vulnerable":true},{"cpe23Uri":"cpe:2.3:o:google:android:10.0:*:*:*:*:*:*:*","vulnerable":true}],"operator":"OR"}]}`, + CPEDetails: types.CPEDetails{ + CveDataVersion: "4.0", + Nodes: []types.Node{ + types.Node{ + Operator: "OR", + CPEMatch: []types.Node{ + { + Cpe23Uri: "cpe:2.3:o:google:android:8.0:*:*:*:*:*:*:*", + Vulnerable: boolptr(true), + }, + { + Cpe23Uri: "cpe:2.3:o:google:android:8.1:*:*:*:*:*:*:*", + Vulnerable: boolptr(true), + }, + { + Cpe23Uri: "cpe:2.3:o:google:android:9.0:*:*:*:*:*:*:*", + Vulnerable: boolptr(true), + }, + { + Cpe23Uri: "cpe:2.3:o:google:android:10.0:*:*:*:*:*:*:*", + Vulnerable: boolptr(true), + }, + }, + }, + }, + }, + }, + }, + { + name: "happy path with CPE detail having children", + dir: "./testdata", + cveID: "CVE-2021-0109", + want: types.VulnerabilityDetail{ + Description: "Insecure inherited permissions for the Intel(R) SOC driver package for STK1A32SC before version 604 may allow an authenticated user to potentially enable escalation of privilege via local access.", + CvssScore: 4.6, + CvssVector: "AV:L/AC:L/Au:N/C:P/I:P/A:P", + CvssScoreV3: 7.8, + CvssVectorV3: "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", + Severity: types.SeverityMedium, + SeverityV3: types.SeverityHigh, + References: []string{"https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00471.html"}, + LastModifiedDate: utils.MustTimeParse("2021-02-22T20:23:00Z"), + PublishedDate: utils.MustTimeParse("2021-02-17T14:15:00Z"), + CPEDetails: types.CPEDetails{ + CveDataVersion: "4.0", + Nodes: []types.Node{ + { + Operator: "AND", + Children: []types.Node{ + types.Node{ + Operator: "OR", + CPEMatch: []types.Node{ + types.Node{ + Cpe23Uri: "cpe:2.3:o:intel:compute_stick_stk1a32sc_firmware:*:*:*:*:*:*:*:*", + VersionEndExcluding: "604", + Vulnerable: boolptr(true), + }, + }, + }, + types.Node{ + Operator: "OR", + CPEMatch: []types.Node{ + types.Node{ + Cpe23Uri: "cpe:2.3:h:intel:compute_stick_stk1a32sc:-:*:*:*:*:*:*:*", + Vulnerable: boolptr(false), + }, + }, + }, + }, + }, + }, + }, }, }, { diff --git a/pkg/vulnsrc/nvd/testdata/vuln-list/nvd/CVE-2021-0109.json b/pkg/vulnsrc/nvd/testdata/vuln-list/nvd/CVE-2021-0109.json new file mode 100644 index 00000000..84330eef --- /dev/null +++ b/pkg/vulnsrc/nvd/testdata/vuln-list/nvd/CVE-2021-0109.json @@ -0,0 +1,115 @@ +{ + "configurations": { + "CVE_data_version": "4.0", + "nodes": [ + { + "children": [ + { + "cpe_match": [ + { + "cpe23Uri": "cpe:2.3:o:intel:compute_stick_stk1a32sc_firmware:*:*:*:*:*:*:*:*", + "versionEndExcluding": "604", + "vulnerable": true + } + ], + "operator": "OR" + }, + { + "cpe_match": [ + { + "cpe23Uri": "cpe:2.3:h:intel:compute_stick_stk1a32sc:-:*:*:*:*:*:*:*", + "vulnerable": false + } + ], + "operator": "OR" + } + ], + "operator": "AND" + } + ] + }, + "cve": { + "CVE_data_meta": { + "ASSIGNER": "cve@mitre.org", + "ID": "CVE-2021-0109" + }, + "data_format": "MITRE", + "data_type": "CVE", + "data_version": "4.0", + "description": { + "description_data": [ + { + "lang": "en", + "value": "Insecure inherited permissions for the Intel(R) SOC driver package for STK1A32SC before version 604 may allow an authenticated user to potentially enable escalation of privilege via local access." + } + ] + }, + "problemtype": { + "problemtype_data": [ + { + "description": [ + { + "lang": "en", + "value": "NVD-CWE-Other" + } + ] + } + ] + }, + "references": { + "reference_data": [ + { + "name": "https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00471.html", + "refsource": "MISC", + "tags": [ + "Vendor Advisory" + ], + "url": "https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00471.html" + } + ] + } + }, + "impact": { + "baseMetricV2": { + "acInsufInfo": false, + "cvssV2": { + "accessComplexity": "LOW", + "accessVector": "LOCAL", + "authentication": "NONE", + "availabilityImpact": "PARTIAL", + "baseScore": 4.6, + "confidentialityImpact": "PARTIAL", + "integrityImpact": "PARTIAL", + "vectorString": "AV:L/AC:L/Au:N/C:P/I:P/A:P", + "version": "2.0" + }, + "exploitabilityScore": 3.9, + "impactScore": 6.4, + "obtainAllPrivilege": false, + "obtainOtherPrivilege": false, + "obtainUserPrivilege": false, + "severity": "MEDIUM", + "userInteractionRequired": false + }, + "baseMetricV3": { + "cvssV3": { + "attackComplexity": "LOW", + "attackVector": "LOCAL", + "availabilityImpact": "HIGH", + "baseScore": 7.8, + "baseSeverity": "HIGH", + "confidentialityImpact": "HIGH", + "integrityImpact": "HIGH", + "privilegesRequired": "LOW", + "scope": "UNCHANGED", + "userInteraction": "NONE", + "vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", + "version": "3.1" + }, + "exploitabilityScore": 1.8, + "impactScore": 5.9 + } + }, + "lastModifiedDate": "2021-02-22T20:23Z", + "publishedDate": "2021-02-17T14:15Z" +} \ No newline at end of file diff --git a/pkg/vulnsrc/nvd/types.go b/pkg/vulnsrc/nvd/types.go index 280273b2..18f1067c 100644 --- a/pkg/vulnsrc/nvd/types.go +++ b/pkg/vulnsrc/nvd/types.go @@ -1,11 +1,17 @@ package nvd +import ( + "encoding/json" + + "github.com/aquasecurity/trivy-db/pkg/types" +) + type NVD struct { CVEItems []Item `json:"CVE_Items"` } type Item struct { - Configurations interface{} + Configurations Configurations Cve Cve Impact Impact LastModifiedDate string `json:"lastModifiedDate"` @@ -78,3 +84,32 @@ type ProblemTypeDataDescription struct { Lang string Value string } + +type Configurations struct { + CveDataVersion string `json:"CVE_data_version"` + Nodes []Node `json:"nodes,omitempty"` +} + +type Node struct { + Children []Node `json:"children,omitempty"` + Operator string `json:"operator,omitempty"` + CPEMatch []Node `json:"cpe_match,omitempty"` + Cpe23Uri string `json:"cpe23Uri,omitempty"` + VersionEndExcluding string `json:"versionEndExcluding,omitempty"` + Vulnerable *bool `json:"vulnerable,omitempty"` +} + +func mapConfigurationsToCPEDetails(configuration Configurations, cpeDetail *types.CPEDetails) error { + rawJson, err := json.Marshal(configuration) + if err != nil { + return err + } + if err = json.Unmarshal(rawJson, &cpeDetail); err != nil { + return err + } + return nil +} + +func boolptr(val bool) *bool { + return &val +} diff --git a/pkg/vulnsrc/vulnerability/vulnerability.go b/pkg/vulnsrc/vulnerability/vulnerability.go index a7d06c9f..8657eda8 100644 --- a/pkg/vulnsrc/vulnerability/vulnerability.go +++ b/pkg/vulnsrc/vulnerability/vulnerability.go @@ -46,7 +46,7 @@ func (Vulnerability) IsRejected(details map[string]types.VulnerabilityDetail) bo } func (Vulnerability) Normalize(details map[string]types.VulnerabilityDetail) types.Vulnerability { - return types.Vulnerability{ + vuln := types.Vulnerability{ Title: getTitle(details), Description: getDescription(details), Severity: getSeverity(details).String(), // TODO: We have to keep this key until we deprecate @@ -57,6 +57,10 @@ func (Vulnerability) Normalize(details map[string]types.VulnerabilityDetail) typ PublishedDate: details[Nvd].PublishedDate, LastModifiedDate: details[Nvd].LastModifiedDate, } + if details[Nvd].CPEDetails.CveDataVersion != "" { + vuln.CPEDetails = details[Nvd].CPEDetails + } + return vuln } func (v Vulnerability) SaveAdvisoryDetails(tx *bolt.Tx, cveID string) error { From 5d376c416b81f31bb19164bfa7d9a352ffedfd6b Mon Sep 17 00:00:00 2001 From: Rahul Yadav Date: Thu, 22 Apr 2021 11:45:42 +0530 Subject: [PATCH 3/5] fixed JSON field names. --- pkg/types/types.go | 16 +++++++-------- pkg/vulnsrc/nvd/types.go | 44 ++++++++++++++++++++++++++++++++-------- 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/pkg/types/types.go b/pkg/types/types.go index 0ae2f294..a5b76323 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -99,17 +99,17 @@ type VulnerabilityDetail struct { } type CPEDetails struct { - CveDataVersion string `json:"CVE_data_version"` - Nodes []Node `json:"nodes,omitempty"` + CveDataVersion string `json:"CVEDataVersion"` + Nodes []Node `json:"Nodes,omitempty"` } type Node struct { - Children []Node `json:"children,omitempty"` - Operator string `json:"operator,omitempty"` - CPEMatch []Node `json:"cpe_match,omitempty"` - Cpe23Uri string `json:"cpe23Uri,omitempty"` - VersionEndExcluding string `json:"versionEndExcluding,omitempty"` - Vulnerable *bool `json:"vulnerable,omitempty"` + Children []Node `json:"Children,omitempty"` + Operator string `json:"Operator,omitempty"` + CPEMatch []Node `json:"CpeMatch,omitempty"` + Cpe23Uri string `json:"Cpe23Uri,omitempty"` + VersionEndExcluding string `json:"VersionEndExcluding,omitempty"` + Vulnerable *bool `json:"Vulnerable,omitempty"` } type AdvisoryDetail struct { diff --git a/pkg/vulnsrc/nvd/types.go b/pkg/vulnsrc/nvd/types.go index 18f1067c..6242f1d1 100644 --- a/pkg/vulnsrc/nvd/types.go +++ b/pkg/vulnsrc/nvd/types.go @@ -1,8 +1,6 @@ package nvd import ( - "encoding/json" - "github.com/aquasecurity/trivy-db/pkg/types" ) @@ -100,16 +98,46 @@ type Node struct { } func mapConfigurationsToCPEDetails(configuration Configurations, cpeDetail *types.CPEDetails) error { - rawJson, err := json.Marshal(configuration) - if err != nil { - return err - } - if err = json.Unmarshal(rawJson, &cpeDetail); err != nil { - return err + cpeDetail.CveDataVersion = configuration.CveDataVersion + if configuration.Nodes != nil { + for _, n := range configuration.Nodes { + var cpeNode types.Node + mapConfigNodeToCPENode(n, &cpeNode) + cpeDetail.Nodes = append(cpeDetail.Nodes, cpeNode) + } } return nil } +func mapConfigNodeToCPENode(configNode Node, cpeNode *types.Node) { + if configNode.Operator != "" { + cpeNode.Operator = configNode.Operator + } + if configNode.Cpe23Uri != "" { + cpeNode.Cpe23Uri = configNode.Cpe23Uri + } + if configNode.VersionEndExcluding != "" { + cpeNode.VersionEndExcluding = configNode.VersionEndExcluding + } + if configNode.Vulnerable != nil { + cpeNode.Vulnerable = configNode.Vulnerable + } + if configNode.Children != nil { + for _, n := range configNode.Children { + var cpeChildNode types.Node + mapConfigNodeToCPENode(n, &cpeChildNode) + cpeNode.Children = append(cpeNode.Children, cpeChildNode) + } + } + if configNode.CPEMatch != nil { + for _, n := range configNode.CPEMatch { + var cpeMatchNode types.Node + mapConfigNodeToCPENode(n, &cpeMatchNode) + cpeNode.CPEMatch = append(cpeNode.CPEMatch, cpeMatchNode) + } + } +} + func boolptr(val bool) *bool { return &val } From 0407c989d34c0d5ee463db46c0b82ba53b1b3b01 Mon Sep 17 00:00:00 2001 From: Rahul Yadav Date: Thu, 22 Apr 2021 11:54:09 +0530 Subject: [PATCH 4/5] removed error return --- pkg/vulnsrc/nvd/nvd.go | 4 +--- pkg/vulnsrc/nvd/types.go | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/pkg/vulnsrc/nvd/nvd.go b/pkg/vulnsrc/nvd/nvd.go index 7f9a9dfd..438dcd63 100644 --- a/pkg/vulnsrc/nvd/nvd.go +++ b/pkg/vulnsrc/nvd/nvd.go @@ -107,9 +107,7 @@ func (vs VulnSrc) commit(tx *bolt.Tx, items []Item) error { LastModifiedDate: &lastModifiedDate, } if item.Configurations.CveDataVersion != "" { - if err := mapConfigurationsToCPEDetails(item.Configurations, &vuln.CPEDetails); err != nil { - log.Printf("error mapping cpe details: %v\n", err) - } + mapConfigurationsToCPEDetails(item.Configurations, &vuln.CPEDetails) } if err := vs.dbc.PutVulnerabilityDetail(tx, cveID, vulnerability.Nvd, vuln); err != nil { return err diff --git a/pkg/vulnsrc/nvd/types.go b/pkg/vulnsrc/nvd/types.go index 6242f1d1..e315a204 100644 --- a/pkg/vulnsrc/nvd/types.go +++ b/pkg/vulnsrc/nvd/types.go @@ -97,7 +97,7 @@ type Node struct { Vulnerable *bool `json:"vulnerable,omitempty"` } -func mapConfigurationsToCPEDetails(configuration Configurations, cpeDetail *types.CPEDetails) error { +func mapConfigurationsToCPEDetails(configuration Configurations, cpeDetail *types.CPEDetails) { cpeDetail.CveDataVersion = configuration.CveDataVersion if configuration.Nodes != nil { for _, n := range configuration.Nodes { @@ -106,7 +106,7 @@ func mapConfigurationsToCPEDetails(configuration Configurations, cpeDetail *type cpeDetail.Nodes = append(cpeDetail.Nodes, cpeNode) } } - return nil + return } func mapConfigNodeToCPENode(configNode Node, cpeNode *types.Node) { From 91d18c9c3834cf30d819766bf9765d74d1bd48f4 Mon Sep 17 00:00:00 2001 From: Rahul Yadav Date: Thu, 22 Apr 2021 12:07:34 +0530 Subject: [PATCH 5/5] remove return --- pkg/vulnsrc/nvd/types.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/vulnsrc/nvd/types.go b/pkg/vulnsrc/nvd/types.go index e315a204..12526042 100644 --- a/pkg/vulnsrc/nvd/types.go +++ b/pkg/vulnsrc/nvd/types.go @@ -106,7 +106,6 @@ func mapConfigurationsToCPEDetails(configuration Configurations, cpeDetail *type cpeDetail.Nodes = append(cpeDetail.Nodes, cpeNode) } } - return } func mapConfigNodeToCPENode(configNode Node, cpeNode *types.Node) {