fix(suse): fix openSUSE, openSUSE Leap, SLES, SLED scan (#1384)
* fix(suse): fix openSUSE, openSUSE Leap scan * docs: update README * fix: unknown CveContent.Type * fix: tui reporting * fix: listening port was duplicated in format-full-text * fix .gitignore * fix: add EOL data for SLES12.5 Co-authored-by: Kota Kanbe <kotakanbe@gmail.com>
This commit is contained in:
@@ -5,7 +5,6 @@ package oval
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
@@ -225,8 +224,8 @@ func (o RedHatBase) convertToModel(cveID string, def *ovalmodels.Definition) *mo
|
||||
continue
|
||||
}
|
||||
|
||||
score2, vec2 := o.parseCvss2(cve.Cvss2)
|
||||
score3, vec3 := o.parseCvss3(cve.Cvss3)
|
||||
score2, vec2 := parseCvss2(cve.Cvss2)
|
||||
score3, vec3 := parseCvss3(cve.Cvss3)
|
||||
|
||||
sev2, sev3, severity := "", "", def.Advisory.Severity
|
||||
if cve.Impact != "" {
|
||||
@@ -262,39 +261,6 @@ func (o RedHatBase) convertToModel(cveID string, def *ovalmodels.Definition) *mo
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseCvss2 divide CVSSv2 string into score and vector
|
||||
// 5/AV:N/AC:L/Au:N/C:N/I:N/A:P
|
||||
func (o RedHatBase) parseCvss2(scoreVector string) (score float64, vector string) {
|
||||
var err error
|
||||
ss := strings.Split(scoreVector, "/")
|
||||
if 1 < len(ss) {
|
||||
if score, err = strconv.ParseFloat(ss[0], 64); err != nil {
|
||||
return 0, ""
|
||||
}
|
||||
return score, strings.Join(ss[1:], "/")
|
||||
}
|
||||
return 0, ""
|
||||
}
|
||||
|
||||
// ParseCvss3 divide CVSSv3 string into score and vector
|
||||
// 5.6/CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L
|
||||
func (o RedHatBase) parseCvss3(scoreVector string) (score float64, vector string) {
|
||||
var err error
|
||||
for _, s := range []string{
|
||||
"/CVSS:3.0/",
|
||||
"/CVSS:3.1/",
|
||||
} {
|
||||
ss := strings.Split(scoreVector, s)
|
||||
if 1 < len(ss) {
|
||||
if score, err = strconv.ParseFloat(ss[0], 64); err != nil {
|
||||
return 0, ""
|
||||
}
|
||||
return score, strings.TrimPrefix(s, "/") + ss[1]
|
||||
}
|
||||
}
|
||||
return 0, ""
|
||||
}
|
||||
|
||||
// RedHat is the interface for RedhatBase OVAL
|
||||
type RedHat struct {
|
||||
RedHatBase
|
||||
|
||||
@@ -11,79 +11,6 @@ import (
|
||||
ovalmodels "github.com/vulsio/goval-dictionary/models"
|
||||
)
|
||||
|
||||
func TestParseCvss2(t *testing.T) {
|
||||
type out struct {
|
||||
score float64
|
||||
vector string
|
||||
}
|
||||
var tests = []struct {
|
||||
in string
|
||||
out out
|
||||
}{
|
||||
{
|
||||
in: "5/AV:N/AC:L/Au:N/C:N/I:N/A:P",
|
||||
out: out{
|
||||
score: 5.0,
|
||||
vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
|
||||
},
|
||||
},
|
||||
{
|
||||
in: "",
|
||||
out: out{
|
||||
score: 0,
|
||||
vector: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
s, v := RedHatBase{}.parseCvss2(tt.in)
|
||||
if s != tt.out.score || v != tt.out.vector {
|
||||
t.Errorf("\nexpected: %f, %s\n actual: %f, %s",
|
||||
tt.out.score, tt.out.vector, s, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseCvss3(t *testing.T) {
|
||||
type out struct {
|
||||
score float64
|
||||
vector string
|
||||
}
|
||||
var tests = []struct {
|
||||
in string
|
||||
out out
|
||||
}{
|
||||
{
|
||||
in: "5.6/CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
|
||||
out: out{
|
||||
score: 5.6,
|
||||
vector: "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
|
||||
},
|
||||
},
|
||||
{
|
||||
in: "6.1/CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
|
||||
out: out{
|
||||
score: 6.1,
|
||||
vector: "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
|
||||
},
|
||||
},
|
||||
{
|
||||
in: "",
|
||||
out: out{
|
||||
score: 0,
|
||||
vector: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
s, v := RedHatBase{}.parseCvss3(tt.in)
|
||||
if s != tt.out.score || v != tt.out.vector {
|
||||
t.Errorf("\nexpected: %f, %s\n actual: %f, %s",
|
||||
tt.out.score, tt.out.vector, s, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPackNamesOfUpdate(t *testing.T) {
|
||||
var tests = []struct {
|
||||
in models.ScanResult
|
||||
|
||||
26
oval/suse.go
26
oval/suse.go
@@ -4,8 +4,9 @@
|
||||
package oval
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/constant"
|
||||
"github.com/future-architect/vuls/logging"
|
||||
"github.com/future-architect/vuls/models"
|
||||
ovalmodels "github.com/vulsio/goval-dictionary/models"
|
||||
@@ -17,11 +18,10 @@ type SUSE struct {
|
||||
}
|
||||
|
||||
// NewSUSE creates OVAL client for SUSE
|
||||
func NewSUSE(cnf config.VulnDictInterface) SUSE {
|
||||
// TODO implement other family
|
||||
func NewSUSE(cnf config.VulnDictInterface, family string) SUSE {
|
||||
return SUSE{
|
||||
Base{
|
||||
family: constant.SUSEEnterpriseServer,
|
||||
family: family,
|
||||
Cnf: cnf,
|
||||
},
|
||||
}
|
||||
@@ -56,7 +56,7 @@ func (o SUSE) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
|
||||
for _, vuln := range r.ScannedCves {
|
||||
if conts, ok := vuln.CveContents[models.SUSE]; ok {
|
||||
for i, cont := range conts {
|
||||
cont.SourceLink = "https://security-tracker.debian.org/tracker/" + cont.CveID
|
||||
cont.SourceLink = fmt.Sprintf("https://www.suse.com/security/cve/%s.html", cont.CveID)
|
||||
vuln.CveContents[models.SUSE][i] = cont
|
||||
}
|
||||
}
|
||||
@@ -117,11 +117,23 @@ func (o SUSE) convertToModel(def *ovalmodels.Definition) *models.CveContent {
|
||||
RefID: r.RefID,
|
||||
})
|
||||
}
|
||||
|
||||
return &models.CveContent{
|
||||
cveCont := models.CveContent{
|
||||
CveID: def.Title,
|
||||
Title: def.Title,
|
||||
Summary: def.Description,
|
||||
References: refs,
|
||||
}
|
||||
|
||||
if 0 < len(def.Advisory.Cves) {
|
||||
if len(def.Advisory.Cves) == 1 {
|
||||
cve := def.Advisory.Cves[0]
|
||||
score3, vec3 := parseCvss3(cve.Cvss3)
|
||||
cveCont.Cvss3Score = score3
|
||||
cveCont.Cvss3Vector = vec3
|
||||
cveCont.Cvss3Severity = cve.Impact
|
||||
} else {
|
||||
logging.Log.Warnf("Unknown Oval format. Please register the issue as it needs to be investigated. https://github.com/future-architect/vuls/issues family: %s, defID: %s", o.family, def.DefinitionID)
|
||||
}
|
||||
}
|
||||
return &cveCont
|
||||
}
|
||||
|
||||
56
oval/util.go
56
oval/util.go
@@ -9,6 +9,7 @@ import (
|
||||
"net/http"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -398,7 +399,10 @@ func isOvalDefAffected(def ovalmodels.Definition, req request, family string, ru
|
||||
constant.Fedora,
|
||||
constant.Amazon,
|
||||
constant.Oracle,
|
||||
constant.OpenSUSE,
|
||||
constant.OpenSUSELeap,
|
||||
constant.SUSEEnterpriseServer,
|
||||
constant.SUSEEnterpriseDesktop,
|
||||
constant.Debian,
|
||||
constant.Raspbian,
|
||||
constant.Ubuntu:
|
||||
@@ -457,7 +461,10 @@ func lessThan(family, newVer string, packInOVAL ovalmodels.Package) (bool, error
|
||||
return vera.LessThan(verb), nil
|
||||
|
||||
case constant.Oracle,
|
||||
constant.OpenSUSE,
|
||||
constant.OpenSUSELeap,
|
||||
constant.SUSEEnterpriseServer,
|
||||
constant.SUSEEnterpriseDesktop,
|
||||
constant.Amazon,
|
||||
constant.Fedora:
|
||||
vera := rpmver.NewVersion(newVer)
|
||||
@@ -500,9 +507,14 @@ func NewOVALClient(family string, cnf config.GovalDictConf) (Client, error) {
|
||||
return NewRocky(&cnf), nil
|
||||
case constant.Oracle:
|
||||
return NewOracle(&cnf), nil
|
||||
case constant.OpenSUSE:
|
||||
return NewSUSE(&cnf, constant.OpenSUSE), nil
|
||||
case constant.OpenSUSELeap:
|
||||
return NewSUSE(&cnf, constant.OpenSUSELeap), nil
|
||||
case constant.SUSEEnterpriseServer:
|
||||
// TODO other suse family
|
||||
return NewSUSE(&cnf), nil
|
||||
return NewSUSE(&cnf, constant.SUSEEnterpriseServer), nil
|
||||
case constant.SUSEEnterpriseDesktop:
|
||||
return NewSUSE(&cnf, constant.SUSEEnterpriseDesktop), nil
|
||||
case constant.Alpine:
|
||||
return NewAlpine(&cnf), nil
|
||||
case constant.Amazon:
|
||||
@@ -535,9 +547,14 @@ func GetFamilyInOval(familyInScanResult string) (string, error) {
|
||||
return constant.Fedora, nil
|
||||
case constant.Oracle:
|
||||
return constant.Oracle, nil
|
||||
case constant.OpenSUSE:
|
||||
return constant.OpenSUSE, nil
|
||||
case constant.OpenSUSELeap:
|
||||
return constant.OpenSUSELeap, nil
|
||||
case constant.SUSEEnterpriseServer:
|
||||
// TODO other suse family
|
||||
return constant.SUSEEnterpriseServer, nil
|
||||
case constant.SUSEEnterpriseDesktop:
|
||||
return constant.SUSEEnterpriseDesktop, nil
|
||||
case constant.Alpine:
|
||||
return constant.Alpine, nil
|
||||
case constant.Amazon:
|
||||
@@ -554,3 +571,36 @@ func GetFamilyInOval(familyInScanResult string) (string, error) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ParseCvss2 divide CVSSv2 string into score and vector
|
||||
// 5/AV:N/AC:L/Au:N/C:N/I:N/A:P
|
||||
func parseCvss2(scoreVector string) (score float64, vector string) {
|
||||
var err error
|
||||
ss := strings.Split(scoreVector, "/")
|
||||
if 1 < len(ss) {
|
||||
if score, err = strconv.ParseFloat(ss[0], 64); err != nil {
|
||||
return 0, ""
|
||||
}
|
||||
return score, strings.Join(ss[1:], "/")
|
||||
}
|
||||
return 0, ""
|
||||
}
|
||||
|
||||
// ParseCvss3 divide CVSSv3 string into score and vector
|
||||
// 5.6/CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L
|
||||
func parseCvss3(scoreVector string) (score float64, vector string) {
|
||||
var err error
|
||||
for _, s := range []string{
|
||||
"/CVSS:3.0/",
|
||||
"/CVSS:3.1/",
|
||||
} {
|
||||
ss := strings.Split(scoreVector, s)
|
||||
if 1 < len(ss) {
|
||||
if score, err = strconv.ParseFloat(ss[0], 64); err != nil {
|
||||
return 0, ""
|
||||
}
|
||||
return score, strings.TrimPrefix(s, "/") + ss[1]
|
||||
}
|
||||
}
|
||||
return 0, ""
|
||||
}
|
||||
|
||||
@@ -2049,3 +2049,76 @@ func Test_ovalResult_Sort(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseCvss2(t *testing.T) {
|
||||
type out struct {
|
||||
score float64
|
||||
vector string
|
||||
}
|
||||
var tests = []struct {
|
||||
in string
|
||||
out out
|
||||
}{
|
||||
{
|
||||
in: "5/AV:N/AC:L/Au:N/C:N/I:N/A:P",
|
||||
out: out{
|
||||
score: 5.0,
|
||||
vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
|
||||
},
|
||||
},
|
||||
{
|
||||
in: "",
|
||||
out: out{
|
||||
score: 0,
|
||||
vector: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
s, v := parseCvss2(tt.in)
|
||||
if s != tt.out.score || v != tt.out.vector {
|
||||
t.Errorf("\nexpected: %f, %s\n actual: %f, %s",
|
||||
tt.out.score, tt.out.vector, s, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseCvss3(t *testing.T) {
|
||||
type out struct {
|
||||
score float64
|
||||
vector string
|
||||
}
|
||||
var tests = []struct {
|
||||
in string
|
||||
out out
|
||||
}{
|
||||
{
|
||||
in: "5.6/CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
|
||||
out: out{
|
||||
score: 5.6,
|
||||
vector: "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
|
||||
},
|
||||
},
|
||||
{
|
||||
in: "6.1/CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
|
||||
out: out{
|
||||
score: 6.1,
|
||||
vector: "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
|
||||
},
|
||||
},
|
||||
{
|
||||
in: "",
|
||||
out: out{
|
||||
score: 0,
|
||||
vector: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
s, v := parseCvss3(tt.in)
|
||||
if s != tt.out.score || v != tt.out.vector {
|
||||
t.Errorf("\nexpected: %f, %s\n actual: %f, %s",
|
||||
tt.out.score, tt.out.vector, s, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user