From c103b79ec24a5ec9e3ff0c5b328d9a71952ed2f5 Mon Sep 17 00:00:00 2001 From: Kota Kanbe Date: Thu, 4 May 2017 13:57:22 +0900 Subject: [PATCH] Change models structure --- Gopkg.lock | 28 ++- commands/report.go | 8 +- commands/util.go | 33 ++- cveapi/cve_client.go | 1 + models/models.go | 515 ++++++++++++++++++++++------------------ oval/debian.go | 71 ++---- oval/redhat.go | 135 +++++------ oval/redhat_test.go | 69 ++++++ report/azureblob.go | 10 +- report/email.go | 4 +- report/slack.go | 236 +++++++++---------- report/tui.go | 271 ++++++++++----------- report/util.go | 547 ++++++++++++++++++++++--------------------- scan/base.go | 4 +- util/util.go | 29 --- util/util_test.go | 66 ------ 16 files changed, 1022 insertions(+), 1005 deletions(-) create mode 100644 oval/redhat_test.go diff --git a/Gopkg.lock b/Gopkg.lock index 6713d9d8..9fe8c4f2 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -4,13 +4,13 @@ memo = "bd95ed8c2b0aa32327ae55d88bff888b8198d238f7a71eee0f8663494664a0ac" branch = "master" name = "github.com/Azure/azure-storage-go" packages = ["."] - revision = "12ccaadb081cdd217702067d28da9a7ff4305239" + revision = "4fe73b0b4f68bf8a7cad2920ef563fe4c40ac5c0" [[projects]] name = "github.com/Azure/go-autorest" - packages = ["autorest","autorest/azure","autorest/date"] - revision = "a2fdd780c9a50455cecd249b00bdc3eb73a78e31" - version = "v7.3.1" + packages = ["autorest","autorest/adal","autorest/azure","autorest/date"] + revision = "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d" + version = "v8.0.0" [[projects]] name = "github.com/BurntSushi/toml" @@ -22,7 +22,7 @@ memo = "bd95ed8c2b0aa32327ae55d88bff888b8198d238f7a71eee0f8663494664a0ac" branch = "master" name = "github.com/Sirupsen/logrus" packages = ["."] - revision = "10f801ebc38b33738c9d17d50860f484a0988ff5" + revision = "508f304878257fb578be3e863e3990ed9ec3aa2e" [[projects]] name = "github.com/asaskevich/govalidator" @@ -141,7 +141,7 @@ memo = "bd95ed8c2b0aa32327ae55d88bff888b8198d238f7a71eee0f8663494664a0ac" branch = "master" name = "github.com/kotakanbe/goval-dictionary" packages = ["config","db","log","models"] - revision = "5470d7565a9de51593f53327ce14c97d466b05ab" + revision = "545199055508ae62a6d3bd34ef83034fbfc04d7f" [[projects]] branch = "master" @@ -221,6 +221,12 @@ memo = "bd95ed8c2b0aa32327ae55d88bff888b8198d238f7a71eee0f8663494664a0ac" revision = "2adb3e0c4ddd8778c4adde609d2dfd4fbe6096ea" version = "1.6" +[[projects]] + name = "github.com/satori/uuid" + packages = ["."] + revision = "879c5887cd475cd7864858769793b2ceb0d44feb" + version = "v1.1.0" + [[projects]] branch = "master" name = "github.com/valyala/bytebufferpool" @@ -237,28 +243,28 @@ memo = "bd95ed8c2b0aa32327ae55d88bff888b8198d238f7a71eee0f8663494664a0ac" branch = "master" name = "github.com/ymomoi/goval-parser" packages = ["oval"] - revision = "4ddf6fc4f1a1af026f7cae41f76979c7ff2b2e2f" + revision = "003ac9af5fffac6c97ab1def025d2cb73e88469a" [[projects]] branch = "master" name = "golang.org/x/crypto" packages = ["curve25519","ed25519","ed25519/internal/edwards25519","ssh","ssh/agent","ssh/terminal"] - revision = "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e" + revision = "04eae0b62feaaf659a0ce2c4e8dc70b6ae2fff67" [[projects]] branch = "master" name = "golang.org/x/net" packages = ["context","idna","publicsuffix"] - revision = "da118f7b8e5954f39d0d2130ab35d4bf0e3cb344" + revision = "feeb485667d1fdabe727840fe00adc22431bc86e" [[projects]] branch = "master" name = "golang.org/x/sys" packages = ["unix"] - revision = "9f30dcbe5be197894515a338a9bda9253567ea8f" + revision = "9ccfe848b9db8435a24c424abbc07a921adf1df5" [[projects]] branch = "master" name = "golang.org/x/text" packages = ["internal/gen","internal/triegen","internal/ucd","secure/bidirule","transform","unicode/bidi","unicode/cldr","unicode/norm","unicode/rangetable"] - revision = "a9a820217f98f7c8a207ec1e45a874e1fe12c478" + revision = "470f45bf29f4147d6fbd7dfd0a02a848e49f5bf4" diff --git a/commands/report.go b/commands/report.go index 5600e440..08b3afae 100644 --- a/commands/report.go +++ b/commands/report.go @@ -422,7 +422,6 @@ 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 { @@ -463,6 +462,13 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{} var res models.ScanResults for _, r := range results { + //TODO remove + for _, vuln := range r.ScannedCves { + if _, ok := vuln.CveContents.Get(models.CveContentType(r.Family)); !ok { + fmt.Println("not in oval") + pp.Println(vuln) + } + } res = append(res, r.FilterByCvssOver()) } diff --git a/commands/util.go b/commands/util.go index 98306c36..93b99d76 100644 --- a/commands/util.go +++ b/commands/util.go @@ -231,8 +231,9 @@ func diff(current, previous models.ScanResults) (diff models.ScanResults, err er if found { currentResult.ScannedCves = getNewCves(previousResult, currentResult) - currentResult.KnownCves = []models.CveInfo{} - currentResult.UnknownCves = []models.CveInfo{} + //TODO + // currentResult.KnownCves = []models.CveInfo{} + // currentResult.UnknownCves = []models.CveInfo{} currentResult.Packages = models.PackageInfoList{} for _, s := range currentResult.ScannedCves { @@ -270,27 +271,28 @@ func isCveInfoUpdated(current, previous models.ScanResult, CveID string) bool { Jvn time.Time } + //TODO previousModifies := lastModified{} - for _, c := range previous.KnownCves { + for _, c := range previous.ScannedCves { if CveID == c.CveID { //TODO - if nvd, found := c.Get(models.NVD); found { + if nvd, found := c.CveContents.Get(models.NVD); found { previousModifies.Nvd = nvd.LastModified } - if jvn, found := c.Get(models.JVN); found { + if jvn, found := c.CveContents.Get(models.JVN); found { previousModifies.Jvn = jvn.LastModified } } } currentModifies := lastModified{} - for _, c := range current.KnownCves { - if CveID == c.VulnInfo.CveID { + for _, c := range current.ScannedCves { + if CveID == c.CveID { //TODO - if nvd, found := c.Get(models.NVD); found { + if nvd, found := c.CveContents.Get(models.NVD); found { previousModifies.Nvd = nvd.LastModified } - if jvn, found := c.Get(models.JVN); found { + if jvn, found := c.CveContents.Get(models.JVN); found { previousModifies.Jvn = jvn.LastModified } } @@ -352,7 +354,14 @@ func scanVulnByCpeNames(cpeNames []string, scannedVulns []models.VulnInfo) ([]mo } func needToRefreshCve(r models.ScanResult) bool { - return r.Lang != c.Conf.Lang || len(r.KnownCves) == 0 && - len(r.UnknownCves) == 0 && - len(r.IgnoredCves) == 0 + if r.Lang != c.Conf.Lang { + return true + } + + for _, cve := range r.ScannedCves { + if 0 < len(cve.CveContents) { + return false + } + } + return true } diff --git a/cveapi/cve_client.go b/cveapi/cve_client.go index 972f7ae9..af219238 100644 --- a/cveapi/cve_client.go +++ b/cveapi/cve_client.go @@ -69,6 +69,7 @@ type response struct { CveDetail cve.CveDetail } +//TODO rename to FetchCveDictionary func (api cvedictClient) FetchCveDetails(cveIDs []string) (cveDetails cve.CveDetails, err error) { switch config.Conf.CveDBType { case "sqlite3", "mysql", "postgres": diff --git a/models/models.go b/models/models.go index 7eee245e..387b63db 100644 --- a/models/models.go +++ b/models/models.go @@ -60,25 +60,19 @@ type ScanResult struct { Container Container Platform Platform - // Scanned Vulns via SSH + CPE Vulns - ScannedCves []VulnInfo - - KnownCves CveInfos - UnknownCves CveInfos - IgnoredCves CveInfos + // Scanned Vulns by SSH scan + CPE + OVAL + ScannedCves VulnInfos Packages PackageInfoList - Errors []string Optional [][]interface{} } // FillCveDetail fetches NVD, JVN from CVE Database, and then set to fields. +//TODO rename to FillCveDictionary func (r ScanResult) FillCveDetail() (*ScanResult, error) { - set := map[string]VulnInfo{} var cveIDs []string for _, v := range r.ScannedCves { - set[v.CveID] = v cveIDs = append(cveIDs, v.CveID) } @@ -86,64 +80,24 @@ func (r ScanResult) FillCveDetail() (*ScanResult, error) { if err != nil { return nil, err } - - r.IgnoredCves = CveInfos{} for _, d := range ds { nvd := *r.convertNvdToModel(d.CveID, d.Nvd) jvn := *r.convertJvnToModel(d.CveID, d.Jvn) - cinfo := CveInfo{ - CveContents: []CveContent{nvd, jvn}, - VulnInfo: set[d.CveID], - } - cinfo.NilSliceToEmpty() - - // ignored - ignore := false - for _, icve := range config.Conf.Servers[r.ServerName].IgnoreCves { - if icve == d.CveID { - r.IgnoredCves.Insert(cinfo) - ignore = true + for i, sc := range r.ScannedCves { + if sc.CveID == d.CveID { + for _, con := range []CveContent{nvd, jvn} { + if !con.Empty() { + r.ScannedCves[i].CveContents.Upsert(con) + } + } break } } - if ignore { - continue - } - - // Update known if KnownCves already have cinfo - if c, ok := r.KnownCves.Get(cinfo.CveID); ok { - 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 { - for _, con := range []CveContent{nvd, jvn} { - if !c.Update(con) { - c.Insert(con) - } - } - r.UnknownCves.Update(c) - continue - } - - // unknown - if d.CvssScore(config.Conf.Lang) <= 0 { - r.UnknownCves.Insert(cinfo) - continue - } - - // known - r.KnownCves.Insert(cinfo) } - sort.Sort(r.KnownCves) - sort.Sort(r.UnknownCves) - sort.Sort(r.IgnoredCves) + //TODO sort + // sort.Sort(r.KnownCves) + // sort.Sort(r.UnknownCves) + // sort.Sort(r.IgnoredCves) return &r, nil } @@ -236,19 +190,21 @@ func (r ScanResult) convertJvnToModel(cveID string, jvn cvedict.Jvn) *CveContent // FilterByCvssOver is filter function. func (r ScanResult) FilterByCvssOver() ScanResult { - cveInfos := []CveInfo{} // TODO: Set correct default value if config.Conf.CvssScoreOver == 0 { config.Conf.CvssScoreOver = -1.1 } - for _, cveInfo := range r.KnownCves { - if config.Conf.CvssScoreOver <= cveInfo.CvssV2Score() { - cveInfos = append(cveInfos, cveInfo) + // TODO: Filter by ignore cves??? + filtered := VulnInfos{} + for _, sc := range r.ScannedCves { + if config.Conf.CvssScoreOver <= sc.CveContents.CvssV2Score() { + filtered = append(filtered, sc) } } - r.KnownCves = cveInfos - return r + copiedScanResult := r + copiedScanResult.ScannedCves = filtered + return copiedScanResult } // ReportFileName returns the filename on localhost without extention @@ -311,9 +267,8 @@ func (r ScanResult) FormatServerName() string { // CveSummary summarize the number of CVEs group by CVSSv2 Severity func (r ScanResult) CveSummary() string { var high, medium, low, unknown int - cves := append(r.KnownCves, r.UnknownCves...) - for _, cveInfo := range cves { - score := cveInfo.CvssV2Score() + for _, vInfo := range r.ScannedCves { + score := vInfo.CveContents.CvssV2Score() switch { case 7.0 <= score: high++ @@ -334,18 +289,14 @@ func (r ScanResult) CveSummary() string { high+medium+low+unknown, high, medium, low, unknown) } -// AllCves returns Known and Unknown CVEs -func (r ScanResult) AllCves() []CveInfo { - return append(r.KnownCves, r.UnknownCves...) -} - // NWLink has network link information. -type NWLink struct { - IPAddress string - Netmask string - DevName string - LinkState string -} +//TODO remove +// type NWLink struct { +// IPAddress string +// Netmask string +// DevName string +// LinkState string +// } // Confidence is a ranking how confident the CVE-ID was deteted correctly // Score: 0 - 100 @@ -405,6 +356,89 @@ var ChangelogLenientMatch = Confidence{50, ChangelogLenientMatchStr} // VulnInfos is VulnInfo list, getter/setter, sortable methods. type VulnInfos []VulnInfo +// FindByCveID find by CVEID +// TODO remove +// func (v *VulnInfos) FindByCveID(cveID string) (VulnInfo, bool) { +// for _, p := range s { +// if cveID == p.CveID { +// return p, true +// } +// } +// return VulnInfo{CveID: cveID}, false +// } + +// Get VulnInfo by cveID +func (v *VulnInfos) Get(cveID string) (VulnInfo, bool) { + for _, vv := range *v { + if vv.CveID == cveID { + return vv, true + } + } + return VulnInfo{}, false +} + +// Delete by cveID +func (v *VulnInfos) Delete(cveID string) { + vInfos := *v + for i, vv := range vInfos { + if vv.CveID == cveID { + *v = append(vInfos[:i], vInfos[i+1:]...) + break + } + } +} + +// Insert VulnInfo +func (v *VulnInfos) Insert(vinfo VulnInfo) { + *v = append(*v, vinfo) +} + +// Update VulnInfo +func (v *VulnInfos) Update(vInfo VulnInfo) (ok bool) { + for i, vv := range *v { + if vv.CveID == vInfo.CveID { + (*v)[i] = vInfo + return true + } + } + return false +} + +// Upsert cveInfo +func (v *VulnInfos) Upsert(vInfo VulnInfo) { + ok := v.Update(vInfo) + if !ok { + v.Insert(vInfo) + } +} + +// immutable +// func (v *VulnInfos) set(cveID string, v VulnInfo) VulnInfos { +// for i, p := range s { +// if cveID == p.CveID { +// s[i] = v +// return s +// } +// } +// return append(s, v) +// } + +//TODO GO 1.8 +// Len implement Sort Interface +// func (s VulnInfos) Len() int { +// return len(s) +// } + +// // Swap implement Sort Interface +// func (s VulnInfos) Swap(i, j int) { +// s[i], s[j] = s[j], s[i] +// } + +// // Less implement Sort Interface +// func (s VulnInfos) Less(i, j int) bool { +// return s[i].CveID < s[j].CveID +// } + // VulnInfo holds a vulnerability information and unsecure packages type VulnInfo struct { CveID string @@ -412,6 +446,7 @@ type VulnInfo struct { Packages PackageInfoList DistroAdvisories []DistroAdvisory // for Aamazon, RHEL, FreeBSD CpeNames []string + CveContents CveContents } // NilSliceToEmpty set nil slice fields to empty slice to avoid null in JSON @@ -427,167 +462,132 @@ func (v *VulnInfo) NilSliceToEmpty() { } } -// FindByCveID find by CVEID -func (s VulnInfos) FindByCveID(cveID string) (VulnInfo, bool) { - for _, p := range s { - if cveID == p.CveID { - return p, true - } - } - return VulnInfo{CveID: cveID}, false -} - -// immutable -func (s VulnInfos) set(cveID string, v VulnInfo) VulnInfos { - for i, p := range s { - if cveID == p.CveID { - s[i] = v - return s - } - } - return append(s, v) -} - -// Len implement Sort Interface -func (s VulnInfos) Len() int { - return len(s) -} - -// Swap implement Sort Interface -func (s VulnInfos) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -// Less implement Sort Interface -func (s VulnInfos) Less(i, j int) bool { - return s[i].CveID < s[j].CveID -} - // CveInfos is for sorting -type CveInfos []CveInfo +// type CveInfos []CveInfo -func (c CveInfos) Len() int { - return len(c) -} +// func (c CveInfos) Len() int { +// return len(c) +// } -func (c CveInfos) Swap(i, j int) { - c[i], c[j] = c[j], c[i] -} +// func (c CveInfos) Swap(i, j int) { +// c[i], c[j] = c[j], c[i] +// } -func (c CveInfos) Less(i, j int) bool { - if c[i].CvssV2Score() == c[j].CvssV2Score() { - return c[i].CveID < c[j].CveID - } - return c[j].CvssV2Score() < c[i].CvssV2Score() -} +// func (c CveInfos) Less(i, j int) bool { +// if c[i].CvssV2Score() == c[j].CvssV2Score() { +// return c[i].CveID < c[j].CveID +// } +// return c[j].CvssV2Score() < c[i].CvssV2Score() +// } -// Get cveInfo by cveID -func (c CveInfos) Get(cveID string) (CveInfo, bool) { - for _, cve := range c { - if cve.VulnInfo.CveID == cveID { - return cve, true - } - } - return CveInfo{}, false -} +// // Get cveInfo by cveID +// func (c CveInfos) Get(cveID string) (CveInfo, bool) { +// for _, cve := range c { +// if cve.VulnInfo.CveID == cveID { +// return cve, true +// } +// } +// return CveInfo{}, false +// } -// Delete by cveID -func (c *CveInfos) Delete(cveID string) { - cveInfos := *c - for i, cve := range cveInfos { - if cve.VulnInfo.CveID == cveID { - *c = append(cveInfos[:i], cveInfos[i+1:]...) - break - } - } -} +// // Delete by cveID +// func (c *CveInfos) Delete(cveID string) { +// cveInfos := *c +// for i, cve := range cveInfos { +// if cve.VulnInfo.CveID == cveID { +// *c = append(cveInfos[:i], cveInfos[i+1:]...) +// break +// } +// } +// } -// Insert cveInfo -func (c *CveInfos) Insert(cveInfo CveInfo) { - *c = append(*c, cveInfo) -} +// // Insert cveInfo +// func (c *CveInfos) Insert(cveInfo CveInfo) { +// *c = append(*c, cveInfo) +// } -// Update cveInfo -func (c CveInfos) Update(cveInfo CveInfo) (ok bool) { - for i, cve := range c { - if cve.VulnInfo.CveID == cveInfo.VulnInfo.CveID { - c[i] = cveInfo - return true - } - } - return false -} +// // Update cveInfo +// func (c CveInfos) Update(cveInfo CveInfo) (ok bool) { +// for i, cve := range c { +// if cve.VulnInfo.CveID == cveInfo.VulnInfo.CveID { +// c[i] = cveInfo +// return true +// } +// } +// return false +// } -// Upsert cveInfo -func (c *CveInfos) Upsert(cveInfo CveInfo) { - ok := c.Update(cveInfo) - if !ok { - c.Insert(cveInfo) - } -} +// // Upsert cveInfo +// func (c *CveInfos) Upsert(cveInfo CveInfo) { +// ok := c.Update(cveInfo) +// if !ok { +// c.Insert(cveInfo) +// } +// } +//TODO // CveInfo has CVE detailed Information. -type CveInfo struct { - VulnInfo - CveContents []CveContent -} +// type CveInfo struct { +// 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 -} +// 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) -} +// // 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 -} +// // 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 -} +// // 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() { - 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{} - // } -} +// // NilSliceToEmpty set nil slice fields to empty slice to avoid null in JSON +// func (c *CveInfo) NilSliceToEmpty() { +// 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 @@ -612,6 +612,68 @@ const ( Ubuntu CveContentType = "ubuntu" ) +// CveContents has slice of CveContent +type CveContents []CveContent + +// Get CveContent by cveID +// TODO Pointer +func (v *CveContents) Get(typestr CveContentType) (CveContent, bool) { + for _, vv := range *v { + if vv.Type == typestr { + return vv, true + } + } + return CveContent{}, false +} + +// Delete by cveID +func (v *CveContents) Delete(typestr CveContentType) { + cveContents := *v + for i, cc := range cveContents { + if cc.Type == typestr { + *v = append(cveContents[:i], cveContents[i+1:]...) + break + } + } +} + +// Insert CveContent +func (v *CveContents) Insert(cont CveContent) { + *v = append(*v, cont) +} + +// Update VulnInfo +func (v *CveContents) Update(cont CveContent) (ok bool) { + for i, vv := range *v { + if vv.Type == cont.Type { + (*v)[i] = cont + return true + } + } + return false +} + +// Upsert CveContent +func (v *CveContents) Upsert(cont CveContent) { + ok := v.Update(cont) + if !ok { + v.Insert(cont) + } +} + +// CvssV2Score returns CVSS V2 Score +func (v *CveContents) CvssV2Score() float64 { + //TODO + if cont, found := v.Get(NVD); found { + return cont.Cvss2Score + } else if cont, found := v.Get(JVN); found { + return cont.Cvss2Score + } else if cont, found := v.Get(RedHat); found { + return cont.Cvss2Score + } + return -1 +} + // CveContent has abstraction of various vulnerability information type CveContent struct { Type CveContentType @@ -630,6 +692,11 @@ type CveContent struct { LastModified time.Time } +// Empty checks the content is empty +func (c CveContent) Empty() bool { + return c.Summary == "" +} + // Cpe is Common Platform Enumeration type Cpe struct { CpeName string diff --git a/oval/debian.go b/oval/debian.go index b9cf3194..76720e91 100644 --- a/oval/debian.go +++ b/oval/debian.go @@ -59,64 +59,30 @@ 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 - updatedCves := []models.VulnInfo{} - - // Update scanned confidence to ovalmatch - for _, scanned := range r.ScannedCves { - if scanned.CveID == definition.Debian.CveID { - found = true - if scanned.Confidence.Score < models.OvalMatch.Score { - scanned.Confidence = models.OvalMatch - } - } - updatedCves = append(updatedCves, scanned) - } - - vuln := models.VulnInfo{ - CveID: definition.Debian.CveID, - Confidence: models.OvalMatch, - Packages: getPackageInfoList(r, definition), - } - - if !found { - util.Log.Debugf("%s is newly detected by OVAL", vuln.CveID) - updatedCves = append(updatedCves, vuln) - } - r.ScannedCves = updatedCves - - // Update KnownCves by OVAL info ovalContent := *o.convertToModel(definition) ovalContent.Type = models.CveContentType(r.Family) - cInfo, ok := r.KnownCves.Get(definition.Debian.CveID) + vinfo, ok := r.ScannedCves.Get(definition.Debian.CveID) if !ok { - cInfo.VulnInfo = vuln - cInfo.CveContents = []models.CveContent{ovalContent} - } - if !cInfo.Update(ovalContent) { - cInfo.Insert(ovalContent) - } - if cInfo.VulnInfo.Confidence.Score < models.OvalMatch.Score { - cInfo.Confidence = models.OvalMatch - } - r.KnownCves.Upsert(cInfo) - - // Update UnknownCves by OVAL info - cInfo, ok = r.UnknownCves.Get(definition.Debian.CveID) - if ok { - r.UnknownCves.Delete(definition.Debian.CveID) - - // Insert new CveInfo - if !cInfo.Update(ovalContent) { - cInfo.Insert(ovalContent) + util.Log.Infof("%s is newly detected by OVAL", + definition.Debian.CveID) + vinfo = models.VulnInfo{ + CveID: definition.Debian.CveID, + Confidence: models.OvalMatch, + Packages: getPackageInfoList(r, definition), + CveContents: []models.CveContent{ovalContent}, } - if cInfo.VulnInfo.Confidence.Score < models.OvalMatch.Score { - cInfo.Confidence = models.OvalMatch + } else { + if _, ok := vinfo.CveContents.Get(models.CveContentType(r.Family)); !ok { + util.Log.Infof("%s is also detected by OVAL", definition.Debian.CveID) + } else { + util.Log.Infof("%s will be updated by OVAL", definition.Debian.CveID) } - r.KnownCves.Upsert(cInfo) + if vinfo.Confidence.Score < models.OvalMatch.Score { + vinfo.Confidence = models.OvalMatch + } + vinfo.CveContents.Upsert(ovalContent) } - + r.ScannedCves.Upsert(vinfo) return r } @@ -133,6 +99,7 @@ func (o Debian) convertToModel(def *ovalmodels.Definition) *models.CveContent { CveID: def.Debian.CveID, Title: def.Title, Summary: def.Description, + Severity: def.Advisory.Severity, References: refs, } } diff --git a/oval/redhat.go b/oval/redhat.go index 9a0e1abd..da0ff9fb 100644 --- a/oval/redhat.go +++ b/oval/redhat.go @@ -2,6 +2,8 @@ package oval import ( "fmt" + "strconv" + "strings" "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/models" @@ -55,76 +57,26 @@ func (o Redhat) FillCveInfoFromOvalDB(r *models.ScanResult) (*models.ScanResult, } func (o Redhat) fillOvalInfo(r *models.ScanResult, definition *ovalmodels.Definition) *models.ScanResult { - cveIDSet := make(map[string]bool) - cveID2VulnInfo := make(map[string]models.VulnInfo) for _, cve := range definition.Advisory.Cves { - cveIDSet[cve.CveID] = false - cveID2VulnInfo[cve.CveID] = models.VulnInfo{ - CveID: cve.CveID, - Confidence: models.OvalMatch, - Packages: getPackageInfoList(r, definition), - } - } - - // Update ScannedCves by OVAL info - updatedCves := []models.VulnInfo{} - for _, scanned := range r.ScannedCves { - // Update scanned confidence to ovalmatch - for _, c := range definition.Advisory.Cves { - if scanned.CveID == c.CveID { - cveIDSet[c.CveID] = true - if scanned.Confidence.Score < models.OvalMatch.Score { - scanned.Confidence = models.OvalMatch - } - break - } - } - updatedCves = append(updatedCves, scanned) - } - - for cveID, found := range cveIDSet { - if !found { - util.Log.Debugf("%s is newly detected by OVAL", cveID) - updatedCves = append(updatedCves, cveID2VulnInfo[cveID]) - } - } - r.ScannedCves = updatedCves - - // Update KnownCves by OVAL info - for _, c := range definition.Advisory.Cves { - ovalContent := *o.convertToModel(c.CveID, definition) - cInfo, ok := r.KnownCves.Get(c.CveID) + ovalContent := *o.convertToModel(cve.CveID, definition) + vinfo, ok := r.ScannedCves.Get(cve.CveID) if !ok { - cInfo.VulnInfo = cveID2VulnInfo[c.CveID] - cInfo.CveContents = []models.CveContent{ovalContent} - } - if !cInfo.Update(ovalContent) { - cInfo.Insert(ovalContent) - } - 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 { - cInfo, ok := r.UnknownCves.Get(c.CveID) - if ok { - r.UnknownCves.Delete(c.CveID) - - // Insert new CveInfo - ovalContent := *o.convertToModel(c.CveID, definition) - if !cInfo.Update(ovalContent) { - cInfo.Insert(ovalContent) + util.Log.Infof("%s is newly detected by OVAL", + definition.Debian.CveID) + vinfo = models.VulnInfo{ + CveID: cve.CveID, + Confidence: models.OvalMatch, + Packages: getPackageInfoList(r, definition), + CveContents: []models.CveContent{ovalContent}, } - if cInfo.VulnInfo.Confidence.Score < models.OvalMatch.Score { - cInfo.Confidence = models.OvalMatch + } else { + if vinfo.Confidence.Score < models.OvalMatch.Score { + vinfo.Confidence = models.OvalMatch } - r.KnownCves.Upsert(cInfo) + vinfo.CveContents.Upsert(ovalContent) } + r.ScannedCves.Upsert(vinfo) } - return r } @@ -134,7 +86,6 @@ func (o Redhat) convertToModel(cveID string, def *ovalmodels.Definition) *models continue } var refs []models.Reference - //TODO RHSAのリンクを入れる for _, r := range def.References { refs = append(refs, models.Reference{ Link: r.RefURL, @@ -143,20 +94,52 @@ func (o Redhat) convertToModel(cveID string, def *ovalmodels.Definition) *models }) } - // util.ParseCvss2() + score2, vec2 := o.parseCvss2(cve.Cvss2) + score3, vec3 := o.parseCvss3(cve.Cvss3) 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, + Type: models.RedHat, + CveID: cve.CveID, + Title: def.Title, + Summary: def.Description, + Severity: def.Advisory.Severity, + Cvss2Score: score2, + Cvss2Vector: vec2, + Cvss3Score: score3, + Cvss3Vector: vec3, + References: refs, + CweID: cve.Cwe, + Published: def.Advisory.Issued, + LastModified: def.Advisory.Updated, } } 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 Redhat) 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 (o Redhat) 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, "" +} diff --git a/oval/redhat_test.go b/oval/redhat_test.go new file mode 100644 index 00000000..c9b57dc8 --- /dev/null +++ b/oval/redhat_test.go @@ -0,0 +1,69 @@ +package oval + +import "testing" + +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 := Redhat{}.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 := Redhat{}.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) + } + } +} diff --git a/report/azureblob.go b/report/azureblob.go index e8ac3578..2220e9c1 100644 --- a/report/azureblob.go +++ b/report/azureblob.go @@ -139,13 +139,9 @@ func createBlockBlob(cli storage.BlobStorageClient, k string, b []byte) error { k = k + ".gz" } - if err := cli.CreateBlockBlobFromReader( - c.Conf.AzureContainer, - k, - uint64(len(b)), - bytes.NewReader(b), - map[string]string{}, - ); err != nil { + ref := cli.GetContainerReference(c.Conf.AzureContainer) + blob := ref.GetBlobReference(k) + if err := blob.CreateBlockBlobFromReader(bytes.NewReader(b), nil); err != nil { return fmt.Errorf("Failed to upload data to %s/%s, %s", c.Conf.AzureContainer, k, err) } diff --git a/report/email.go b/report/email.go index 48d7449c..8dd3a941 100644 --- a/report/email.go +++ b/report/email.go @@ -41,8 +41,8 @@ func (w EMailWriter) Write(rs ...models.ScanResult) (err error) { for _, r := range rs { if conf.FormatOneEMail { message += formatFullPlainText(r) + "\r\n\r\n" - totalResult.KnownCves = append(totalResult.KnownCves, r.KnownCves...) - totalResult.UnknownCves = append(totalResult.UnknownCves, r.UnknownCves...) + // totalResult.KnownCves = append(totalResult.KnownCves, r.KnownCves...) + // totalResult.UnknownCves = append(totalResult.UnknownCves, r.UnknownCves...) } else { var subject string if len(r.Errors) != 0 { diff --git a/report/slack.go b/report/slack.go index 3b9c9b74..c1c6733c 100644 --- a/report/slack.go +++ b/report/slack.go @@ -21,7 +21,6 @@ import ( "encoding/json" "fmt" "sort" - "strings" "time" log "github.com/Sirupsen/logrus" @@ -67,11 +66,12 @@ func (w SlackWriter) Write(rs ...models.ScanResult) error { } if 0 < len(r.Errors) { - serverInfo := fmt.Sprintf("*%s*", r.ServerInfo()) - notifyUsers := getNotifyUsers(config.Conf.Slack.NotifyUsers) - txt := fmt.Sprintf("%s\n%s\nError: %s", notifyUsers, serverInfo, r.Errors) + //TODO + // serverInfo := fmt.Sprintf("*%s*", r.ServerInfo()) + // notifyUsers := getNotifyUsers(config.Conf.Slack.NotifyUsers) + // txt := fmt.Sprintf("%s\n%s\nError: %s", notifyUsers, serverInfo, r.Errors) msg := message{ - Text: txt, + // Text: txt, Username: conf.AuthUser, IconEmoji: conf.IconEmoji, Channel: channel, @@ -152,57 +152,57 @@ func send(msg message) error { func msgText(r models.ScanResult) string { notifyUsers := "" - if 0 < len(r.KnownCves) || 0 < len(r.UnknownCves) { - notifyUsers = getNotifyUsers(config.Conf.Slack.NotifyUsers) - } + // if 0 < len(r.KnownCves) || 0 < len(r.UnknownCves) { + // notifyUsers = getNotifyUsers(config.Conf.Slack.NotifyUsers) + // } serverInfo := fmt.Sprintf("*%s*", r.ServerInfo()) return fmt.Sprintf("%s\n%s\n>%s", notifyUsers, serverInfo, r.CveSummary()) } func toSlackAttachments(scanResult models.ScanResult) (attaches []*attachment) { - cves := scanResult.KnownCves - if !config.Conf.IgnoreUnscoredCves { - cves = append(cves, scanResult.UnknownCves...) - } + // cves := scanResult.KnownCves + // if !config.Conf.IgnoreUnscoredCves { + // cves = append(cves, scanResult.UnknownCves...) + // } - for _, cveInfo := range cves { - cveID := cveInfo.VulnInfo.CveID + // for _, cveInfo := range cves { + // cveID := cveInfo.VulnInfo.CveID - curentPackages := []string{} - for _, p := range cveInfo.Packages { - curentPackages = append(curentPackages, p.FormatCurrentVer()) - } - for _, n := range cveInfo.CpeNames { - curentPackages = append(curentPackages, n) - } + // curentPackages := []string{} + // for _, p := range cveInfo.Packages { + // curentPackages = append(curentPackages, p.FormatCurrentVer()) + // } + // for _, n := range cveInfo.CpeNames { + // curentPackages = append(curentPackages, n) + // } - newPackages := []string{} - for _, p := range cveInfo.Packages { - newPackages = append(newPackages, p.FormatNewVer()) - } + // newPackages := []string{} + // for _, p := range cveInfo.Packages { + // newPackages = append(newPackages, p.FormatNewVer()) + // } - a := attachment{ - Title: cveID, - TitleLink: fmt.Sprintf("%s/%s", nvdBaseURL, cveID), - Text: attachmentText(cveInfo, scanResult.Family), - MrkdwnIn: []string{"text", "pretext"}, - Fields: []*field{ - { - // Title: "Current Package/CPE", - Title: "Installed", - Value: strings.Join(curentPackages, "\n"), - Short: true, - }, - { - Title: "Candidate", - Value: strings.Join(newPackages, "\n"), - Short: true, - }, - }, - Color: color(cveInfo.CvssV2Score()), - } - attaches = append(attaches, &a) - } + // a := attachment{ + // Title: cveID, + // TitleLink: fmt.Sprintf("%s/%s", nvdBaseURL, cveID), + // Text: attachmentText(cveInfo, scanResult.Family), + // MrkdwnIn: []string{"text", "pretext"}, + // Fields: []*field{ + // { + // // Title: "Current Package/CPE", + // Title: "Installed", + // Value: strings.Join(curentPackages, "\n"), + // Short: true, + // }, + // { + // Title: "Candidate", + // Value: strings.Join(newPackages, "\n"), + // Short: true, + // }, + // }, + // Color: color(cveInfo.CvssV2Score()), + // } + // attaches = append(attaches, &a) + // } return } @@ -220,80 +220,80 @@ func color(cvssScore float64) string { } } -func attachmentText(cveInfo models.CveInfo, osFamily string) string { - // linkText := links(cveInfo, osFamily) - //TODO - return "" - // switch { - // case config.Conf.Lang == "ja" && - // 0 < cveInfo.CveDetail.Jvn.CvssScore(): +// func attachmentText(cveInfo models.CveInfo, osFamily string) string { +// 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{} +// func links(cveInfo models.CveInfo, osFamily string) string { +// links := []string{} - //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)) - // } - // } +// //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.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, - fmt.Sprintf("<%s|%s>", link.url, link.title)) - } - links = append(links, fmt.Sprintf("<%s|MITRE>", - fmt.Sprintf("%s%s", mitreBaseURL, cveID))) - links = append(links, fmt.Sprintf("<%s|CVEDetails>", - fmt.Sprintf("%s/%s", cveDetailsBaseURL, cveID))) +// 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, +// fmt.Sprintf("<%s|%s>", link.url, link.title)) +// } +// links = append(links, fmt.Sprintf("<%s|MITRE>", +// fmt.Sprintf("%s%s", mitreBaseURL, cveID))) +// links = append(links, fmt.Sprintf("<%s|CVEDetails>", +// fmt.Sprintf("%s/%s", cveDetailsBaseURL, cveID))) - return strings.Join(links, " / ") -} +// return strings.Join(links, " / ") +// } -// See testcase -func getNotifyUsers(notifyUsers []string) string { - slackStyleTexts := []string{} - for _, username := range notifyUsers { - slackStyleTexts = append(slackStyleTexts, fmt.Sprintf("<%s>", username)) - } - return strings.Join(slackStyleTexts, " ") -} +// // See testcase +// func getNotifyUsers(notifyUsers []string) string { +// slackStyleTexts := []string{} +// for _, username := range notifyUsers { +// slackStyleTexts = append(slackStyleTexts, fmt.Sprintf("<%s>", username)) +// } +// return strings.Join(slackStyleTexts, " ") +// } diff --git a/report/tui.go b/report/tui.go index 74ab3cf2..2a3c8fdc 100644 --- a/report/tui.go +++ b/report/tui.go @@ -22,7 +22,6 @@ import ( "fmt" "os" "strings" - "text/template" "time" log "github.com/Sirupsen/logrus" @@ -221,7 +220,8 @@ func movable(v *gocui.View, nextY int) (ok bool, yLimit int) { } return true, yLimit case "summary": - yLimit = len(currentScanResult.AllCves()) - 1 + //TODO + // yLimit = len(currentScanResult.AllCves()) - 1 if yLimit < nextY { return false, yLimit } @@ -601,71 +601,72 @@ func summaryLines() string { return "Error: Scan with --debug to view the details" } - indexFormat := "" - if len(currentScanResult.AllCves()) < 10 { - indexFormat = "[%1d]" - } else if len(currentScanResult.AllCves()) < 100 { - indexFormat = "[%2d]" - } else { - indexFormat = "[%3d]" - } + //TODO + // indexFormat := "" + // if len(currentScanResult.AllCves()) < 10 { + // indexFormat = "[%1d]" + // } else if len(currentScanResult.AllCves()) < 100 { + // indexFormat = "[%2d]" + // } else { + // indexFormat = "[%3d]" + // } - for i, d := range currentScanResult.AllCves() { - var cols []string - //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() + // for i, d := range currentScanResult.AllCves() { + // var cols []string + // //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)) - // } + // // 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, - // } - // } + // // 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 { - icols[j] = cols[j] - } - stable.AddRow(icols...) - } + // icols := make([]interface{}, len(cols)) + // for j := range cols { + // icols[j] = cols[j] + // } + // stable.AddRow(icols...) + // } return fmt.Sprintf("%s", stable) } @@ -712,19 +713,21 @@ func setChangelogLayout(g *gocui.Gui) error { if err != gocui.ErrUnknownView { return err } - if len(currentScanResult.Errors) != 0 || len(currentScanResult.AllCves()) == 0 { - return nil - } + //TODO + // if len(currentScanResult.Errors) != 0 || len(currentScanResult.AllCves()) == 0 { + // return nil + // } lines := []string{} - cveInfo := currentScanResult.AllCves()[currentCveInfo] - for _, pack := range cveInfo.Packages { - for _, p := range currentScanResult.Packages { - if pack.Name == p.Name { - lines = append(lines, formatOneChangelog(p), "\n") - } - } - } + //TODO + // cveInfo := currentScanResult.AllCves()[currentCveInfo] + // for _, pack := range cveInfo.Packages { + // for _, p := range currentScanResult.Packages { + // if pack.Name == p.Name { + // lines = append(lines, formatOneChangelog(p), "\n") + // } + // } + // } text := strings.Join(lines, "\n") fmt.Fprint(v, text) v.Editable = false @@ -756,20 +759,20 @@ func detailLines() (string, error) { return "", nil } - if len(currentScanResult.AllCves()) == 0 { - return "No vulnerable packages", nil - } + //TODO + // if len(currentScanResult.AllCves()) == 0 { + // return "No vulnerable packages", nil + // } + // cveInfo := currentScanResult.AllCves()[currentCveInfo] + // cveID := cveInfo.VulnInfo.CveID - cveInfo := currentScanResult.AllCves()[currentCveInfo] - cveID := cveInfo.VulnInfo.CveID + // tmpl, err := template.New("detail").Parse(detailTemplate()) + // if err != nil { + // return "", err + // } - tmpl, err := template.New("detail").Parse(detailTemplate()) - if err != nil { - return "", err - } - - var cvssSeverity, cvssVector, summary string - var refs []cve.Reference + // var cvssSeverity, cvssVector, summary string + // var refs []cve.Reference switch { //TODO // case config.Conf.Lang == "ja" && @@ -780,67 +783,67 @@ func detailLines() (string, error) { // summary = fmt.Sprintf("%s\n%s", jvn.CveTitle(), jvn.CveSummary()) // refs = jvn.VulnSiteReferences() default: - var nvd *models.CveContent - if cont, found := cveInfo.Get(models.NVD); found { - nvd = cont - } + // var nvd *models.CveContent + //TODO + // if cont, found := cveInfo.Get(models.NVD); found { + // nvd = cont + // } // cvssSeverity = nvd.CvssSeverity() // cvssVector = nvd.CvssVector() - summary = nvd.Summary + // summary = nvd.Summary // refs = nvd.VulnSiteReferences() } //TODO // cweURL := cweURL(cveInfo.CveDetail.CweID()) - - links := []string{ - fmt.Sprintf("[NVD]( %s )", fmt.Sprintf("%s/%s", nvdBaseURL, cveID)), - fmt.Sprintf("[MITRE]( %s )", fmt.Sprintf("%s%s", mitreBaseURL, cveID)), - fmt.Sprintf("[CveDetais]( %s )", fmt.Sprintf("%s/%s", cveDetailsBaseURL, cveID)), - fmt.Sprintf("[CVSSv2 Calc]( %s )", fmt.Sprintf(cvssV2CalcBaseURL, cveID)), - fmt.Sprintf("[CVSSv3 Calc]( %s )", fmt.Sprintf(cvssV3CalcBaseURL, cveID)), - } - dlinks := distroLinks(cveInfo, currentScanResult.Family) - for _, link := range dlinks { - links = append(links, fmt.Sprintf("[%s]( %s )", link.title, link.url)) - } + // links := []string{ + // fmt.Sprintf("[NVD]( %s )", fmt.Sprintf("%s/%s", nvdBaseURL, cveID)), + // fmt.Sprintf("[MITRE]( %s )", fmt.Sprintf("%s%s", mitreBaseURL, cveID)), + // fmt.Sprintf("[CveDetais]( %s )", fmt.Sprintf("%s/%s", cveDetailsBaseURL, cveID)), + // fmt.Sprintf("[CVSSv2 Calc]( %s )", fmt.Sprintf(cvssV2CalcBaseURL, cveID)), + // fmt.Sprintf("[CVSSv3 Calc]( %s )", fmt.Sprintf(cvssV3CalcBaseURL, cveID)), + // } + // dlinks := distroLinks(cveInfo, currentScanResult.Family) + // for _, link := range dlinks { + // links = append(links, fmt.Sprintf("[%s]( %s )", link.title, link.url)) + // } //TODO - var cvssScore string - if cveInfo.CvssV2Score() == -1 { - cvssScore = "?" - // } else { - // cvssScore = fmt.Sprintf("%4.1f", cveInfo.CveDetail.CvssScore(config.Conf.Lang)) - } + // var cvssScore string + // if cveInfo.CvssV2Score() == -1 { + // cvssScore = "?" + // // } else { + // // cvssScore = fmt.Sprintf("%4.1f", cveInfo.CveDetail.CvssScore(config.Conf.Lang)) + // } - packages := []string{} - for _, pack := range cveInfo.Packages { - packages = append(packages, - fmt.Sprintf( - "%s -> %s", - pack.FormatCurrentVer(), - pack.FormatNewVer())) - } + // packages := []string{} + // for _, pack := range cveInfo.Packages { + // packages = append(packages, + // fmt.Sprintf( + // "%s -> %s", + // pack.FormatCurrentVer(), + // pack.FormatNewVer())) + // } - data := dataForTmpl{ - CveID: cveID, - CvssScore: cvssScore, - CvssSeverity: cvssSeverity, - CvssVector: cvssVector, - Summary: summary, - Confidence: cveInfo.VulnInfo.Confidence, - //TODO - // CweURL: cweURL, - VulnSiteLinks: links, - References: refs, - Packages: packages, - CpeNames: cveInfo.CpeNames, - } + // data := dataForTmpl{ + // CveID: cveID, + // CvssScore: cvssScore, + // CvssSeverity: cvssSeverity, + // CvssVector: cvssVector, + // Summary: summary, + // Confidence: cveInfo.VulnInfo.Confidence, + // //TODO + // // CweURL: cweURL, + // VulnSiteLinks: links, + // References: refs, + // Packages: packages, + // CpeNames: cveInfo.CpeNames, + // } buf := bytes.NewBuffer(nil) // create empty buffer - if err := tmpl.Execute(buf, data); err != nil { - return "", err - } + // if err := tmpl.Execute(buf, data); err != nil { + // return "", err + // } return string(buf.Bytes()), nil } diff --git a/report/util.go b/report/util.go index e7b6420d..e813e676 100644 --- a/report/util.go +++ b/report/util.go @@ -22,7 +22,6 @@ import ( "fmt" "strings" - "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/models" "github.com/gosuri/uitable" ) @@ -84,10 +83,11 @@ func formatShortPlainText(r models.ScanResult) string { stable.MaxColWidth = maxColWidth stable.Wrap = true - cves := r.KnownCves - if !config.Conf.IgnoreUnscoredCves { - cves = append(cves, r.UnknownCves...) - } + //TODO + // cves := r.KnownCves + // if !config.Conf.IgnoreUnscoredCves { + // cves = append(cves, r.UnknownCves...) + // } var buf bytes.Buffer for i := 0; i < len(r.ServerInfo()); i++ { @@ -106,83 +106,84 @@ func formatShortPlainText(r models.ScanResult) string { header, r.Errors) } - if len(cves) == 0 { - return fmt.Sprintf(` -%s -No CVE-IDs are found in updatable packages. -%s -`, header, r.Packages.FormatUpdatablePacksSummary()) - } + //TODO + // if len(cves) == 0 { + // return fmt.Sprintf(` + // %s + // No CVE-IDs are found in updatable packages. + // %s + // `, header, r.Packages.FormatUpdatablePacksSummary()) + // } - for _, d := range cves { - var packsVer string - for _, p := range d.Packages { - packsVer += fmt.Sprintf( - "%s -> %s\n", p.FormatCurrentVer(), p.FormatNewVer()) - } - for _, n := range d.CpeNames { - packsVer += n - } + // for _, d := range cves { + // var packsVer string + // for _, p := range d.Packages { + // packsVer += fmt.Sprintf( + // "%s -> %s\n", p.FormatCurrentVer(), p.FormatNewVer()) + // } + // for _, n := range d.CpeNames { + // packsVer += n + // } - var scols []string - switch { - // 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, - // } + // var scols []string + // switch { + // // 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.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", - nvd.Summary, - cveDetailsBaseURL, - d.VulnInfo.CveID, - distroLinks(d, r.Family)[0].url, - packsVer, - d.VulnInfo.Confidence, - ) - scols = []string{ - d.VulnInfo.CveID, - fmt.Sprintf("%-4.1f (%s)", - d.CvssV2Score(), - "TODO", - ), - summary, - } - default: - summary := fmt.Sprintf("%s\n%sConfidence: %v", - distroLinks(d, r.Family)[0].url, packsVer, d.VulnInfo.Confidence) - scols = []string{ - d.VulnInfo.CveID, - "?", - summary, - } - } + // 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", + // nvd.Summary, + // cveDetailsBaseURL, + // d.VulnInfo.CveID, + // distroLinks(d, r.Family)[0].url, + // packsVer, + // d.VulnInfo.Confidence, + // ) + // scols = []string{ + // d.VulnInfo.CveID, + // fmt.Sprintf("%-4.1f (%s)", + // d.CvssV2Score(), + // "TODO", + // ), + // summary, + // } + // default: + // summary := fmt.Sprintf("%s\n%sConfidence: %v", + // distroLinks(d, r.Family)[0].url, packsVer, d.VulnInfo.Confidence) + // scols = []string{ + // d.VulnInfo.CveID, + // "?", + // summary, + // } + // } - cols := make([]interface{}, len(scols)) - for i := range cols { - cols[i] = scols[i] - } - stable.AddRow(cols...) - stable.AddRow("") - } + // cols := make([]interface{}, len(scols)) + // for i := range cols { + // cols[i] = scols[i] + // } + // stable.AddRow(cols...) + // stable.AddRow("") + // } return fmt.Sprintf("%s\n%s\n", header, stable) } @@ -206,32 +207,34 @@ func formatFullPlainText(r models.ScanResult) string { header, r.Errors) } - if len(r.KnownCves) == 0 && len(r.UnknownCves) == 0 { - return fmt.Sprintf(` -%s -No CVE-IDs are found in updatable packages. -%s -`, header, r.Packages.FormatUpdatablePacksSummary()) - } + //TODO + // if len(r.KnownCves) == 0 && len(r.UnknownCves) == 0 { + // return fmt.Sprintf(` + // %s + // No CVE-IDs are found in updatable packages. + // %s + // `, header, r.Packages.FormatUpdatablePacksSummary()) + // } - scoredReport, unscoredReport := []string{}, []string{} - scoredReport, unscoredReport = formatPlainTextDetails(r, r.Family) + // scoredReport, unscoredReport := []string{}, []string{} + // scoredReport, unscoredReport = formatPlainTextDetails(r, r.Family) - unscored := "" - if !config.Conf.IgnoreUnscoredCves { - unscored = strings.Join(unscoredReport, "\n\n") - } + // unscored := "" + // if !config.Conf.IgnoreUnscoredCves { + // unscored = strings.Join(unscoredReport, "\n\n") + // } - scored := strings.Join(scoredReport, "\n\n") - detail := fmt.Sprintf(` -%s + // scored := strings.Join(scoredReport, "\n\n") + // detail := fmt.Sprintf(` + // %s -%s -`, - scored, - unscored, - ) - return fmt.Sprintf("%s\n%s\n%s", header, detail, formatChangelogs(r)) + // %s + // `, + // scored, + // unscored, + // ) + // return fmt.Sprintf("%s\n%s\n%s", header, detail, formatChangelogs(r)) + return "" } //TODO @@ -266,116 +269,116 @@ func formatPlainTextDetails(r models.ScanResult, osFamily string) (scoredReport, return } -func formatPlainTextUnknownCve(cveInfo models.CveInfo, osFamily string) string { - cveID := cveInfo.VulnInfo.CveID - dtable := uitable.New() - dtable.MaxColWidth = maxColWidth - dtable.Wrap = true - dtable.AddRow(cveID) - dtable.AddRow("-------------") - dtable.AddRow("Score", "?") - dtable.AddRow("NVD", fmt.Sprintf("%s/%s", nvdBaseURL, cveID)) - dlinks := distroLinks(cveInfo, osFamily) - for _, link := range dlinks { - dtable.AddRow(link.title, link.url) - } - dtable.AddRow("CVE Details", fmt.Sprintf("%s/%s", cveDetailsBaseURL, cveID)) - dtable = addPackageInfos(dtable, cveInfo.Packages) - dtable = addCpeNames(dtable, cveInfo.CpeNames) - dtable.AddRow("Confidence", cveInfo.VulnInfo.Confidence) +// func formatPlainTextUnknownCve(cveInfo models.CveInfo, osFamily string) string { +// cveID := cveInfo.VulnInfo.CveID +// dtable := uitable.New() +// dtable.MaxColWidth = maxColWidth +// dtable.Wrap = true +// dtable.AddRow(cveID) +// dtable.AddRow("-------------") +// dtable.AddRow("Score", "?") +// dtable.AddRow("NVD", fmt.Sprintf("%s/%s", nvdBaseURL, cveID)) +// dlinks := distroLinks(cveInfo, osFamily) +// for _, link := range dlinks { +// dtable.AddRow(link.title, link.url) +// } +// dtable.AddRow("CVE Details", fmt.Sprintf("%s/%s", cveDetailsBaseURL, cveID)) +// 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 formatPlainTextDetailsLangJa(cveInfo models.CveInfo, osFamily string) string { - return "TODO" - // cveDetail := cveInfo.CveDetail - // cveID := cveDetail.CveID - // jvn := cveDetail.Jvn +// func formatPlainTextDetailsLangJa(cveInfo models.CveInfo, osFamily string) string { +// 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 { - return "" - // cveDetail := d.CveDetail - // cveID := cveDetail.CveID - // nvd := cveDetail.Nvd +// func formatPlainTextDetailsLangEn(d models.CveInfo, osFamily string) string { +// 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 { title string @@ -383,84 +386,84 @@ type distroLink struct { } // distroLinks add Vendor URL of the CVE to table -func distroLinks(cveInfo models.CveInfo, osFamily string) []distroLink { - cveID := cveInfo.VulnInfo.CveID - switch osFamily { - case "rhel", "centos": - links := []distroLink{ - { - "RHEL-CVE", - fmt.Sprintf("%s/%s", redhatSecurityBaseURL, cveID), - }, - } - for _, advisory := range cveInfo.DistroAdvisories { - aidURL := strings.Replace(advisory.AdvisoryID, ":", "-", -1) - links = append(links, distroLink{ - // "RHEL-errata", - advisory.AdvisoryID, - fmt.Sprintf(redhatRHSABaseBaseURL, aidURL), - }) - } - return links - case "oraclelinux": - links := []distroLink{ - { - "Oracle-CVE", - fmt.Sprintf(oracleSecurityBaseURL, cveID), - }, - } - for _, advisory := range cveInfo.DistroAdvisories { - links = append(links, distroLink{ - // "Oracle-ELSA" - advisory.AdvisoryID, - fmt.Sprintf(oracleELSABaseBaseURL, advisory.AdvisoryID), - }) - } - return links - case "amazon": - links := []distroLink{ - { - "RHEL-CVE", - fmt.Sprintf("%s/%s", redhatSecurityBaseURL, cveID), - }, - } - for _, advisory := range cveInfo.DistroAdvisories { - links = append(links, distroLink{ - // "Amazon-ALAS", - advisory.AdvisoryID, - fmt.Sprintf(amazonSecurityBaseURL, advisory.AdvisoryID), - }) - } - return links - case "ubuntu": - return []distroLink{ - { - "Ubuntu-CVE", - fmt.Sprintf("%s/%s", ubuntuSecurityBaseURL, cveID), - }, - //TODO Ubuntu USN - } - case "debian": - return []distroLink{ - { - "Debian-CVE", - fmt.Sprintf("%s/%s", debianTrackerBaseURL, cveID), - }, - // TODO Debian dsa - } - case "FreeBSD": - links := []distroLink{} - for _, advisory := range cveInfo.DistroAdvisories { - links = append(links, distroLink{ - "FreeBSD-VuXML", - fmt.Sprintf(freeBSDVuXMLBaseURL, advisory.AdvisoryID), - }) - } - return links - default: - return []distroLink{} - } -} +// func distroLinks(cveInfo models.CveInfo, osFamily string) []distroLink { +// cveID := cveInfo.VulnInfo.CveID +// switch osFamily { +// case "rhel", "centos": +// links := []distroLink{ +// { +// "RHEL-CVE", +// fmt.Sprintf("%s/%s", redhatSecurityBaseURL, cveID), +// }, +// } +// for _, advisory := range cveInfo.DistroAdvisories { +// aidURL := strings.Replace(advisory.AdvisoryID, ":", "-", -1) +// links = append(links, distroLink{ +// // "RHEL-errata", +// advisory.AdvisoryID, +// fmt.Sprintf(redhatRHSABaseBaseURL, aidURL), +// }) +// } +// return links +// case "oraclelinux": +// links := []distroLink{ +// { +// "Oracle-CVE", +// fmt.Sprintf(oracleSecurityBaseURL, cveID), +// }, +// } +// for _, advisory := range cveInfo.DistroAdvisories { +// links = append(links, distroLink{ +// // "Oracle-ELSA" +// advisory.AdvisoryID, +// fmt.Sprintf(oracleELSABaseBaseURL, advisory.AdvisoryID), +// }) +// } +// return links +// case "amazon": +// links := []distroLink{ +// { +// "RHEL-CVE", +// fmt.Sprintf("%s/%s", redhatSecurityBaseURL, cveID), +// }, +// } +// for _, advisory := range cveInfo.DistroAdvisories { +// links = append(links, distroLink{ +// // "Amazon-ALAS", +// advisory.AdvisoryID, +// fmt.Sprintf(amazonSecurityBaseURL, advisory.AdvisoryID), +// }) +// } +// return links +// case "ubuntu": +// return []distroLink{ +// { +// "Ubuntu-CVE", +// fmt.Sprintf("%s/%s", ubuntuSecurityBaseURL, cveID), +// }, +// //TODO Ubuntu USN +// } +// case "debian": +// return []distroLink{ +// { +// "Debian-CVE", +// fmt.Sprintf("%s/%s", debianTrackerBaseURL, cveID), +// }, +// // TODO Debian dsa +// } +// case "FreeBSD": +// links := []distroLink{} +// for _, advisory := range cveInfo.DistroAdvisories { +// links = append(links, distroLink{ +// "FreeBSD-VuXML", +// fmt.Sprintf(freeBSDVuXMLBaseURL, advisory.AdvisoryID), +// }) +// } +// return links +// default: +// return []distroLink{} +// } +// } // addPackageInfos add package information related the CVE to table func addPackageInfos(table *uitable.Table, packs []models.PackageInfo) *uitable.Table { diff --git a/scan/base.go b/scan/base.go index 99c4eb40..98e6a3d8 100644 --- a/scan/base.go +++ b/scan/base.go @@ -267,9 +267,11 @@ func (l base) isAwsInstanceID(str string) bool { func (l *base) convertToModel() models.ScanResult { for _, p := range l.VulnInfos { + //TODO sort.Sort(models.PackageInfosByName(p.Packages)) } - sort.Sort(l.VulnInfos) + //TODO + // sort.Sort(l.VulnInfos) ctype := l.ServerInfo.Containers.Type if l.ServerInfo.Container.ContainerID != "" && ctype == "" { diff --git a/util/util.go b/util/util.go index c022c87d..3b94e8a6 100644 --- a/util/util.go +++ b/util/util.go @@ -20,7 +20,6 @@ package util import ( "fmt" "net/url" - "strconv" "strings" "github.com/future-architect/vuls/config" @@ -136,31 +135,3 @@ 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, "" -} diff --git a/util/util_test.go b/util/util_test.go index 19ce9f92..49340a3d 100644 --- a/util/util_test.go +++ b/util/util_test.go @@ -171,69 +171,3 @@ 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) - } - } -}