From 6e82981ee3be74953886e7c4348a1d989132c2dd Mon Sep 17 00:00:00 2001 From: Kota Kanbe Date: Fri, 30 Nov 2018 15:41:59 +0900 Subject: [PATCH] feat(report): Display CERT information to reports (#741) * fix(tui): show JPCERT Alert URL in TUI * feat(tui): show `!` when the CVE-ID corresponds to USCERT or JPCERT alert * feat(report): display cert alert info to stdout report * fix(report): Display CVEs detected by CPEs with -ignore-unfixed flag --- models/scanresults.go | 6 +++++- models/vulninfos.go | 20 +++++++++++++++++++- report/tui.go | 35 ++++++++++++++--------------------- report/util.go | 11 +++++++++-- 4 files changed, 47 insertions(+), 25 deletions(-) diff --git a/models/scanresults.go b/models/scanresults.go index 1f4fbb5e..7e91c680 100644 --- a/models/scanresults.go +++ b/models/scanresults.go @@ -20,11 +20,12 @@ package models import ( "bytes" "fmt" - "github.com/future-architect/vuls/alert" "regexp" "strings" "time" + "github.com/future-architect/vuls/alert" + "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/cwe" "github.com/future-architect/vuls/util" @@ -189,6 +190,9 @@ func (r ScanResult) FilterUnfixed() ScanResult { return r } filtered := r.ScannedCves.Find(func(v VulnInfo) bool { + if len(v.CpeURIs) != 0 { + return true + } NotFixedAll := true for _, p := range v.AffectedPackages { NotFixedAll = NotFixedAll && p.NotFixedYet diff --git a/models/vulninfos.go b/models/vulninfos.go index 837eae1a..1817544d 100644 --- a/models/vulninfos.go +++ b/models/vulninfos.go @@ -20,11 +20,12 @@ package models import ( "bytes" "fmt" - "github.com/future-architect/vuls/alert" "sort" "strings" "time" + "github.com/future-architect/vuls/alert" + "github.com/future-architect/vuls/config" exploitmodels "github.com/mozqnet/go-exploitdb/models" ) @@ -694,6 +695,23 @@ type AlertDict struct { En []alert.Alert } +// HasAlert returns whether or not it has En or Ja entries. +func (a AlertDict) HasAlert() bool { + return len(a.En) != 0 || len(a.Ja) != 0 +} + +// FormatSource returns which source has this alert +func (a AlertDict) FormatSource() string { + s := []string{} + if len(a.En) != 0 { + s = append(s, "USCERT") + } + if len(a.Ja) != 0 { + s = append(s, "JPCERT") + } + return strings.Join(s, "/") +} + // Confidences is a list of Confidence type Confidences []Confidence diff --git a/report/tui.go b/report/tui.go index 6bbac3bd..10e496e6 100644 --- a/report/tui.go +++ b/report/tui.go @@ -20,13 +20,14 @@ package report import ( "bytes" "fmt" - "github.com/future-architect/vuls/alert" "os" "sort" "strings" "text/template" "time" + "github.com/future-architect/vuls/alert" + "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/models" "github.com/future-architect/vuls/util" @@ -636,10 +637,15 @@ func summaryLines(r models.ScanResult) string { packname := vinfo.AffectedPackages.FormatTuiSummary() packname += strings.Join(vinfo.CpeURIs, ", ") + alert := " " + if vinfo.AlertDict.HasAlert() { + alert = "! " + } + var cols []string cols = []string{ fmt.Sprintf(indexFormat, i+1), - vinfo.CveID, + alert + vinfo.CveID, cvssScore + " |", fmt.Sprintf("%8s |", vinfo.AttackVector()), fmt.Sprintf("%7s |", vinfo.PatchStatus(r.Packages)), @@ -764,13 +770,17 @@ func setChangelogLayout(g *gocui.Gui) error { } } - if config.Conf.Lang == "ja" && len(vinfo.AlertDict.Ja) > 0 { + if len(vinfo.AlertDict.Ja) > 0 { lines = append(lines, "\n", "JPCERT Alert", "=============", ) for _, alert := range vinfo.AlertDict.Ja { - lines = append(lines, fmt.Sprintf("* [%s](%s)", alert.Title, alert.URL)) + if config.Conf.Lang == "ja" { + lines = append(lines, fmt.Sprintf("* [%s](%s)", alert.Title, alert.URL)) + } else { + lines = append(lines, fmt.Sprintf("* [JPCERT](%s)", alert.URL)) + } } } @@ -884,17 +894,6 @@ func detailLines() (string, error) { } } - alerts := []alert.Alert{} - for _, alert := range vinfo.AlertDict.En { - alerts = append(alerts, alert) - } - // Only show JPCERT alert to Japanese users - if config.Conf.Lang == "ja" { - for _, alert := range vinfo.AlertDict.Ja { - alerts = append(alerts, alert) - } - } - data := dataForTmpl{ CveID: vinfo.CveID, Cvsses: fmt.Sprintf("%s\n", table), @@ -902,7 +901,6 @@ func detailLines() (string, error) { Mitigation: fmt.Sprintf("%s (%s)", mitigation.Value, mitigation.Type), Confidences: vinfo.Confidences, Cwes: cwes, - Alerts: alerts, Links: util.Distinct(links), References: refs, } @@ -949,11 +947,6 @@ Confidence {{range $confidence := .Confidences -}} * {{$confidence.DetectionMethod}} {{end}} -Alerts ------------ -{{range .Alerts -}} -* [{{.Title}}]({{.URL}}) -{{end}} References ----------- {{range .References -}} diff --git a/report/util.go b/report/util.go index 27315eb6..84587916 100644 --- a/report/util.go +++ b/report/util.go @@ -50,7 +50,6 @@ func formatScanSummary(rs ...models.ScanResult) string { r.FormatServerName(), fmt.Sprintf("%s%s", r.Family, r.Release), r.FormatUpdatablePacksSummary(), - r.FormatExploitCveSummary(), } } else { cols = []interface{}{ @@ -78,6 +77,7 @@ func formatOneLineSummary(rs ...models.ScanResult) string { r.ScannedCves.FormatFixedStatus(r.Packages), r.FormatUpdatablePacksSummary(), r.FormatExploitCveSummary(), + r.FormatAlertSummary(), } } else { cols = []interface{}{ @@ -116,8 +116,14 @@ No CVE-IDs are found in updatable packages. // packname := vinfo.AffectedPackages.FormatTuiSummary() // packname += strings.Join(vinfo.CpeURIs, ", ") + exploits := "" + if 0 < len(vinfo.Exploits) { + exploits = " Y" + } + data = append(data, []string{ vinfo.CveID, + vinfo.AlertDict.FormatSource(), fmt.Sprintf("%4.1f", max), // fmt.Sprintf("%4.1f", v2max), // fmt.Sprintf("%4.1f", v3max), @@ -125,7 +131,7 @@ No CVE-IDs are found in updatable packages. fmt.Sprintf("%7s", vinfo.PatchStatus(r.Packages)), // packname, fmt.Sprintf("https://nvd.nist.gov/vuln/detail/%s", vinfo.CveID), - fmt.Sprintf("%t", 0 < len(vinfo.Exploits)), + exploits, }) } @@ -133,6 +139,7 @@ No CVE-IDs are found in updatable packages. table := tablewriter.NewWriter(&b) table.SetHeader([]string{ "CVE-ID", + "CERT", "CVSS", // "v3", // "v2",