diff --git a/pkg/vulnsrc/ghsa/ghsa.go b/pkg/vulnsrc/ghsa/ghsa.go index 93dc78c1..81671234 100644 --- a/pkg/vulnsrc/ghsa/ghsa.go +++ b/pkg/vulnsrc/ghsa/ghsa.go @@ -40,7 +40,8 @@ var ( ) type DatabaseSpecific struct { - Severity string `json:"severity"` + Severity string `json:"severity"` + LastKnownAffectedVersionRange string `json:"last_known_affected_version_range"` } type GHSA struct{} @@ -95,6 +96,12 @@ func (t *transformer) TransformAdvisories(advisories []osv.Advisory, entry osv.E severity := convertSeverity(specific.Severity) for i, adv := range advisories { + // Parse database_specific + if err := parseDatabaseSpecific(adv); err != nil { + return nil, xerrors.Errorf("failed to parse database specific: %w", err) + } + + // Fill severity from GHSA advisories[i].Severity = severity // Replace a git URL with a CocoaPods package name in a Swift vulnerability @@ -112,6 +119,33 @@ func (t *transformer) TransformAdvisories(advisories []osv.Advisory, entry osv.E return advisories, nil } +// parseDatabaseSpecific adds a version from the last_known_affected_version_range field +// cf. https://github.com/github/advisory-database/issues/470#issuecomment-1998604377 +func parseDatabaseSpecific(advisory osv.Advisory) error { + // Skip if the `affected[].database_specific` field doesn't exist + if advisory.DatabaseSpecific == nil { + return nil + } + + var affectedSpecific DatabaseSpecific + if err := json.Unmarshal(advisory.DatabaseSpecific, &affectedSpecific); err != nil { + return xerrors.Errorf("JSON decode error: %w", err) + } + + for i, vulnVersion := range advisory.VulnerableVersions { + // The fixed and last_affected fields (which use <, <=, or =) take precedence over + // the last_known_affected_version_range field. + if strings.Contains(vulnVersion, "<") || strings.HasPrefix(vulnVersion, "=") { + continue + } + // `last_known_affected_version_range` uses `< version` or `<= version` formats (e.g. `< 1.2.3` or `<= 1.2.3`). + // Remove spaces to match our format + verRange := strings.ReplaceAll(affectedSpecific.LastKnownAffectedVersionRange, " ", "") + advisory.VulnerableVersions[i] = fmt.Sprintf("%s, %s", vulnVersion, verRange) + } + return nil +} + func convertSeverity(severity string) types.Severity { switch severity { case "LOW": diff --git a/pkg/vulnsrc/ghsa/ghsa_test.go b/pkg/vulnsrc/ghsa/ghsa_test.go index 2037fd16..df0cbf32 100644 --- a/pkg/vulnsrc/ghsa/ghsa_test.go +++ b/pkg/vulnsrc/ghsa/ghsa_test.go @@ -73,6 +73,72 @@ func TestVulnSrc_Update(t *testing.T) { }, Value: map[string]interface{}{}, }, + { + Key: []string{ + "data-source", + "maven::GitHub Security Advisory Maven", + }, + Value: types.DataSource{ + ID: vulnerability.GHSA, + Name: "GitHub Security Advisory Maven", + URL: "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Amaven", + }, + }, + { + Key: []string{ + "advisory-detail", + "CVE-2023-25330", + "maven::GitHub Security Advisory Maven", + "com.baomidou:mybatis-plus", + }, + Value: types.Advisory{ + VendorIDs: []string{ + "GHSA-32qq-m9fh-f74w", + }, + VulnerableVersions: []string{">=0, <3.5.3.1"}, + }, + }, + { + Key: []string{ + "advisory-detail", + "CVE-2023-25330", + "maven::GitHub Security Advisory Maven", + "com.baomidou:mybatis-plus-copy", + }, + Value: types.Advisory{ + VendorIDs: []string{ + "GHSA-32qq-m9fh-f74w", + }, + PatchedVersions: []string{"3.5.0"}, + VulnerableVersions: []string{"<3.5.0"}, + }, + }, + { + Key: []string{ + "vulnerability-detail", + "CVE-2023-25330", + "ghsa", + }, + Value: types.VulnerabilityDetail{ + Title: "MyBatis-Plus vulnerable to SQL injection via TenantPlugin", + Description: "MyBatis-Plus below 3.5.3.1 is vulnerable to SQL injection via the tenant ID value. This may allow remote attackers to execute arbitrary SQL commands.", + References: []string{ + "https://nvd.nist.gov/vuln/detail/CVE-2023-25330", + "https://github.com/FCncdn/MybatisPlusTenantPluginSQLInjection-POC/blob/master/Readme.en.md", + "https://github.com/baomidou/mybatis-plus", + }, + Severity: types.SeverityCritical, + CvssVectorV3: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + CvssScoreV3: 9.8, + }, + }, + { + Key: []string{ + "vulnerability-id", + "CVE-2023-25330", + }, + Value: map[string]interface{}{}, + }, { Key: []string{ "data-source", diff --git a/pkg/vulnsrc/ghsa/testdata/happy/ghsa/advisories/github-reviewed/2023/04/GHSA-32qq-m9fh-f74w/GHSA-32qq-m9fh-f74w.json b/pkg/vulnsrc/ghsa/testdata/happy/ghsa/advisories/github-reviewed/2023/04/GHSA-32qq-m9fh-f74w/GHSA-32qq-m9fh-f74w.json new file mode 100644 index 00000000..75beaab5 --- /dev/null +++ b/pkg/vulnsrc/ghsa/testdata/happy/ghsa/advisories/github-reviewed/2023/04/GHSA-32qq-m9fh-f74w/GHSA-32qq-m9fh-f74w.json @@ -0,0 +1,83 @@ +{ + "schema_version": "1.4.0", + "id": "GHSA-32qq-m9fh-f74w", + "modified": "2023-04-14T20:31:15Z", + "published": "2023-04-05T15:30:24Z", + "aliases": [ + "CVE-2023-25330" + ], + "summary": "MyBatis-Plus vulnerable to SQL injection via TenantPlugin", + "details": "MyBatis-Plus below 3.5.3.1 is vulnerable to SQL injection via the tenant ID value. This may allow remote attackers to execute arbitrary SQL commands.", + "severity": [ + { + "type": "CVSS_V3", + "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" + } + ], + "affected": [ + { + "package": { + "ecosystem": "Maven", + "name": "com.baomidou:mybatis-plus" + }, + "ranges": [ + { + "type": "ECOSYSTEM", + "events": [ + { + "introduced": "0" + } + ] + } + ], + "database_specific": { + "last_known_affected_version_range": "< 3.5.3.1" + } + }, + { + "package": { + "ecosystem": "Maven", + "name": "com.baomidou:mybatis-plus-copy" + }, + "ranges": [ + { + "type": "ECOSYSTEM", + "events": [ + { + "introduced": "0" + }, + { + "fixed": "3.5.0" + } + ] + } + ], + "database_specific": { + "last_known_affected_version_range": "< 3.5.3.1" + } + } + ], + "references": [ + { + "type": "ADVISORY", + "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-25330" + }, + { + "type": "WEB", + "url": "https://github.com/FCncdn/MybatisPlusTenantPluginSQLInjection-POC/blob/master/Readme.en.md" + }, + { + "type": "PACKAGE", + "url": "https://github.com/baomidou/mybatis-plus" + } + ], + "database_specific": { + "cwe_ids": [ + "CWE-89" + ], + "severity": "CRITICAL", + "github_reviewed": true, + "github_reviewed_at": "2023-04-05T21:13:04Z", + "nvd_published_at": "2023-04-05T14:15:00Z" + } +} \ No newline at end of file diff --git a/pkg/vulnsrc/osv/osv.go b/pkg/vulnsrc/osv/osv.go index f17bf2d3..6bd03258 100644 --- a/pkg/vulnsrc/osv/osv.go +++ b/pkg/vulnsrc/osv/osv.go @@ -40,6 +40,9 @@ type Advisory struct { References []string CVSSScoreV3 float64 CVSSVectorV3 string + + // From affected[].database_specific + DatabaseSpecific json.RawMessage } type OSV struct { @@ -252,6 +255,7 @@ func parseAffected(entry Entry, vulnIDs, aliases, references []string) ([]Adviso References: references, CVSSVectorV3: cvssVectorV3, CVSSScoreV3: cvssScoreV3, + DatabaseSpecific: affected.DatabaseSpecific, } } } diff --git a/pkg/vulnsrc/osv/types.go b/pkg/vulnsrc/osv/types.go index b1cc3b75..648d93b5 100644 --- a/pkg/vulnsrc/osv/types.go +++ b/pkg/vulnsrc/osv/types.go @@ -55,6 +55,7 @@ type Affected struct { Ranges []Range `json:"ranges,omitempty"` Versions []string `json:"versions,omitempty"` EcosystemSpecific EcosystemSpecific `json:"ecosystem_specific"` + DatabaseSpecific json.RawMessage `json:"database_specific,omitempty"` } type Import struct {