Support the case when Red Hat returns the different type (#8)

This commit is contained in:
Teppei Fukuda 2019-09-28 02:35:47 +03:00 committed by GitHub
parent cb535a8983
commit 9eea8f0eaa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 396 additions and 18 deletions

1
go.mod
View File

@ -10,6 +10,7 @@ require (
github.com/fatih/color v1.7.0 // indirect github.com/fatih/color v1.7.0 // indirect
github.com/hashicorp/go-version v1.2.0 github.com/hashicorp/go-version v1.2.0
github.com/kr/pretty v0.1.0 // indirect github.com/kr/pretty v0.1.0 // indirect
github.com/kylelemons/godebug v1.1.0
github.com/mattn/go-colorable v0.1.1 // indirect github.com/mattn/go-colorable v0.1.1 // indirect
github.com/mattn/go-jsonpointer v0.0.0-20180225143300-37667080efed github.com/mattn/go-jsonpointer v0.0.0-20180225143300-37667080efed
github.com/mattn/go-runewidth v0.0.4 // indirect github.com/mattn/go-runewidth v0.0.4 // indirect

2
go.sum
View File

@ -19,6 +19,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw= github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw=

View File

@ -21,14 +21,6 @@ const (
retry = 20 // Red Hat Security Data API is unstable retry = 20 // Red Hat Security Data API is unstable
) )
type RedhatEntry struct {
CveID string `json:"CVE"`
}
type RedhatCVEJSON struct {
Name string `json:"name"`
}
func Update(years []int) error { func Update(years []int) error {
for _, year := range years { for _, year := range years {
if err := update(year); err != nil { if err := update(year); err != nil {
@ -96,8 +88,8 @@ func listAllRedhatCves(after, before string, wait int) (entries []RedhatEntry, e
// retrieveRedhatCveDetails returns full CVE details from RedHat API // retrieveRedhatCveDetails returns full CVE details from RedHat API
// https://access.redhat.com/documentation/en-us/red_hat_security_data_api/0.1/html-single/red_hat_security_data_api/#retrieve_a_cve // https://access.redhat.com/documentation/en-us/red_hat_security_data_api/0.1/html-single/red_hat_security_data_api/#retrieve_a_cve
func retrieveRedhatCveDetails(urls []string) (map[string]interface{}, error) { func retrieveRedhatCveDetails(urls []string) (map[string]*RedhatCVEJSON, error) {
cves := map[string]interface{}{} cves := map[string]*RedhatCVEJSON{}
cveJSONs, err := utils.FetchConcurrently(urls, concurrency, wait, retry) cveJSONs, err := utils.FetchConcurrently(urls, concurrency, wait, retry)
if err != nil { if err != nil {
@ -105,17 +97,12 @@ func retrieveRedhatCveDetails(urls []string) (map[string]interface{}, error) {
} }
for _, cveJSON := range cveJSONs { for _, cveJSON := range cveJSONs {
var cve RedhatCVEJSON cve := &RedhatCVEJSON{}
if err = json.Unmarshal(cveJSON, &cve); err != nil { if err = json.Unmarshal(cveJSON, cve); err != nil {
log.Printf("json decode error: %s", err) log.Printf("json decode error: %s", err)
continue continue
} }
var cveInterface interface{} cves[cve.Name] = cve
if err = json.Unmarshal(cveJSON, &cveInterface); err != nil {
log.Printf("json decode error: %s", err)
continue
}
cves[cve.Name] = cveInterface
} }
return cves, nil return cves, nil

32
redhat/testdata/CVE-2009-2694.json vendored Normal file
View File

@ -0,0 +1,32 @@
{
"threat_severity": "Critical",
"public_date": "2009-08-18T00:00:00Z",
"bugzilla": {
"description": "\nCVE-2009-2694 pidgin: insufficient input validation in msn_slplink_process_msg()\n ",
"id": "514957",
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=514957"
},
"cvss": {
"cvss_base_score": "7.5",
"cvss_scoring_vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P",
"status": "verified"
},
"cwe": "CWE-228->CWE-119",
"details": [
"\nThe msn_slplink_process_msg function in libpurple/protocols/msn/slplink.c in libpurple, as used in Pidgin (formerly Gaim) before 2.5.9 and Adium 1.3.5 and earlier, allows remote attackers to execute arbitrary code or cause a denial of service (memory corruption and application crash) by sending multiple crafted SLP (aka MSNSLP) messages to trigger an overwrite of an arbitrary memory location. NOTE: this issue reportedly exists because of an incomplete fix for CVE-2009-1376.\n "
],
"affected_release": [
{
"product_name": "Red Hat Enterprise Linux 3",
"release_date": "2009-08-18T00:00:00Z",
"advisory": "RHSA-2009:1218",
"cpe": "cpe:/o:redhat:enterprise_linux:3",
"package": "pidgin-1.5.1-4.el3"
}
],
"name": "CVE-2009-2694",
"mitigation": {
"value": "\nUsers can lower the impact of this flaw by making sure their privacy settings only allow Pidgin to accept messages from the users on their buddy list. This will prevent exploitation of this flaw by other random MSN users.\n ",
"lang": "en:us"
}
}

36
redhat/testdata/CVE-2019-7614.json vendored Normal file
View File

@ -0,0 +1,36 @@
{
"bugzilla": {
"description": "\nCVE-2019-7614 elasticsearch: Race condition in response headers on systems with multiple submitting requests\n ",
"id": "1747240",
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=1747240"
},
"cvss3": {
"cvss3_base_score": "2.0",
"cvss3_scoring_vector": "CVSS:3.0/AV:A/AC:H/PR:H/UI:N/S:U/C:L/I:N/A:N",
"status": "draft"
},
"cwe": "CWE-362",
"details": [
"\nA race condition flaw was found in the response headers Elasticsearch versions before 7.2.1 and 6.8.2 returns to a request. On a system with multiple users submitting requests, it could be possible for an attacker to gain access to response header containing sensitive data from another user.\n "
],
"mitigation": "\nThere is no mitigation for this issue, the flaw can only be resolved by applying updates.\n ",
"name": "CVE-2019-7614",
"package_state": [
{
"cpe": "cpe:/a:redhat:jboss_fuse:6",
"fix_state": "Out of support scope",
"package_name": "elasticsearch",
"product_name": "Red Hat JBoss Fuse 6"
},
{
"cpe": "cpe:/a:redhat:jboss_fuse:7",
"fix_state": "New",
"package_name": "elasticsearch",
"product_name": "Red Hat JBoss Fuse 7"
}
],
"public_date": "2019-07-31T00:00:00",
"statement": "\nRed Hat JBoss Fuse 6: \nThis vulnerability has been rated as having a security impact of Low. After evaluation and in accordance with the criteria noted in the product support life cycle, there are no plans to address this issue in an upcoming release. Please contact Red Hat Support for further information.\n ",
"threat_severity": "Low",
"upstream_fix": "elasticsearch 7.2.1, elasticsearch 6.8.2"
}

186
redhat/types.go Normal file
View File

@ -0,0 +1,186 @@
package redhat
import (
"encoding/json"
"golang.org/x/xerrors"
)
type RedhatEntry struct {
CveID string `json:"CVE"`
}
type RedhatCVEJSON struct {
ThreatSeverity string `json:"threat_severity"`
PublicDate string `json:"public_date"`
Bugzilla RedhatBugzilla `json:"bugzilla"`
Cvss RedhatCvss `json:"cvss"`
Cvss3 RedhatCvss3 `json:"cvss3"`
Iava string `json:"iava"`
Cwe string `json:"cwe"`
Statement string `json:"statement"`
Acknowledgement string `json:"acknowledgement"`
Mitigation string `json:"-"`
AffectedRelease []RedhatAffectedRelease `json:"-"`
PackageState []RedhatPackageState `json:"-"`
Name string `json:"name"`
DocumentDistribution string `json:"document_distribution"`
Details []string `json:"details"`
References []string `json:"references"`
}
func (r *RedhatCVEJSON) UnmarshalJSON(data []byte) error {
type AliasRedhatCVEJSON RedhatCVEJSON
alias := &struct {
TempMitigation interface{} `json:"mitigation"` // mitigation is string or object
TempAffectedRelease interface{} `json:"affected_release"` // affected_release is array or object
TempPackageState interface{} `json:"package_state"` // package_state is array or object
*AliasRedhatCVEJSON
}{
AliasRedhatCVEJSON: (*AliasRedhatCVEJSON)(r),
}
if err := json.Unmarshal(data, alias); err != nil {
return err
}
switch alias.TempAffectedRelease.(type) {
case []interface{}:
var ar RedhatCVEJSONAffectedReleaseArray
if err := json.Unmarshal(data, &ar); err != nil {
return xerrors.Errorf("unknown affected_release type: %w", err)
}
r.AffectedRelease = ar.AffectedRelease
case map[string]interface{}:
var ar RedhatCVEJSONAffectedReleaseObject
if err := json.Unmarshal(data, &ar); err != nil {
return xerrors.Errorf("unknown affected_release type: %w", err)
}
r.AffectedRelease = []RedhatAffectedRelease{ar.AffectedRelease}
case nil:
default:
return xerrors.New("unknown affected_release type")
}
switch alias.TempPackageState.(type) {
case []interface{}:
var ps RedhatCVEJSONPackageStateArray
if err := json.Unmarshal(data, &ps); err != nil {
return xerrors.Errorf("unknown package_state type: %w", err)
}
r.PackageState = ps.PackageState
case map[string]interface{}:
var ps RedhatCVEJSONPackageStateObject
if err := json.Unmarshal(data, &ps); err != nil {
return xerrors.Errorf("unknown package_state type: %w", err)
}
r.PackageState = []RedhatPackageState{ps.PackageState}
case nil:
default:
return xerrors.New("unknown package_state type")
}
switch alias.TempMitigation.(type) {
case string:
r.Mitigation = alias.TempMitigation.(string)
case map[string]interface{}:
var m struct {
Mitigation RedhatCVEJSONMitigationObject
}
if err := json.Unmarshal(data, &m); err != nil {
return xerrors.Errorf("unknown package_state type: %w", err)
}
r.Mitigation = m.Mitigation.Value
case nil:
default:
return xerrors.New("unknown package_state type")
}
return nil
}
func (r *RedhatCVEJSON) MarshalJSON() ([]byte, error) {
type Alias RedhatCVEJSON
return json.Marshal(&struct {
TempMitigation string `json:"mitigation,omitempty"`
TempAffectedRelease interface{} `json:"affected_release,omitempty"` // affected_release is array or object
TempPackageState interface{} `json:"package_state,omitempty"` // package_state is array or object
*Alias
}{
TempMitigation: r.Mitigation,
TempAffectedRelease: r.AffectedRelease,
TempPackageState: r.PackageState,
Alias: (*Alias)(r),
})
}
type RedhatCVEJSONAffectedReleaseArray struct {
AffectedRelease []RedhatAffectedRelease `json:"affected_release"`
}
type RedhatCVEJSONAffectedReleaseObject struct {
AffectedRelease RedhatAffectedRelease `json:"affected_release"`
}
type RedhatCVEJSONPackageStateArray struct {
PackageState []RedhatPackageState `json:"package_state"`
}
type RedhatCVEJSONPackageStateObject struct {
PackageState RedhatPackageState `json:"package_state"`
}
type RedhatCVEJSONMitigationObject struct {
Value string
Lang string
}
type RedhatDetail struct {
RedhatCVEID int64 `json:",omitempty"`
Detail string
}
type RedhatReference struct {
RedhatCVEID int64 `json:",omitempty"`
Reference string
}
type RedhatBugzilla struct {
RedhatCVEID int64 `json:",omitempty"`
Description string `json:"description"`
BugzillaID string `json:"id"`
URL string `json:"url"`
}
type RedhatCvss struct {
RedhatCVEID int64 `json:",omitempty"`
CvssBaseScore string `json:"cvss_base_score"`
CvssScoringVector string `json:"cvss_scoring_vector"`
Status string `json:"status"`
}
type RedhatCvss3 struct {
RedhatCVEID int64 `json:",omitempty"`
Cvss3BaseScore string `json:"cvss3_base_score"`
Cvss3ScoringVector string `json:"cvss3_scoring_vector"`
Status string `json:"status"`
}
type RedhatAffectedRelease struct {
RedhatCVEID int64 `json:",omitempty"`
ProductName string `json:"product_name"`
ReleaseDate string `json:"release_date"`
Advisory string `json:"advisory"`
Package string `json:"package"`
Cpe string `json:"cpe"`
}
type RedhatPackageState struct {
RedhatCVEID int64 `json:",omitempty"`
ProductName string `json:"product_name"`
FixState string `json:"fix_state"`
PackageName string `json:"package_name"`
Cpe string `json:"cpe"`
}

134
redhat/types_test.go Normal file
View File

@ -0,0 +1,134 @@
package redhat_test
import (
"encoding/json"
"io/ioutil"
"reflect"
"testing"
"github.com/aquasecurity/vuln-list-update/redhat"
"github.com/kylelemons/godebug/pretty"
)
func TestRedhatCVEJSON_UnmarshalJSON(t *testing.T) {
tests := map[string]struct {
in string
want *redhat.RedhatCVEJSON
}{
"mitigation_string": {
in: "testdata/CVE-2019-7614.json",
want: &redhat.RedhatCVEJSON{
ThreatSeverity: "Low",
PublicDate: "2019-07-31T00:00:00",
Bugzilla: redhat.RedhatBugzilla{
RedhatCVEID: 0,
Description: "\nCVE-2019-7614 elasticsearch: Race condition in response headers on systems with multiple submitting requests\n ",
BugzillaID: "1747240",
URL: "https://bugzilla.redhat.com/show_bug.cgi?id=1747240",
},
Cvss: redhat.RedhatCvss{
RedhatCVEID: 0,
CvssBaseScore: "",
CvssScoringVector: "",
Status: "",
},
Cvss3: redhat.RedhatCvss3{
RedhatCVEID: 0,
Cvss3BaseScore: "2.0",
Cvss3ScoringVector: "CVSS:3.0/AV:A/AC:H/PR:H/UI:N/S:U/C:L/I:N/A:N",
Status: "draft",
},
Iava: "",
Cwe: "CWE-362",
Statement: "\nRed Hat JBoss Fuse 6: \nThis vulnerability has been rated as having a security impact of Low. After evaluation and in accordance with the criteria noted in the product support life cycle, there are no plans to address this issue in an upcoming release. Please contact Red Hat Support for further information.\n ",
Acknowledgement: "",
Mitigation: "\nThere is no mitigation for this issue, the flaw can only be resolved by applying updates.\n ",
PackageState: []redhat.RedhatPackageState{
{
RedhatCVEID: 0,
ProductName: "Red Hat JBoss Fuse 6",
FixState: "Out of support scope",
PackageName: "elasticsearch",
Cpe: "cpe:/a:redhat:jboss_fuse:6",
},
{
RedhatCVEID: 0,
ProductName: "Red Hat JBoss Fuse 7",
FixState: "New",
PackageName: "elasticsearch",
Cpe: "cpe:/a:redhat:jboss_fuse:7",
},
},
//AffectedRelease: []redhat.RedhatAffectedRelease{},
Name: "CVE-2019-7614",
DocumentDistribution: "",
Details: []string{
"\nA race condition flaw was found in the response headers Elasticsearch versions before 7.2.1 and 6.8.2 returns to a request. On a system with multiple users submitting requests, it could be possible for an attacker to gain access to response header containing sensitive data from another user.\n ",
},
//References: []string{},
},
},
"mitigation_object": {
in: "testdata/CVE-2009-2694.json",
want: &redhat.RedhatCVEJSON{
ThreatSeverity: "Critical",
PublicDate: "2009-08-18T00:00:00Z",
Bugzilla: redhat.RedhatBugzilla{
RedhatCVEID: 0,
Description: "\nCVE-2009-2694 pidgin: insufficient input validation in msn_slplink_process_msg()\n ",
BugzillaID: "514957",
URL: "https://bugzilla.redhat.com/show_bug.cgi?id=514957",
},
Cvss: redhat.RedhatCvss{
RedhatCVEID: 0,
CvssBaseScore: "7.5",
CvssScoringVector: "AV:N/AC:L/Au:N/C:P/I:P/A:P",
Status: "verified",
},
Cvss3: redhat.RedhatCvss3{
RedhatCVEID: 0,
Cvss3BaseScore: "",
Cvss3ScoringVector: "",
Status: "",
},
Iava: "",
Cwe: "CWE-228->CWE-119",
Statement: "",
Acknowledgement: "",
Mitigation: "\nUsers can lower the impact of this flaw by making sure their privacy settings only allow Pidgin to accept messages from the users on their buddy list. This will prevent exploitation of this flaw by other random MSN users.\n ",
AffectedRelease: []redhat.RedhatAffectedRelease{
redhat.RedhatAffectedRelease{
RedhatCVEID: 0,
ProductName: "Red Hat Enterprise Linux 3",
ReleaseDate: "2009-08-18T00:00:00Z",
Advisory: "RHSA-2009:1218",
Package: "pidgin-1.5.1-4.el3",
Cpe: "cpe:/o:redhat:enterprise_linux:3",
},
},
Name: "CVE-2009-2694",
DocumentDistribution: "",
Details: []string{
"\nThe msn_slplink_process_msg function in libpurple/protocols/msn/slplink.c in libpurple, as used in Pidgin (formerly Gaim) before 2.5.9 and Adium 1.3.5 and earlier, allows remote attackers to execute arbitrary code or cause a denial of service (memory corruption and application crash) by sending multiple crafted SLP (aka MSNSLP) messages to trigger an overwrite of an arbitrary memory location. NOTE: this issue reportedly exists because of an incomplete fix for CVE-2009-1376.\n ",
},
},
},
}
for testname, tt := range tests {
t.Run(testname, func(t *testing.T) {
jsonByte, err := ioutil.ReadFile(tt.in)
if err != nil {
t.Fatalf("unknown error: %s", err)
}
got := &redhat.RedhatCVEJSON{}
err = json.Unmarshal(jsonByte, got)
if err != nil {
t.Fatalf("unknown error: %s", err)
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("[%s]\n diff: %s", testname, pretty.Compare(got, tt.want))
}
})
}
}