feat(report): Add NVD as a source for mitigations, primarySrc URL and Patch URL (#1097)
* feat(report): Add NVD as a src for mitigations. * feat(report): display "Vendor Advisory" URL in NVD * feat(report): display patch urls in report, tui
This commit is contained in:
@@ -184,6 +184,9 @@ func DetectPkgCves(dbclient DBClient, r *models.ScanResult) error {
|
||||
}
|
||||
|
||||
// To keep backward compatibility
|
||||
// Newer versions use ListenPortStats,
|
||||
// but older versions of Vuls are set to ListenPorts.
|
||||
// Set ListenPorts to ListenPortStats to allow newer Vuls to report old results.
|
||||
for i, pkg := range r.Packages {
|
||||
for j, proc := range pkg.AffectedProcs {
|
||||
for _, ipPort := range proc.ListenPorts {
|
||||
@@ -277,7 +280,7 @@ func FillCveInfo(dbclient DBClient, r *models.ScanResult) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// fillCvesWithNvdJvn fetches NVD, JVN from CVE Database
|
||||
// fillCvesWithNvdJvn fills CVE detail with NVD, JVN
|
||||
func fillCvesWithNvdJvn(driver cvedb.DB, r *models.ScanResult) error {
|
||||
cveIDs := []string{}
|
||||
for _, v := range r.ScannedCves {
|
||||
@@ -289,7 +292,7 @@ func fillCvesWithNvdJvn(driver cvedb.DB, r *models.ScanResult) error {
|
||||
return err
|
||||
}
|
||||
for _, d := range ds {
|
||||
nvd, exploits := models.ConvertNvdJSONToModel(d.CveID, d.NvdJSON)
|
||||
nvd, exploits, mitigations := models.ConvertNvdJSONToModel(d.CveID, d.NvdJSON)
|
||||
jvn := models.ConvertJvnToModel(d.CveID, d.Jvn)
|
||||
|
||||
alerts := fillCertAlerts(&d)
|
||||
@@ -305,6 +308,7 @@ func fillCvesWithNvdJvn(driver cvedb.DB, r *models.ScanResult) error {
|
||||
}
|
||||
vinfo.AlertDict = alerts
|
||||
vinfo.Exploits = append(vinfo.Exploits, exploits...)
|
||||
vinfo.Mitigations = append(vinfo.Mitigations, mitigations...)
|
||||
r.ScannedCves[cveID] = vinfo
|
||||
break
|
||||
}
|
||||
|
||||
@@ -277,9 +277,8 @@ func attachmentText(vinfo models.VulnInfo, osFamily string, cweDict map[string]m
|
||||
} else {
|
||||
if 0 < len(vinfo.DistroAdvisories) {
|
||||
links := []string{}
|
||||
for k, v := range vinfo.VendorLinks(osFamily) {
|
||||
links = append(links, fmt.Sprintf("<%s|%s>",
|
||||
v, k))
|
||||
for _, v := range vinfo.CveContents.PrimarySrcURLs(config.Conf.Lang, osFamily, vinfo.CveID) {
|
||||
links = append(links, fmt.Sprintf("<%s|%s>", v.Value, v.Type))
|
||||
}
|
||||
|
||||
v := fmt.Sprintf("<%s|%s> %s (%s)",
|
||||
@@ -303,9 +302,8 @@ func attachmentText(vinfo models.VulnInfo, osFamily string, cweDict map[string]m
|
||||
}
|
||||
|
||||
mitigation := ""
|
||||
if vinfo.Mitigations(osFamily)[0].Type != models.Unknown {
|
||||
mitigation = fmt.Sprintf("\nMitigation:\n```%s```\n",
|
||||
vinfo.Mitigations(osFamily)[0].Value)
|
||||
for _, m := range vinfo.Mitigations {
|
||||
mitigation = fmt.Sprintf("\nMitigation:\n<%s|%s>", m.URL, m.CveContentType)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("*%4.1f (%s)* %s %s\n%s\n```\n%s\n```%s\n%s\n",
|
||||
|
||||
@@ -866,6 +866,7 @@ type dataForTmpl struct {
|
||||
Metasploits []models.Metasploit
|
||||
Summary string
|
||||
Mitigation string
|
||||
PatchURLs []string
|
||||
Confidences models.Confidences
|
||||
Cwes []models.CweDictEntry
|
||||
Alerts []models.Alert
|
||||
@@ -894,14 +895,8 @@ func detailLines() (string, error) {
|
||||
|
||||
vinfo := vinfos[currentVinfo]
|
||||
links := []string{}
|
||||
if strings.HasPrefix(vinfo.CveID, "CVE-") {
|
||||
links = append(links, vinfo.CveContents.SourceLinks(
|
||||
config.Conf.Lang, r.Family, vinfo.CveID)[0].Value,
|
||||
vinfo.Cvss2CalcURL(),
|
||||
vinfo.Cvss3CalcURL())
|
||||
}
|
||||
for _, url := range vinfo.VendorLinks(r.Family) {
|
||||
links = append(links, url)
|
||||
for _, r := range vinfo.CveContents.PrimarySrcURLs(config.Conf.Lang, r.Family, vinfo.CveID) {
|
||||
links = append(links, r.Value)
|
||||
}
|
||||
|
||||
refsMap := map[string]models.Reference{}
|
||||
@@ -924,7 +919,20 @@ func detailLines() (string, error) {
|
||||
}
|
||||
|
||||
summary := vinfo.Summaries(r.Lang, r.Family)[0]
|
||||
mitigation := vinfo.Mitigations(r.Family)[0]
|
||||
|
||||
mitigations := []string{}
|
||||
for _, m := range vinfo.Mitigations {
|
||||
switch m.CveContentType {
|
||||
case models.RedHatAPI, models.Microsoft:
|
||||
mitigations = append(mitigations,
|
||||
fmt.Sprintf("%s (%s)", m.Mitigation, m.CveContentType))
|
||||
case models.Nvd:
|
||||
mitigations = append(mitigations,
|
||||
fmt.Sprintf("* %s (%s)", m.URL, m.CveContentType))
|
||||
default:
|
||||
util.Log.Errorf("Unknown CveContentType: %s", m)
|
||||
}
|
||||
}
|
||||
|
||||
table := uitable.New()
|
||||
table.MaxColWidth = maxColWidth
|
||||
@@ -962,7 +970,8 @@ func detailLines() (string, error) {
|
||||
CveID: vinfo.CveID,
|
||||
Cvsses: fmt.Sprintf("%s\n", table),
|
||||
Summary: fmt.Sprintf("%s (%s)", summary.Value, summary.Type),
|
||||
Mitigation: fmt.Sprintf("%s (%s)", mitigation.Value, mitigation.Type),
|
||||
Mitigation: strings.Join(mitigations, "\n"),
|
||||
PatchURLs: vinfo.CveContents.PatchURLs(),
|
||||
Confidences: vinfo.Confidences,
|
||||
Cwes: cwes,
|
||||
Links: util.Distinct(links),
|
||||
@@ -991,13 +1000,18 @@ Summary
|
||||
|
||||
Mitigation
|
||||
-----------
|
||||
{{.Mitigation }}
|
||||
{{.Mitigation }}
|
||||
|
||||
Links
|
||||
Primary Src
|
||||
-----------
|
||||
{{range $link := .Links -}}
|
||||
* {{$link}}
|
||||
{{end}}
|
||||
Patch
|
||||
-----------
|
||||
{{range $url := .PatchURLs -}}
|
||||
* {{$url}}
|
||||
{{end}}
|
||||
CWE
|
||||
-----------
|
||||
{{range .Cwes -}}
|
||||
|
||||
@@ -217,38 +217,18 @@ No CVE-IDs are found in updatable packages.
|
||||
data = append(data, []string{"Summary", vuln.Summaries(
|
||||
config.Conf.Lang, r.Family)[0].Value})
|
||||
|
||||
mitigation := vuln.Mitigations(r.Family)[0]
|
||||
if mitigation.Type != models.Unknown {
|
||||
data = append(data, []string{"Mitigation", mitigation.Value})
|
||||
for _, m := range vuln.Mitigations {
|
||||
data = append(data, []string{"Mitigation", m.URL})
|
||||
}
|
||||
|
||||
cweURLs, top10URLs := []string{}, []string{}
|
||||
cweTop25URLs, sansTop25URLs := []string{}, []string{}
|
||||
for _, v := range vuln.CveContents.UniqCweIDs(r.Family) {
|
||||
name, url, top10Rank, top10URL, cweTop25Rank, cweTop25URL, sansTop25Rank, sansTop25URL := r.CweDict.Get(v.Value, r.Lang)
|
||||
if top10Rank != "" {
|
||||
data = append(data, []string{"CWE",
|
||||
fmt.Sprintf("[OWASP Top%s] %s: %s (%s)",
|
||||
top10Rank, v.Value, name, v.Type)})
|
||||
top10URLs = append(top10URLs, top10URL)
|
||||
}
|
||||
if cweTop25Rank != "" {
|
||||
data = append(data, []string{"CWE",
|
||||
fmt.Sprintf("[CWE Top%s] %s: %s (%s)",
|
||||
cweTop25Rank, v.Value, name, v.Type)})
|
||||
cweTop25URLs = append(cweTop25URLs, cweTop25URL)
|
||||
}
|
||||
if sansTop25Rank != "" {
|
||||
data = append(data, []string{"CWE",
|
||||
fmt.Sprintf("[CWE/SANS Top%s] %s: %s (%s)",
|
||||
sansTop25Rank, v.Value, name, v.Type)})
|
||||
sansTop25URLs = append(sansTop25URLs, sansTop25URL)
|
||||
}
|
||||
if top10Rank == "" && cweTop25Rank == "" && sansTop25Rank == "" {
|
||||
data = append(data, []string{"CWE", fmt.Sprintf("%s: %s (%s)",
|
||||
v.Value, name, v.Type)})
|
||||
}
|
||||
cweURLs = append(cweURLs, url)
|
||||
links := vuln.CveContents.PrimarySrcURLs(
|
||||
config.Conf.Lang, r.Family, vuln.CveID)
|
||||
for _, link := range links {
|
||||
data = append(data, []string{"Primary Src", link.Value})
|
||||
}
|
||||
|
||||
for _, url := range vuln.CveContents.PatchURLs() {
|
||||
data = append(data, []string{"Patch", url})
|
||||
}
|
||||
|
||||
vuln.AffectedPackages.Sort()
|
||||
@@ -324,23 +304,35 @@ No CVE-IDs are found in updatable packages.
|
||||
data = append(data, []string{"Confidence", confidence.String()})
|
||||
}
|
||||
|
||||
if strings.HasPrefix(vuln.CveID, "CVE-") {
|
||||
links := vuln.CveContents.SourceLinks(
|
||||
config.Conf.Lang, r.Family, vuln.CveID)
|
||||
data = append(data, []string{"Source", links[0].Value})
|
||||
|
||||
if 0 < len(vuln.Cvss2Scores(r.Family)) {
|
||||
data = append(data, []string{"CVSSv2 Calc", vuln.Cvss2CalcURL()})
|
||||
cweURLs, top10URLs := []string{}, []string{}
|
||||
cweTop25URLs, sansTop25URLs := []string{}, []string{}
|
||||
for _, v := range vuln.CveContents.UniqCweIDs(r.Family) {
|
||||
name, url, top10Rank, top10URL, cweTop25Rank, cweTop25URL, sansTop25Rank, sansTop25URL := r.CweDict.Get(v.Value, r.Lang)
|
||||
if top10Rank != "" {
|
||||
data = append(data, []string{"CWE",
|
||||
fmt.Sprintf("[OWASP Top%s] %s: %s (%s)",
|
||||
top10Rank, v.Value, name, v.Type)})
|
||||
top10URLs = append(top10URLs, top10URL)
|
||||
}
|
||||
if 0 < len(vuln.Cvss3Scores()) {
|
||||
data = append(data, []string{"CVSSv3 Calc", vuln.Cvss3CalcURL()})
|
||||
if cweTop25Rank != "" {
|
||||
data = append(data, []string{"CWE",
|
||||
fmt.Sprintf("[CWE Top%s] %s: %s (%s)",
|
||||
cweTop25Rank, v.Value, name, v.Type)})
|
||||
cweTop25URLs = append(cweTop25URLs, cweTop25URL)
|
||||
}
|
||||
if sansTop25Rank != "" {
|
||||
data = append(data, []string{"CWE",
|
||||
fmt.Sprintf("[CWE/SANS Top%s] %s: %s (%s)",
|
||||
sansTop25Rank, v.Value, name, v.Type)})
|
||||
sansTop25URLs = append(sansTop25URLs, sansTop25URL)
|
||||
}
|
||||
if top10Rank == "" && cweTop25Rank == "" && sansTop25Rank == "" {
|
||||
data = append(data, []string{"CWE", fmt.Sprintf("%s: %s (%s)",
|
||||
v.Value, name, v.Type)})
|
||||
}
|
||||
cweURLs = append(cweURLs, url)
|
||||
}
|
||||
|
||||
vlinks := vuln.VendorLinks(r.Family)
|
||||
for name, url := range vlinks {
|
||||
data = append(data, []string{name, url})
|
||||
}
|
||||
for _, url := range cweURLs {
|
||||
data = append(data, []string{"CWE", url})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user