Unify the models of NVD, JVN, OVAL

This commit is contained in:
Kota Kanbe
2017-05-02 15:39:22 +09:00
committed by kota kanbe
parent 342a1c6cff
commit b545b5d0a3
12 changed files with 736 additions and 343 deletions

View File

@@ -30,6 +30,7 @@ import (
"github.com/future-architect/vuls/report"
"github.com/future-architect/vuls/util"
"github.com/google/subcommands"
"github.com/k0kubun/pp"
)
// ReportCmd is subcommand for reporting
@@ -421,6 +422,7 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
util.Log.Errorf("Failed to fill OVAL information: %s", err)
return subcommands.ExitFailure
}
pp.Println(filled)
filled, err = fillCveInfoFromCveDB(*filled)
if err != nil {

View File

@@ -246,15 +246,15 @@ func diff(current, previous models.ScanResults) (diff models.ScanResults, err er
return diff, err
}
func getNewCves(previousResult, currentResult models.ScanResult) (newVulninfos []models.VulnInfo) {
func getNewCves(previous, current models.ScanResult) (newVulninfos []models.VulnInfo) {
previousCveIDsSet := map[string]bool{}
for _, previousVulnInfo := range previousResult.ScannedCves {
for _, previousVulnInfo := range previous.ScannedCves {
previousCveIDsSet[previousVulnInfo.CveID] = true
}
for _, v := range currentResult.ScannedCves {
for _, v := range current.ScannedCves {
if previousCveIDsSet[v.CveID] {
if isCveInfoUpdated(currentResult, previousResult, v.CveID) {
if isCveInfoUpdated(current, previous, v.CveID) {
newVulninfos = append(newVulninfos, v)
}
} else {
@@ -264,25 +264,35 @@ func getNewCves(previousResult, currentResult models.ScanResult) (newVulninfos [
return
}
func isCveInfoUpdated(currentResult, previousResult models.ScanResult, CveID string) bool {
func isCveInfoUpdated(current, previous models.ScanResult, CveID string) bool {
type lastModified struct {
Nvd time.Time
Jvn time.Time
}
previousModifies := lastModified{}
for _, c := range previousResult.KnownCves {
for _, c := range previous.KnownCves {
if CveID == c.CveID {
previousModifies.Nvd = c.CveDetail.Nvd.LastModifiedDate
previousModifies.Jvn = c.CveDetail.Jvn.LastModifiedDate
//TODO
if nvd, found := c.Get(models.NVD); found {
previousModifies.Nvd = nvd.LastModified
}
if jvn, found := c.Get(models.JVN); found {
previousModifies.Jvn = jvn.LastModified
}
}
}
currentModifies := lastModified{}
for _, c := range currentResult.KnownCves {
if CveID == c.CveDetail.CveID {
currentModifies.Nvd = c.CveDetail.Nvd.LastModifiedDate
currentModifies.Jvn = c.CveDetail.Jvn.LastModifiedDate
for _, c := range current.KnownCves {
if CveID == c.VulnInfo.CveID {
//TODO
if nvd, found := c.Get(models.NVD); found {
previousModifies.Nvd = nvd.LastModified
}
if jvn, found := c.Get(models.JVN); found {
previousModifies.Jvn = jvn.LastModified
}
}
}
return !currentModifies.Nvd.Equal(previousModifies.Nvd) ||

View File

@@ -25,7 +25,6 @@ import (
"github.com/future-architect/vuls/models"
"github.com/k0kubun/pp"
cve "github.com/kotakanbe/go-cve-dictionary/models"
)
func TestDiff(t *testing.T) {
@@ -174,10 +173,11 @@ func TestDiff(t *testing.T) {
},
KnownCves: []models.CveInfo{
{
CveDetail: cve.CveDetail{
CveID: "CVE-2016-6662",
Nvd: cve.Nvd{
LastModifiedDate: time.Date(2016, 1, 1, 0, 0, 0, 0, time.Local),
CveContents: []models.CveContent{
{
Type: models.NVD,
CveID: "CVE-2016-6662",
LastModified: time.Date(2016, 1, 1, 0, 0, 0, 0, time.Local),
},
},
VulnInfo: models.VulnInfo{
@@ -214,10 +214,11 @@ func TestDiff(t *testing.T) {
},
KnownCves: []models.CveInfo{
{
CveDetail: cve.CveDetail{
CveID: "CVE-2016-6662",
Nvd: cve.Nvd{
LastModifiedDate: time.Date(2017, 3, 15, 13, 40, 57, 0, time.Local),
CveContents: []models.CveContent{
{
Type: models.NVD,
CveID: "CVE-2016-6662",
LastModified: time.Date(2017, 3, 15, 13, 40, 57, 0, time.Local),
},
},
VulnInfo: models.VulnInfo{

View File

@@ -20,12 +20,12 @@ package models
import (
"fmt"
"sort"
"strings"
"time"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/cveapi"
cve "github.com/kotakanbe/go-cve-dictionary/models"
goval "github.com/kotakanbe/goval-dictionary/models"
cvedict "github.com/kotakanbe/go-cve-dictionary/models"
)
// ScanResults is slice of ScanResult.
@@ -73,8 +73,7 @@ type ScanResult struct {
Optional [][]interface{}
}
// FillCveDetail fetches CVE detailed information from
// CVE Database, and then set to fields.
// FillCveDetail fetches NVD, JVN from CVE Database, and then set to fields.
func (r ScanResult) FillCveDetail() (*ScanResult, error) {
set := map[string]VulnInfo{}
var cveIDs []string
@@ -90,35 +89,45 @@ func (r ScanResult) FillCveDetail() (*ScanResult, error) {
r.IgnoredCves = CveInfos{}
for _, d := range ds {
nvd := *r.convertNvdToModel(d.CveID, d.Nvd)
jvn := *r.convertJvnToModel(d.CveID, d.Jvn)
cinfo := CveInfo{
CveDetail: d,
VulnInfo: set[d.CveID],
CveContents: []CveContent{nvd, jvn},
VulnInfo: set[d.CveID],
}
cinfo.NilSliceToEmpty()
// ignored
found := false
ignore := false
for _, icve := range config.Conf.Servers[r.ServerName].IgnoreCves {
if icve == d.CveID {
r.IgnoredCves.Insert(cinfo)
found = true
ignore = true
break
}
}
if found {
if ignore {
continue
}
// Update known if KnownCves already have cinfo
if c, ok := r.KnownCves.Get(cinfo.CveID); ok {
c.CveDetail = d
for _, con := range []CveContent{nvd, jvn} {
if !c.Update(con) {
c.Insert(con)
}
}
r.KnownCves.Update(c)
continue
}
// Update unknown if UnknownCves already have cinfo
if c, ok := r.UnknownCves.Get(cinfo.CveID); ok {
c.CveDetail = d
for _, con := range []CveContent{nvd, jvn} {
if !c.Update(con) {
c.Insert(con)
}
}
r.UnknownCves.Update(c)
continue
}
@@ -138,6 +147,93 @@ func (r ScanResult) FillCveDetail() (*ScanResult, error) {
return &r, nil
}
func (r ScanResult) convertNvdToModel(cveID string, nvd cvedict.Nvd) *CveContent {
var cpes []Cpe
for _, c := range nvd.Cpes {
cpes = append(cpes, Cpe{CpeName: c.CpeName})
}
var refs []Reference
for _, r := range nvd.References {
refs = append(refs, Reference{
Link: r.Link,
Source: r.Source,
})
}
validVec := true
for _, v := range []string{
nvd.AccessVector,
nvd.AccessComplexity,
nvd.Authentication,
nvd.ConfidentialityImpact,
nvd.IntegrityImpact,
nvd.AvailabilityImpact,
} {
if len(v) == 0 {
validVec = false
}
}
vector := ""
if validVec {
vector = fmt.Sprintf("AV:%s/AC:%s/Au:%s/C:%s/I:%s/A:%s",
string(nvd.AccessVector[0]),
string(nvd.AccessComplexity[0]),
string(nvd.Authentication[0]),
string(nvd.ConfidentialityImpact[0]),
string(nvd.IntegrityImpact[0]),
string(nvd.AvailabilityImpact[0]))
}
//TODO CVSSv3
return &CveContent{
Type: NVD,
CveID: cveID,
Summary: nvd.Summary,
Cvss2Score: nvd.Score,
Cvss2Vector: vector,
Cpes: cpes,
CweID: nvd.CweID,
References: refs,
Published: nvd.PublishedDate,
LastModified: nvd.LastModifiedDate,
}
}
func (r ScanResult) convertJvnToModel(cveID string, jvn cvedict.Jvn) *CveContent {
var cpes []Cpe
for _, c := range jvn.Cpes {
cpes = append(cpes, Cpe{CpeName: c.CpeName})
}
refs := []Reference{{
Link: jvn.JvnLink,
Source: string(JVN),
}}
for _, r := range jvn.References {
refs = append(refs, Reference{
Link: r.Link,
Source: r.Source,
})
}
vector := strings.TrimSuffix(strings.TrimPrefix(jvn.Vector, "("), ")")
return &CveContent{
Type: JVN,
CveID: cveID,
Title: jvn.Title,
Summary: jvn.Summary,
Severity: jvn.Severity,
Cvss2Score: jvn.Score,
Cvss2Vector: vector,
Cpes: cpes,
References: refs,
Published: jvn.PublishedDate,
LastModified: jvn.LastModifiedDate,
}
}
// FilterByCvssOver is filter function.
func (r ScanResult) FilterByCvssOver() ScanResult {
cveInfos := []CveInfo{}
@@ -147,7 +243,7 @@ func (r ScanResult) FilterByCvssOver() ScanResult {
}
for _, cveInfo := range r.KnownCves {
if config.Conf.CvssScoreOver <= cveInfo.CveDetail.CvssScore(config.Conf.Lang) {
if config.Conf.CvssScoreOver <= cveInfo.CvssV2Score() {
cveInfos = append(cveInfos, cveInfo)
}
}
@@ -217,7 +313,7 @@ func (r ScanResult) CveSummary() string {
var high, medium, low, unknown int
cves := append(r.KnownCves, r.UnknownCves...)
for _, cveInfo := range cves {
score := cveInfo.CveDetail.CvssScore(config.Conf.Lang)
score := cveInfo.CvssV2Score()
switch {
case 7.0 <= score:
high++
@@ -379,11 +475,10 @@ func (c CveInfos) Swap(i, j int) {
}
func (c CveInfos) Less(i, j int) bool {
lang := config.Conf.Lang
if c[i].CveDetail.CvssScore(lang) == c[j].CveDetail.CvssScore(lang) {
return c[i].CveDetail.CveID < c[j].CveDetail.CveID
if c[i].CvssV2Score() == c[j].CvssV2Score() {
return c[i].CveID < c[j].CveID
}
return c[j].CveDetail.CvssScore(lang) < c[i].CveDetail.CvssScore(lang)
return c[j].CvssV2Score() < c[i].CvssV2Score()
}
// Get cveInfo by cveID
@@ -431,27 +526,120 @@ func (c *CveInfos) Upsert(cveInfo CveInfo) {
}
}
// CveInfo has Cve Information.
// CveInfo has CVE detailed Information.
type CveInfo struct {
CveDetail cve.CveDetail
OvalDetail goval.Definition
VulnInfo
CveContents []CveContent
}
// Get a CveContent specified by arg
func (c *CveInfo) Get(typestr CveContentType) (*CveContent, bool) {
for _, cont := range c.CveContents {
if cont.Type == typestr {
return &cont, true
}
}
return &CveContent{}, false
}
// Insert a CveContent to specified by arg
func (c *CveInfo) Insert(con CveContent) {
c.CveContents = append(c.CveContents, con)
}
// Update a CveContent to specified by arg
func (c *CveInfo) Update(to CveContent) bool {
for i, cont := range c.CveContents {
if cont.Type == to.Type {
c.CveContents[i] = to
return true
}
}
return false
}
// CvssV2Score returns CVSS V2 Score
func (c *CveInfo) CvssV2Score() float64 {
//TODO
if cont, found := c.Get(NVD); found {
return cont.Cvss2Score
} else if cont, found := c.Get(JVN); found {
return cont.Cvss2Score
} else if cont, found := c.Get(RedHat); found {
return cont.Cvss2Score
}
return -1
}
// NilSliceToEmpty set nil slice fields to empty slice to avoid null in JSON
func (c *CveInfo) NilSliceToEmpty() {
if c.CveDetail.Nvd.Cpes == nil {
c.CveDetail.Nvd.Cpes = []cve.Cpe{}
}
if c.CveDetail.Jvn.Cpes == nil {
c.CveDetail.Jvn.Cpes = []cve.Cpe{}
}
if c.CveDetail.Nvd.References == nil {
c.CveDetail.Nvd.References = []cve.Reference{}
}
if c.CveDetail.Jvn.References == nil {
c.CveDetail.Jvn.References = []cve.Reference{}
}
return
// TODO
// if c.CveDetail.Nvd.Cpes == nil {
// c.CveDetail.Nvd.Cpes = []cve.Cpe{}
// }
// if c.CveDetail.Jvn.Cpes == nil {
// c.CveDetail.Jvn.Cpes = []cve.Cpe{}
// }
// if c.CveDetail.Nvd.References == nil {
// c.CveDetail.Nvd.References = []cve.Reference{}
// }
// if c.CveDetail.Jvn.References == nil {
// c.CveDetail.Jvn.References = []cve.Reference{}
// }
}
// CveContentType is a source of CVE information
type CveContentType string
const (
// NVD is NVD
NVD CveContentType = "nvd"
// JVN is JVN
JVN CveContentType = "jvn"
// RedHat is RedHat
RedHat CveContentType = "redhat"
// CentOS is CentOS
CentOS CveContentType = "centos"
// Debian is Debian
Debian CveContentType = "debian"
// Ubuntu is Ubuntu
Ubuntu CveContentType = "ubuntu"
)
// CveContent has abstraction of various vulnerability information
type CveContent struct {
Type CveContentType
CveID string
Title string
Summary string
Severity string
Cvss2Score float64
Cvss2Vector string
Cvss3Score float64
Cvss3Vector string
Cpes []Cpe
References []Reference
CweID string
Published time.Time
LastModified time.Time
}
// Cpe is Common Platform Enumeration
type Cpe struct {
CpeName string
}
// Reference has a related link of the CVE
type Reference struct {
RefID string
Source string
Link string
}
// PackageInfoList is slice of PackageInfo
@@ -552,13 +740,14 @@ func (a PackageInfosByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
// PackageInfo has installed packages.
type PackageInfo struct {
Name string
Version string
Release string
NewVersion string
NewRelease string
Repository string
Changelog Changelog
Name string
Version string
Release string
NewVersion string
NewRelease string
Repository string
Changelog Changelog
NotFixedYet bool // Ubuntu OVAL Only
}
// Changelog has contents of changelog and how to get it.

View File

@@ -7,7 +7,6 @@ import (
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
ver "github.com/knqyf263/go-deb-version"
cve "github.com/kotakanbe/go-cve-dictionary/models"
ovalconf "github.com/kotakanbe/goval-dictionary/config"
db "github.com/kotakanbe/goval-dictionary/db"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
@@ -62,54 +61,78 @@ func (o Debian) FillCveInfoFromOvalDB(r *models.ScanResult) (*models.ScanResult,
func (o Debian) fillOvalInfo(r *models.ScanResult, definition *ovalmodels.Definition) *models.ScanResult {
// Update ScannedCves by OVAL info
found := false
cves := []models.VulnInfo{}
for _, cve := range r.ScannedCves {
if cve.CveID == definition.Debian.CveID {
updatedCves := []models.VulnInfo{}
// Update scanned confidence to ovalmatch
for _, scanned := range r.ScannedCves {
if scanned.CveID == definition.Debian.CveID {
found = true
if cve.Confidence.Score < models.OvalMatch.Score {
cve.Confidence = models.OvalMatch
if scanned.Confidence.Score < models.OvalMatch.Score {
scanned.Confidence = models.OvalMatch
}
}
cves = append(cves, cve)
updatedCves = append(updatedCves, scanned)
}
packageInfoList := getPackageInfoList(r, definition)
vuln := models.VulnInfo{
CveID: definition.Debian.CveID,
Confidence: models.OvalMatch,
Packages: packageInfoList,
Packages: getPackageInfoList(r, definition),
}
if !found {
cves = append(cves, vuln)
util.Log.Debugf("%s is newly detected by OVAL", vuln.CveID)
updatedCves = append(updatedCves, vuln)
}
r.ScannedCves = cves
r.ScannedCves = updatedCves
// Update KnownCves by OVAL info
cveInfo, ok := r.KnownCves.Get(definition.Debian.CveID)
ovalContent := *o.convertToModel(definition)
ovalContent.Type = models.CveContentType(r.Family)
cInfo, ok := r.KnownCves.Get(definition.Debian.CveID)
if !ok {
cveInfo.CveDetail = cve.CveDetail{
CveID: definition.Debian.CveID,
}
cveInfo.VulnInfo = vuln
cInfo.VulnInfo = vuln
cInfo.CveContents = []models.CveContent{ovalContent}
}
cveInfo.OvalDetail = *definition
if cveInfo.VulnInfo.Confidence.Score < models.OvalMatch.Score {
cveInfo.Confidence = models.OvalMatch
if !cInfo.Update(ovalContent) {
cInfo.Insert(ovalContent)
}
r.KnownCves.Upsert(cveInfo)
if cInfo.VulnInfo.Confidence.Score < models.OvalMatch.Score {
cInfo.Confidence = models.OvalMatch
}
r.KnownCves.Upsert(cInfo)
// Update UnknownCves by OVAL info
cveInfo, ok = r.UnknownCves.Get(definition.Debian.CveID)
cInfo, ok = r.UnknownCves.Get(definition.Debian.CveID)
if ok {
cveInfo.OvalDetail = *definition
if cveInfo.VulnInfo.Confidence.Score < models.OvalMatch.Score {
cveInfo.Confidence = models.OvalMatch
}
r.UnknownCves.Delete(definition.Debian.CveID)
r.KnownCves.Upsert(cveInfo)
// Insert new CveInfo
if !cInfo.Update(ovalContent) {
cInfo.Insert(ovalContent)
}
if cInfo.VulnInfo.Confidence.Score < models.OvalMatch.Score {
cInfo.Confidence = models.OvalMatch
}
r.KnownCves.Upsert(cInfo)
}
return r
}
func (o Debian) convertToModel(def *ovalmodels.Definition) *models.CveContent {
var refs []models.Reference
for _, r := range def.References {
refs = append(refs, models.Reference{
Link: r.RefURL,
Source: r.Source,
RefID: r.RefID,
})
}
return &models.CveContent{
CveID: def.Debian.CveID,
Title: def.Title,
Summary: def.Description,
References: refs,
}
}

View File

@@ -15,6 +15,7 @@ func getPackageInfoList(r *models.ScanResult, d *ovalmodels.Definition) models.P
for _, pack := range d.AffectedPacks {
for _, p := range r.Packages {
if pack.Name == p.Name {
p.Changelog = models.Changelog{}
packageInfoList = append(packageInfoList, p)
break
}

View File

@@ -7,7 +7,6 @@ import (
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
ver "github.com/knqyf263/go-deb-version"
cve "github.com/kotakanbe/go-cve-dictionary/models"
ovalconf "github.com/kotakanbe/goval-dictionary/config"
db "github.com/kotakanbe/goval-dictionary/db"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
@@ -56,69 +55,108 @@ func (o Redhat) FillCveInfoFromOvalDB(r *models.ScanResult) (*models.ScanResult,
}
func (o Redhat) fillOvalInfo(r *models.ScanResult, definition *ovalmodels.Definition) *models.ScanResult {
found := make(map[string]bool)
vulnInfos := make(map[string]models.VulnInfo)
packageInfoList := getPackageInfoList(r, definition)
cveIDSet := make(map[string]bool)
cveID2VulnInfo := make(map[string]models.VulnInfo)
for _, cve := range definition.Advisory.Cves {
found[cve.CveID] = false
vulnInfos[cve.CveID] = models.VulnInfo{
cveIDSet[cve.CveID] = false
cveID2VulnInfo[cve.CveID] = models.VulnInfo{
CveID: cve.CveID,
Confidence: models.OvalMatch,
Packages: packageInfoList,
Packages: getPackageInfoList(r, definition),
}
}
// Update ScannedCves by OVAL info
cves := []models.VulnInfo{}
for _, scannedCve := range r.ScannedCves {
updatedCves := []models.VulnInfo{}
for _, scanned := range r.ScannedCves {
// Update scanned confidence to ovalmatch
for _, c := range definition.Advisory.Cves {
if scannedCve.CveID == c.CveID {
found[c.CveID] = true
if scannedCve.Confidence.Score < models.OvalMatch.Score {
scannedCve.Confidence = models.OvalMatch
if scanned.CveID == c.CveID {
cveIDSet[c.CveID] = true
if scanned.Confidence.Score < models.OvalMatch.Score {
scanned.Confidence = models.OvalMatch
}
break
}
}
cves = append(cves, scannedCve)
updatedCves = append(updatedCves, scanned)
}
for cveID, found := range found {
for cveID, found := range cveIDSet {
if !found {
cves = append(cves, vulnInfos[cveID])
util.Log.Debugf("%s is newly detected by OVAL", cveID)
updatedCves = append(updatedCves, cveID2VulnInfo[cveID])
}
}
r.ScannedCves = cves
r.ScannedCves = updatedCves
// Update KnownCves by OVAL info
for _, c := range definition.Advisory.Cves {
cveInfo, ok := r.KnownCves.Get(c.CveID)
ovalContent := *o.convertToModel(c.CveID, definition)
cInfo, ok := r.KnownCves.Get(c.CveID)
if !ok {
cveInfo.CveDetail = cve.CveDetail{
CveID: c.CveID,
}
cveInfo.VulnInfo = vulnInfos[c.CveID]
cInfo.VulnInfo = cveID2VulnInfo[c.CveID]
cInfo.CveContents = []models.CveContent{ovalContent}
}
cveInfo.OvalDetail = *definition
if cveInfo.VulnInfo.Confidence.Score < models.OvalMatch.Score {
cveInfo.Confidence = models.OvalMatch
if !cInfo.Update(ovalContent) {
cInfo.Insert(ovalContent)
}
r.KnownCves.Upsert(cveInfo)
if cInfo.VulnInfo.Confidence.Score < models.OvalMatch.Score {
cInfo.Confidence = models.OvalMatch
}
r.KnownCves.Upsert(cInfo)
}
// Update UnknownCves by OVAL info
for _, c := range definition.Advisory.Cves {
cveInfo, ok := r.UnknownCves.Get(c.CveID)
cInfo, ok := r.UnknownCves.Get(c.CveID)
if ok {
cveInfo.OvalDetail = *definition
if cveInfo.VulnInfo.Confidence.Score < models.OvalMatch.Score {
cveInfo.Confidence = models.OvalMatch
}
r.UnknownCves.Delete(c.CveID)
r.KnownCves.Upsert(cveInfo)
// Insert new CveInfo
ovalContent := *o.convertToModel(c.CveID, definition)
if !cInfo.Update(ovalContent) {
cInfo.Insert(ovalContent)
}
if cInfo.VulnInfo.Confidence.Score < models.OvalMatch.Score {
cInfo.Confidence = models.OvalMatch
}
r.KnownCves.Upsert(cInfo)
}
}
return r
}
func (o Redhat) convertToModel(cveID string, def *ovalmodels.Definition) *models.CveContent {
for _, cve := range def.Advisory.Cves {
if cve.CveID != cveID {
continue
}
var refs []models.Reference
//TODO RHSAのリンクを入れる
for _, r := range def.References {
refs = append(refs, models.Reference{
Link: r.RefURL,
Source: r.Source,
RefID: r.RefID,
})
}
// util.ParseCvss2()
return &models.CveContent{
Type: models.RedHat,
CveID: cve.CveID,
Title: def.Title,
Summary: def.Description,
Severity: def.Advisory.Severity,
// V2Score: v2Score, // TODO divide into score and vector
Cvss2Vector: cve.Cvss2, // TODO divide into score and vector
Cvss3Vector: cve.Cvss3, // TODO divide into score and vector
References: refs,
CweID: cve.Cwe,
}
}
return nil
}

View File

@@ -166,7 +166,7 @@ func toSlackAttachments(scanResult models.ScanResult) (attaches []*attachment) {
}
for _, cveInfo := range cves {
cveID := cveInfo.CveDetail.CveID
cveID := cveInfo.VulnInfo.CveID
curentPackages := []string{}
for _, p := range cveInfo.Packages {
@@ -199,7 +199,7 @@ func toSlackAttachments(scanResult models.ScanResult) (attaches []*attachment) {
Short: true,
},
},
Color: color(cveInfo.CveDetail.CvssScore(config.Conf.Lang)),
Color: color(cveInfo.CvssV2Score()),
}
attaches = append(attaches, &a)
}
@@ -221,57 +221,61 @@ func color(cvssScore float64) string {
}
func attachmentText(cveInfo models.CveInfo, osFamily string) string {
linkText := links(cveInfo, osFamily)
switch {
case config.Conf.Lang == "ja" &&
0 < cveInfo.CveDetail.Jvn.CvssScore():
// linkText := links(cveInfo, osFamily)
//TODO
return ""
// switch {
// case config.Conf.Lang == "ja" &&
// 0 < cveInfo.CveDetail.Jvn.CvssScore():
jvn := cveInfo.CveDetail.Jvn
return fmt.Sprintf("*%4.1f (%s)* <%s|%s>\n%s\n%s\n*Confidence:* %v",
cveInfo.CveDetail.CvssScore(config.Conf.Lang),
jvn.CvssSeverity(),
fmt.Sprintf(cvssV2CalcBaseURL, cveInfo.CveDetail.CveID),
jvn.CvssVector(),
jvn.CveTitle(),
linkText,
cveInfo.VulnInfo.Confidence,
)
case 0 < cveInfo.CveDetail.CvssScore("en"):
nvd := cveInfo.CveDetail.Nvd
return fmt.Sprintf("*%4.1f (%s)* <%s|%s>\n%s\n%s\n*Confidence:* %v",
cveInfo.CveDetail.CvssScore(config.Conf.Lang),
nvd.CvssSeverity(),
fmt.Sprintf(cvssV2CalcBaseURL, cveInfo.CveDetail.CveID),
nvd.CvssVector(),
nvd.CveSummary(),
linkText,
cveInfo.VulnInfo.Confidence,
)
default:
nvd := cveInfo.CveDetail.Nvd
return fmt.Sprintf("?\n%s\n%s\n*Confidence:* %v",
nvd.CveSummary(), linkText, cveInfo.VulnInfo.Confidence)
}
// jvn := cveInfo.CveDetail.Jvn
// return fmt.Sprintf("*%4.1f (%s)* <%s|%s>\n%s\n%s\n*Confidence:* %v",
// cveInfo.CveDetail.CvssScore(config.Conf.Lang),
// jvn.CvssSeverity(),
// fmt.Sprintf(cvssV2CalcBaseURL, cveInfo.CveDetail.CveID),
// jvn.CvssVector(),
// jvn.CveTitle(),
// linkText,
// cveInfo.VulnInfo.Confidence,
// )
// case 0 < cveInfo.CveDetail.CvssScore("en"):
// nvd := cveInfo.CveDetail.Nvd
// return fmt.Sprintf("*%4.1f (%s)* <%s|%s>\n%s\n%s\n*Confidence:* %v",
// cveInfo.CveDetail.CvssScore(config.Conf.Lang),
// nvd.CvssSeverity(),
// fmt.Sprintf(cvssV2CalcBaseURL, cveInfo.CveDetail.CveID),
// nvd.CvssVector(),
// nvd.CveSummary(),
// linkText,
// cveInfo.VulnInfo.Confidence,
// )
// default:
// nvd := cveInfo.CveDetail.Nvd
// return fmt.Sprintf("?\n%s\n%s\n*Confidence:* %v",
// nvd.CveSummary(), linkText, cveInfo.VulnInfo.Confidence)
// }
}
func links(cveInfo models.CveInfo, osFamily string) string {
links := []string{}
cweID := cveInfo.CveDetail.CweID()
if 0 < len(cweID) {
links = append(links, fmt.Sprintf("<%s|%s>",
cweURL(cweID), cweID))
if config.Conf.Lang == "ja" {
links = append(links, fmt.Sprintf("<%s|%s(JVN)>",
cweJvnURL(cweID), cweID))
}
}
//TODO
// cweID := cveInfo.CveDetail.CweID()
// if 0 < len(cweID) {
// links = append(links, fmt.Sprintf("<%s|%s>",
// cweURL(cweID), cweID))
// if config.Conf.Lang == "ja" {
// links = append(links, fmt.Sprintf("<%s|%s(JVN)>",
// cweJvnURL(cweID), cweID))
// }
// }
cveID := cveInfo.CveDetail.CveID
if config.Conf.Lang == "ja" && 0 < len(cveInfo.CveDetail.Jvn.Link()) {
jvn := fmt.Sprintf("<%s|JVN>", cveInfo.CveDetail.Jvn.Link())
links = append(links, jvn)
}
cveID := cveInfo.VulnInfo.CveID
//TODO
// if config.Conf.Lang == "ja" && 0 < len(cveInfo.CveDetail.Jvn.Link()) {
// jvn := fmt.Sprintf("<%s|JVN>", cveInfo.CveDetail.Jvn.Link())
// links = append(links, jvn)
// }
dlinks := distroLinks(cveInfo, osFamily)
for _, link := range dlinks {
links = append(links,

View File

@@ -26,7 +26,6 @@ import (
"time"
log "github.com/Sirupsen/logrus"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/google/subcommands"
"github.com/gosuri/uitable"
@@ -613,39 +612,53 @@ func summaryLines() string {
for i, d := range currentScanResult.AllCves() {
var cols []string
// packs := []string{}
// for _, pack := range d.Packages {
// packs = append(packs, pack.Name)
// }
if config.Conf.Lang == "ja" && 0 < d.CveDetail.Jvn.CvssScore() {
summary := d.CveDetail.Jvn.CveTitle()
cols = []string{
fmt.Sprintf(indexFormat, i+1),
d.CveDetail.CveID,
fmt.Sprintf("| %4.1f",
d.CveDetail.CvssScore(config.Conf.Lang)),
fmt.Sprintf("| %3d |", d.VulnInfo.Confidence.Score),
summary,
}
} else {
summary := d.CveDetail.Nvd.CveSummary()
var cvssScore string
if d.CveDetail.CvssScore("en") <= 0 {
cvssScore = "| ?"
} else {
cvssScore = fmt.Sprintf("| %4.1f",
d.CveDetail.CvssScore(config.Conf.Lang))
}
cols = []string{
fmt.Sprintf(indexFormat, i+1),
d.CveDetail.CveID,
cvssScore,
fmt.Sprintf("| %3d |", d.VulnInfo.Confidence.Score),
summary,
}
//TODO
var summary string
if cont, found := d.Get(models.NVD); found {
summary = cont.Summary
}
var cvssScore string
if d.CvssV2Score() <= 0 {
cvssScore = "| ?"
} else {
cvssScore = fmt.Sprintf("| %4.1f", d.CvssV2Score())
}
cols = []string{
fmt.Sprintf(indexFormat, i+1),
d.VulnInfo.CveID,
cvssScore,
fmt.Sprintf("| %3d |", d.VulnInfo.Confidence.Score),
summary,
}
// if config.Conf.Lang == "ja" && 0 < d.CveDetail.Jvn.CvssScore() {
// summary := d.CveDetail.Jvn.CveTitle()
// cols = []string{
// fmt.Sprintf(indexFormat, i+1),
// d.CveDetail.CveID,
// fmt.Sprintf("| %4.1f",
// d.CveDetail.CvssScore(config.Conf.Lang)),
// fmt.Sprintf("| %3d |", d.VulnInfo.Confidence.Score),
// summary,
// }
// } else {
// summary := d.CveDetail.Nvd.CveSummary()
// var cvssScore string
// if d.CveDetail.CvssScore("en") <= 0 {
// cvssScore = "| ?"
// } else {
// cvssScore = fmt.Sprintf("| %4.1f",
// d.CveDetail.CvssScore(config.Conf.Lang))
// }
// cols = []string{
// fmt.Sprintf(indexFormat, i+1),
// d.CveDetail.CveID,
// cvssScore,
// fmt.Sprintf("| %3d |", d.VulnInfo.Confidence.Score),
// summary,
// }
// }
icols := make([]interface{}, len(cols))
for j := range cols {
@@ -748,7 +761,7 @@ func detailLines() (string, error) {
}
cveInfo := currentScanResult.AllCves()[currentCveInfo]
cveID := cveInfo.CveDetail.CveID
cveID := cveInfo.VulnInfo.CveID
tmpl, err := template.New("detail").Parse(detailTemplate())
if err != nil {
@@ -758,22 +771,27 @@ func detailLines() (string, error) {
var cvssSeverity, cvssVector, summary string
var refs []cve.Reference
switch {
case config.Conf.Lang == "ja" &&
0 < cveInfo.CveDetail.Jvn.CvssScore():
jvn := cveInfo.CveDetail.Jvn
cvssSeverity = jvn.CvssSeverity()
cvssVector = jvn.CvssVector()
summary = fmt.Sprintf("%s\n%s", jvn.CveTitle(), jvn.CveSummary())
refs = jvn.VulnSiteReferences()
//TODO
// case config.Conf.Lang == "ja" &&
// 0 < cveInfo.CveDetail.Jvn.CvssScore():
// jvn := cveInfo.CveDetail.Jvn
// cvssSeverity = jvn.CvssSeverity()
// cvssVector = jvn.CvssVector()
// summary = fmt.Sprintf("%s\n%s", jvn.CveTitle(), jvn.CveSummary())
// refs = jvn.VulnSiteReferences()
default:
nvd := cveInfo.CveDetail.Nvd
cvssSeverity = nvd.CvssSeverity()
cvssVector = nvd.CvssVector()
summary = nvd.CveSummary()
refs = nvd.VulnSiteReferences()
var nvd *models.CveContent
if cont, found := cveInfo.Get(models.NVD); found {
nvd = cont
}
// cvssSeverity = nvd.CvssSeverity()
// cvssVector = nvd.CvssVector()
summary = nvd.Summary
// refs = nvd.VulnSiteReferences()
}
cweURL := cweURL(cveInfo.CveDetail.CweID())
//TODO
// cweURL := cweURL(cveInfo.CveDetail.CweID())
links := []string{
fmt.Sprintf("[NVD]( %s )", fmt.Sprintf("%s/%s", nvdBaseURL, cveID)),
@@ -787,11 +805,12 @@ func detailLines() (string, error) {
links = append(links, fmt.Sprintf("[%s]( %s )", link.title, link.url))
}
//TODO
var cvssScore string
if cveInfo.CveDetail.CvssScore(config.Conf.Lang) == -1 {
if cveInfo.CvssV2Score() == -1 {
cvssScore = "?"
} else {
cvssScore = fmt.Sprintf("%4.1f", cveInfo.CveDetail.CvssScore(config.Conf.Lang))
// } else {
// cvssScore = fmt.Sprintf("%4.1f", cveInfo.CveDetail.CvssScore(config.Conf.Lang))
}
packages := []string{}
@@ -804,13 +823,14 @@ func detailLines() (string, error) {
}
data := dataForTmpl{
CveID: cveID,
CvssScore: cvssScore,
CvssSeverity: cvssSeverity,
CvssVector: cvssVector,
Summary: summary,
Confidence: cveInfo.VulnInfo.Confidence,
CweURL: cweURL,
CveID: cveID,
CvssScore: cvssScore,
CvssSeverity: cvssSeverity,
CvssVector: cvssVector,
Summary: summary,
Confidence: cveInfo.VulnInfo.Confidence,
//TODO
// CweURL: cweURL,
VulnSiteLinks: links,
References: refs,
Packages: packages,

View File

@@ -126,38 +126,43 @@ No CVE-IDs are found in updatable packages.
var scols []string
switch {
case config.Conf.Lang == "ja" &&
0 < d.CveDetail.Jvn.CvssScore():
summary := fmt.Sprintf("%s\n%s\n%s\n%sConfidence: %v",
d.CveDetail.Jvn.CveTitle(),
d.CveDetail.Jvn.Link(),
distroLinks(d, r.Family)[0].url,
packsVer,
d.VulnInfo.Confidence,
)
scols = []string{
d.CveDetail.CveID,
fmt.Sprintf("%-4.1f (%s)",
d.CveDetail.CvssScore(config.Conf.Lang),
d.CveDetail.Jvn.CvssSeverity(),
),
summary,
}
// case config.Conf.Lang == "ja" &&
//TODO
// 0 < d.CveDetail.Jvn.CvssScore():
// summary := fmt.Sprintf("%s\n%s\n%s\n%sConfidence: %v",
// d.CveDetail.Jvn.CveTitle(),
// d.CveDetail.Jvn.Link(),
// distroLinks(d, r.Family)[0].url,
// packsVer,
// d.VulnInfo.Confidence,
// )
// scols = []string{
// d.CveDetail.CveID,
// fmt.Sprintf("%-4.1f (%s)",
// d.CveDetail.CvssScore(config.Conf.Lang),
// d.CveDetail.Jvn.CvssSeverity(),
// ),
// summary,
// }
case 0 < d.CveDetail.CvssScore("en"):
case 0 < d.CvssV2Score():
var nvd *models.CveContent
if cont, found := d.Get(models.NVD); found {
nvd = cont
}
summary := fmt.Sprintf("%s\n%s/%s\n%s\n%sConfidence: %v",
d.CveDetail.Nvd.CveSummary(),
nvd.Summary,
cveDetailsBaseURL,
d.CveDetail.CveID,
d.VulnInfo.CveID,
distroLinks(d, r.Family)[0].url,
packsVer,
d.VulnInfo.Confidence,
)
scols = []string{
d.CveDetail.CveID,
d.VulnInfo.CveID,
fmt.Sprintf("%-4.1f (%s)",
d.CveDetail.CvssScore(config.Conf.Lang),
d.CveDetail.Nvd.CvssSeverity(),
d.CvssV2Score(),
"TODO",
),
summary,
}
@@ -165,7 +170,7 @@ No CVE-IDs are found in updatable packages.
summary := fmt.Sprintf("%s\n%sConfidence: %v",
distroLinks(d, r.Family)[0].url, packsVer, d.VulnInfo.Confidence)
scols = []string{
d.CveDetail.CveID,
d.VulnInfo.CveID,
"?",
summary,
}
@@ -229,39 +234,40 @@ No CVE-IDs are found in updatable packages.
return fmt.Sprintf("%s\n%s\n%s", header, detail, formatChangelogs(r))
}
//TODO
func formatPlainTextDetails(r models.ScanResult, osFamily string) (scoredReport, unscoredReport []string) {
for _, cve := range r.KnownCves {
switch config.Conf.Lang {
case "en":
if 0 < cve.CveDetail.Nvd.CvssScore() {
scoredReport = append(
scoredReport, formatPlainTextDetailsLangEn(cve, osFamily))
} else {
scoredReport = append(
scoredReport, formatPlainTextUnknownCve(cve, osFamily))
}
case "ja":
if 0 < cve.CveDetail.Jvn.CvssScore() {
scoredReport = append(
scoredReport, formatPlainTextDetailsLangJa(cve, osFamily))
} else if 0 < cve.CveDetail.Nvd.CvssScore() {
scoredReport = append(
scoredReport, formatPlainTextDetailsLangEn(cve, osFamily))
} else {
scoredReport = append(
scoredReport, formatPlainTextUnknownCve(cve, osFamily))
}
}
}
for _, cve := range r.UnknownCves {
unscoredReport = append(
unscoredReport, formatPlainTextUnknownCve(cve, osFamily))
}
// for _, cve := range r.KnownCves {
// switch config.Conf.Lang {
// case "en":
// if 0 < cve.CveDetail.Nvd.CvssScore() {
// scoredReport = append(
// scoredReport, formatPlainTextDetailsLangEn(cve, osFamily))
// } else {
// scoredReport = append(
// scoredReport, formatPlainTextUnknownCve(cve, osFamily))
// }
// case "ja":
// if 0 < cve.CveDetail.Jvn.CvssScore() {
// scoredReport = append(
// scoredReport, formatPlainTextDetailsLangJa(cve, osFamily))
// } else if 0 < cve.CveDetail.Nvd.CvssScore() {
// scoredReport = append(
// scoredReport, formatPlainTextDetailsLangEn(cve, osFamily))
// } else {
// scoredReport = append(
// scoredReport, formatPlainTextUnknownCve(cve, osFamily))
// }
// }
// }
// for _, cve := range r.UnknownCves {
// unscoredReport = append(
// unscoredReport, formatPlainTextUnknownCve(cve, osFamily))
// }
return
}
func formatPlainTextUnknownCve(cveInfo models.CveInfo, osFamily string) string {
cveID := cveInfo.CveDetail.CveID
cveID := cveInfo.VulnInfo.CveID
dtable := uitable.New()
dtable.MaxColWidth = maxColWidth
dtable.Wrap = true
@@ -281,90 +287,94 @@ func formatPlainTextUnknownCve(cveInfo models.CveInfo, osFamily string) string {
return fmt.Sprintf("%s", dtable)
}
//TODO
func formatPlainTextDetailsLangJa(cveInfo models.CveInfo, osFamily string) string {
cveDetail := cveInfo.CveDetail
cveID := cveDetail.CveID
jvn := cveDetail.Jvn
return "TODO"
// cveDetail := cveInfo.CveDetail
// cveID := cveDetail.CveID
// jvn := cveDetail.Jvn
dtable := uitable.New()
dtable.MaxColWidth = maxColWidth
dtable.Wrap = true
dtable.AddRow(cveID)
dtable.AddRow("-------------")
if score := cveDetail.Jvn.CvssScore(); 0 < score {
dtable.AddRow("Score",
fmt.Sprintf("%4.1f (%s)",
cveDetail.Jvn.CvssScore(),
jvn.CvssSeverity(),
))
} else {
dtable.AddRow("Score", "?")
}
dtable.AddRow("Vector", jvn.CvssVector())
dtable.AddRow("Title", jvn.CveTitle())
dtable.AddRow("Description", jvn.CveSummary())
dtable.AddRow(cveDetail.CweID(), cweURL(cveDetail.CweID()))
dtable.AddRow(cveDetail.CweID()+"(JVN)", cweJvnURL(cveDetail.CweID()))
// dtable := uitable.New()
// dtable.MaxColWidth = maxColWidth
// dtable.Wrap = true
// dtable.AddRow(cveID)
// dtable.AddRow("-------------")
// if score := cveDetail.Jvn.CvssScore(); 0 < score {
// dtable.AddRow("Score",
// fmt.Sprintf("%4.1f (%s)",
// cveDetail.Jvn.CvssScore(),
// jvn.CvssSeverity(),
// ))
// } else {
// dtable.AddRow("Score", "?")
// }
// dtable.AddRow("Vector", jvn.CvssVector())
// dtable.AddRow("Title", jvn.CveTitle())
// dtable.AddRow("Description", jvn.CveSummary())
// dtable.AddRow(cveDetail.CweID(), cweURL(cveDetail.CweID()))
// dtable.AddRow(cveDetail.CweID()+"(JVN)", cweJvnURL(cveDetail.CweID()))
dtable.AddRow("JVN", jvn.Link())
dtable.AddRow("NVD", fmt.Sprintf("%s/%s", nvdBaseURL, cveID))
dtable.AddRow("MITRE", fmt.Sprintf("%s%s", mitreBaseURL, cveID))
dtable.AddRow("CVE Details", fmt.Sprintf("%s/%s", cveDetailsBaseURL, cveID))
dtable.AddRow("CVSSv2 Clac", fmt.Sprintf(cvssV2CalcBaseURL, cveID))
dtable.AddRow("CVSSv3 Clac", fmt.Sprintf(cvssV3CalcBaseURL, cveID))
// dtable.AddRow("JVN", jvn.Link())
// dtable.AddRow("NVD", fmt.Sprintf("%s/%s", nvdBaseURL, cveID))
// dtable.AddRow("MITRE", fmt.Sprintf("%s%s", mitreBaseURL, cveID))
// dtable.AddRow("CVE Details", fmt.Sprintf("%s/%s", cveDetailsBaseURL, cveID))
// dtable.AddRow("CVSSv2 Clac", fmt.Sprintf(cvssV2CalcBaseURL, cveID))
// dtable.AddRow("CVSSv3 Clac", fmt.Sprintf(cvssV3CalcBaseURL, cveID))
dlinks := distroLinks(cveInfo, osFamily)
for _, link := range dlinks {
dtable.AddRow(link.title, link.url)
}
// dlinks := distroLinks(cveInfo, osFamily)
// for _, link := range dlinks {
// dtable.AddRow(link.title, link.url)
// }
dtable = addPackageInfos(dtable, cveInfo.Packages)
dtable = addCpeNames(dtable, cveInfo.CpeNames)
dtable.AddRow("Confidence", cveInfo.VulnInfo.Confidence)
// dtable = addPackageInfos(dtable, cveInfo.Packages)
// dtable = addCpeNames(dtable, cveInfo.CpeNames)
// dtable.AddRow("Confidence", cveInfo.VulnInfo.Confidence)
return fmt.Sprintf("%s", dtable)
// return fmt.Sprintf("%s", dtable)
}
//TODO
func formatPlainTextDetailsLangEn(d models.CveInfo, osFamily string) string {
cveDetail := d.CveDetail
cveID := cveDetail.CveID
nvd := cveDetail.Nvd
return ""
// cveDetail := d.CveDetail
// cveID := cveDetail.CveID
// nvd := cveDetail.Nvd
dtable := uitable.New()
dtable.MaxColWidth = maxColWidth
dtable.Wrap = true
dtable.AddRow(cveID)
dtable.AddRow("-------------")
// dtable := uitable.New()
// dtable.MaxColWidth = maxColWidth
// dtable.Wrap = true
// dtable.AddRow(cveID)
// dtable.AddRow("-------------")
if score := cveDetail.Nvd.CvssScore(); 0 < score {
dtable.AddRow("Score",
fmt.Sprintf("%4.1f (%s)",
cveDetail.Nvd.CvssScore(),
nvd.CvssSeverity(),
))
} else {
dtable.AddRow("Score", "?")
}
// if score := cveDetail.Nvd.CvssScore(); 0 < score {
// dtable.AddRow("Score",
// fmt.Sprintf("%4.1f (%s)",
// cveDetail.Nvd.CvssScore(),
// nvd.CvssSeverity(),
// ))
// } else {
// dtable.AddRow("Score", "?")
// }
dtable.AddRow("Vector", nvd.CvssVector())
dtable.AddRow("Summary", nvd.CveSummary())
dtable.AddRow("CWE", cweURL(cveDetail.CweID()))
// dtable.AddRow("Vector", nvd.CvssVector())
// dtable.AddRow("Summary", nvd.CveSummary())
// dtable.AddRow("CWE", cweURL(cveDetail.CweID()))
dtable.AddRow("NVD", fmt.Sprintf("%s/%s", nvdBaseURL, cveID))
dtable.AddRow("MITRE", fmt.Sprintf("%s%s", mitreBaseURL, cveID))
dtable.AddRow("CVE Details", fmt.Sprintf("%s/%s", cveDetailsBaseURL, cveID))
dtable.AddRow("CVSSv2 Clac", fmt.Sprintf(cvssV2CalcBaseURL, cveID))
dtable.AddRow("CVSSv3 Clac", fmt.Sprintf(cvssV3CalcBaseURL, cveID))
// dtable.AddRow("NVD", fmt.Sprintf("%s/%s", nvdBaseURL, cveID))
// dtable.AddRow("MITRE", fmt.Sprintf("%s%s", mitreBaseURL, cveID))
// dtable.AddRow("CVE Details", fmt.Sprintf("%s/%s", cveDetailsBaseURL, cveID))
// dtable.AddRow("CVSSv2 Clac", fmt.Sprintf(cvssV2CalcBaseURL, cveID))
// dtable.AddRow("CVSSv3 Clac", fmt.Sprintf(cvssV3CalcBaseURL, cveID))
links := distroLinks(d, osFamily)
for _, link := range links {
dtable.AddRow(link.title, link.url)
}
dtable = addPackageInfos(dtable, d.Packages)
dtable = addCpeNames(dtable, d.CpeNames)
dtable.AddRow("Confidence", d.VulnInfo.Confidence)
// links := distroLinks(d, osFamily)
// for _, link := range links {
// dtable.AddRow(link.title, link.url)
// }
// dtable = addPackageInfos(dtable, d.Packages)
// dtable = addCpeNames(dtable, d.CpeNames)
// dtable.AddRow("Confidence", d.VulnInfo.Confidence)
return fmt.Sprintf("%s\n", dtable)
// return fmt.Sprintf("%s\n", dtable)
}
type distroLink struct {
@@ -374,7 +384,7 @@ type distroLink struct {
// distroLinks add Vendor URL of the CVE to table
func distroLinks(cveInfo models.CveInfo, osFamily string) []distroLink {
cveID := cveInfo.CveDetail.CveID
cveID := cveInfo.VulnInfo.CveID
switch osFamily {
case "rhel", "centos":
links := []distroLink{

View File

@@ -20,6 +20,7 @@ package util
import (
"fmt"
"net/url"
"strconv"
"strings"
"github.com/future-architect/vuls/config"
@@ -135,3 +136,31 @@ func Truncate(str string, length int) string {
}
return str
}
// 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:len(ss)], "/")
}
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
ss := strings.Split(scoreVector, "/CVSS:3.0/")
if 1 < len(ss) {
if score, err = strconv.ParseFloat(ss[0], 64); err != nil {
return 0, ""
}
return score, strings.Join(ss[1:len(ss)], "/")
}
return 0, ""
}

View File

@@ -171,3 +171,69 @@ func TestTruncate(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: "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)
}
}
}