Use Severity ranking in OVAL when the CVSS scores are empty.
This commit is contained in:
@@ -106,6 +106,7 @@ func (v CveContents) Cvss2Scores() (values []CveContentCvss2) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -136,9 +137,69 @@ func (v CveContents) MaxCvss2Score() CveContentCvss2 {
|
||||
max = cont.Cvss2Score
|
||||
}
|
||||
}
|
||||
if 0 < max {
|
||||
return value
|
||||
}
|
||||
|
||||
// If CVSS score isn't on NVD, RedHat and JVN use OVAL's Severity information.
|
||||
// Convert severity to cvss srore, then returns max severity.
|
||||
// Only Ubuntu, RedHat and Oracle OVAL has severity data.
|
||||
order = []CveContentType{Ubuntu, RedHat, Oracle}
|
||||
for _, ctype := range order {
|
||||
if cont, found := v[ctype]; found && 0 < len(cont.Severity) {
|
||||
score := 0.0
|
||||
switch cont.Type {
|
||||
case Ubuntu:
|
||||
score = severityToScoreForUbuntu(cont.Severity)
|
||||
case Oracle, RedHat:
|
||||
score = severityToScoreForRedHat(cont.Severity)
|
||||
}
|
||||
if max < score {
|
||||
value = CveContentCvss2{
|
||||
Type: ctype,
|
||||
Value: Cvss2{
|
||||
Score: score,
|
||||
Vector: cont.Cvss2Vector,
|
||||
Severity: cont.Severity,
|
||||
},
|
||||
}
|
||||
}
|
||||
max = score
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// Convert Severity to Score for Ubuntu OVAL
|
||||
func severityToScoreForUbuntu(severity string) float64 {
|
||||
switch strings.ToUpper(severity) {
|
||||
case "HIGH":
|
||||
return 10.0
|
||||
case "MEDIUM":
|
||||
return 6.9
|
||||
case "LOW":
|
||||
return 3.9
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Convert Severity to Score for RedHat, Oracle OVAL
|
||||
// https://access.redhat.com/security/updates/classification
|
||||
// Since I don't know the definition, Use the definition of CVSSv3
|
||||
func severityToScoreForRedHat(severity string) float64 {
|
||||
switch strings.ToUpper(severity) {
|
||||
case "CRITICAL":
|
||||
return 10.0
|
||||
case "IMPORTANT":
|
||||
return 8.9
|
||||
case "MODERATE":
|
||||
return 6.9
|
||||
case "LOW":
|
||||
return 3.9
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// CveContentCvss3 has CveContentType and Cvss3
|
||||
type CveContentCvss3 struct {
|
||||
Type CveContentType
|
||||
@@ -477,6 +538,9 @@ const (
|
||||
// Ubuntu is Ubuntu
|
||||
Ubuntu CveContentType = "ubuntu"
|
||||
|
||||
// Oracle is Oracle Linux
|
||||
Oracle CveContentType = "oracle"
|
||||
|
||||
// Unknown is Unknown
|
||||
Unknown CveContentType = "unknown"
|
||||
)
|
||||
|
||||
@@ -158,6 +158,22 @@ func TestMaxCvss2Scores(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
// Severity in OVAL
|
||||
{
|
||||
in: CveContents{
|
||||
Ubuntu: {
|
||||
Type: Ubuntu,
|
||||
Severity: "HIGH",
|
||||
},
|
||||
},
|
||||
out: CveContentCvss2{
|
||||
Type: Ubuntu,
|
||||
Value: Cvss2{
|
||||
Score: 10,
|
||||
Severity: "HIGH",
|
||||
},
|
||||
},
|
||||
},
|
||||
// Empty
|
||||
{
|
||||
in: CveContents{},
|
||||
|
||||
@@ -166,13 +166,14 @@ func (r ScanResult) FilterByCvssOver(over float64) ScanResult {
|
||||
|
||||
// TODO: Filter by ignore cves???
|
||||
filtered := r.ScannedCves.Find(func(v VulnInfo) bool {
|
||||
//TODO in the case of only oval, no cvecontents
|
||||
values := v.CveContents.Cvss2Scores()
|
||||
for _, vals := range values {
|
||||
score := vals.Value.Score
|
||||
if over <= score {
|
||||
return true
|
||||
}
|
||||
v2Max := v.CveContents.MaxCvss2Score()
|
||||
v3Max := v.CveContents.MaxCvss3Score()
|
||||
max := v2Max.Value.Score
|
||||
if max < v3Max.Value.Score {
|
||||
max = v3Max.Value.Score
|
||||
}
|
||||
if over <= max {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
@@ -15,3 +15,193 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package models
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/k0kubun/pp"
|
||||
)
|
||||
|
||||
func TestFilterByCvssOver(t *testing.T) {
|
||||
type in struct {
|
||||
over float64
|
||||
rs ScanResult
|
||||
}
|
||||
var tests = []struct {
|
||||
in in
|
||||
out ScanResult
|
||||
}{
|
||||
{
|
||||
in: in{
|
||||
over: 7.0,
|
||||
rs: ScanResult{
|
||||
ScannedCves: VulnInfos{
|
||||
"CVE-2017-0001": {
|
||||
CveID: "CVE-2017-0001",
|
||||
CveContents: NewCveContents(
|
||||
CveContent{
|
||||
Type: NVD,
|
||||
CveID: "CVE-2017-0001",
|
||||
Cvss2Score: 7.1,
|
||||
LastModified: time.Time{},
|
||||
},
|
||||
),
|
||||
},
|
||||
"CVE-2017-0002": {
|
||||
CveID: "CVE-2017-0002",
|
||||
CveContents: NewCveContents(
|
||||
CveContent{
|
||||
Type: NVD,
|
||||
CveID: "CVE-2017-0002",
|
||||
Cvss2Score: 6.9,
|
||||
LastModified: time.Time{},
|
||||
},
|
||||
),
|
||||
},
|
||||
"CVE-2017-0003": {
|
||||
CveID: "CVE-2017-0003",
|
||||
CveContents: NewCveContents(
|
||||
CveContent{
|
||||
Type: NVD,
|
||||
CveID: "CVE-2017-0003",
|
||||
Cvss2Score: 6.9,
|
||||
LastModified: time.Time{},
|
||||
},
|
||||
CveContent{
|
||||
Type: JVN,
|
||||
CveID: "CVE-2017-0003",
|
||||
Cvss2Score: 7.2,
|
||||
LastModified: time.Time{},
|
||||
},
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
out: ScanResult{
|
||||
ScannedCves: VulnInfos{
|
||||
"CVE-2017-0001": {
|
||||
CveID: "CVE-2017-0001",
|
||||
CveContents: NewCveContents(
|
||||
CveContent{
|
||||
Type: NVD,
|
||||
CveID: "CVE-2017-0001",
|
||||
Cvss2Score: 7.1,
|
||||
LastModified: time.Time{},
|
||||
},
|
||||
),
|
||||
},
|
||||
"CVE-2017-0003": {
|
||||
CveID: "CVE-2017-0003",
|
||||
CveContents: NewCveContents(
|
||||
CveContent{
|
||||
Type: NVD,
|
||||
CveID: "CVE-2017-0003",
|
||||
Cvss2Score: 6.9,
|
||||
LastModified: time.Time{},
|
||||
},
|
||||
CveContent{
|
||||
Type: JVN,
|
||||
CveID: "CVE-2017-0003",
|
||||
Cvss2Score: 7.2,
|
||||
LastModified: time.Time{},
|
||||
},
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// OVAL Severity
|
||||
{
|
||||
in: in{
|
||||
over: 7.0,
|
||||
rs: ScanResult{
|
||||
ScannedCves: VulnInfos{
|
||||
"CVE-2017-0001": {
|
||||
CveID: "CVE-2017-0001",
|
||||
CveContents: NewCveContents(
|
||||
CveContent{
|
||||
Type: Ubuntu,
|
||||
CveID: "CVE-2017-0001",
|
||||
Severity: "HIGH",
|
||||
LastModified: time.Time{},
|
||||
},
|
||||
),
|
||||
},
|
||||
"CVE-2017-0002": {
|
||||
CveID: "CVE-2017-0002",
|
||||
CveContents: NewCveContents(
|
||||
CveContent{
|
||||
Type: RedHat,
|
||||
CveID: "CVE-2017-0002",
|
||||
Severity: "CRITICAL",
|
||||
LastModified: time.Time{},
|
||||
},
|
||||
),
|
||||
},
|
||||
"CVE-2017-0003": {
|
||||
CveID: "CVE-2017-0003",
|
||||
CveContents: NewCveContents(
|
||||
CveContent{
|
||||
Type: Oracle,
|
||||
CveID: "CVE-2017-0003",
|
||||
Severity: "IMPORTANT",
|
||||
LastModified: time.Time{},
|
||||
},
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
out: ScanResult{
|
||||
ScannedCves: VulnInfos{
|
||||
"CVE-2017-0001": {
|
||||
CveID: "CVE-2017-0001",
|
||||
CveContents: NewCveContents(
|
||||
CveContent{
|
||||
Type: Ubuntu,
|
||||
CveID: "CVE-2017-0001",
|
||||
Severity: "HIGH",
|
||||
LastModified: time.Time{},
|
||||
},
|
||||
),
|
||||
},
|
||||
"CVE-2017-0002": {
|
||||
CveID: "CVE-2017-0002",
|
||||
CveContents: NewCveContents(
|
||||
CveContent{
|
||||
Type: RedHat,
|
||||
CveID: "CVE-2017-0002",
|
||||
Severity: "CRITICAL",
|
||||
LastModified: time.Time{},
|
||||
},
|
||||
),
|
||||
},
|
||||
"CVE-2017-0003": {
|
||||
CveID: "CVE-2017-0003",
|
||||
CveContents: NewCveContents(
|
||||
CveContent{
|
||||
Type: Oracle,
|
||||
CveID: "CVE-2017-0003",
|
||||
Severity: "IMPORTANT",
|
||||
LastModified: time.Time{},
|
||||
},
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
actual := tt.in.rs.FilterByCvssOver(tt.in.over)
|
||||
for k := range tt.out.ScannedCves {
|
||||
if !reflect.DeepEqual(tt.out.ScannedCves[k], actual.ScannedCves[k]) {
|
||||
o := pp.Sprintf("%v", tt.out.ScannedCves[k])
|
||||
a := pp.Sprintf("%v", actual.ScannedCves[k])
|
||||
t.Errorf("[%s] expected: %v\n actual: %v\n", k, o, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user