From cfbf779f9b86bea7f81623952b00df01d41860db Mon Sep 17 00:00:00 2001 From: Kota Kanbe Date: Wed, 16 Dec 2020 07:10:18 +0900 Subject: [PATCH] feat(exploit): add exploit link in NVD as a source (#1096) Added Refs information with NVD's Expoit tag as an information source for Exploit. --- models/cvecontents.go | 30 ------------------------------ models/utils.go | 15 +++++++++++---- models/vulninfos.go | 42 +++++++++++++++++++++--------------------- report/report.go | 5 ++--- report/tui.go | 4 +++- 5 files changed, 37 insertions(+), 59 deletions(-) diff --git a/models/cvecontents.go b/models/cvecontents.go index 16db36ca..3d44eec7 100644 --- a/models/cvecontents.go +++ b/models/cvecontents.go @@ -225,16 +225,6 @@ func NewCveContentType(name string) CveContentType { return Amazon case "trivy": return Trivy - // case vulnerability.NodejsSecurityWg: - // return NodeSec - // case vulnerability.PythonSafetyDB: - // return PythonSec - // case vulnerability.RustSec: - // return RustSec - // case vulnerability.PhpSecurityAdvisories: - // return PhpSec - // case vulnerability.RubySec: - // return RubySec default: return Unknown } @@ -283,21 +273,6 @@ const ( // Trivy is Trivy Trivy CveContentType = "trivy" - // NodeSec : for JS - // NodeSec CveContentType = "node" - - // // PythonSec : for PHP - // PythonSec CveContentType = "python" - - // // PhpSec : for PHP - // PhpSec CveContentType = "php" - - // // RubySec : for Ruby - // RubySec CveContentType = "ruby" - - // // RustSec : for Rust - // RustSec CveContentType = "rust" - // Unknown is Unknown Unknown CveContentType = "unknown" ) @@ -319,11 +294,6 @@ var AllCveContetTypes = CveContentTypes{ DebianSecurityTracker, WPVulnDB, Trivy, - // NodeSec, - // PythonSec, - // PhpSec, - // RubySec, - // RustSec, } // Except returns CveContentTypes except for given args diff --git a/models/utils.go b/models/utils.go index 880f704b..2b76ae52 100644 --- a/models/utils.go +++ b/models/utils.go @@ -49,9 +49,9 @@ func ConvertJvnToModel(cveID string, jvn *cvedict.Jvn) *CveContent { } // ConvertNvdJSONToModel convert NVD to CveContent -func ConvertNvdJSONToModel(cveID string, nvd *cvedict.NvdJSON) *CveContent { +func ConvertNvdJSONToModel(cveID string, nvd *cvedict.NvdJSON) (*CveContent, []Exploit) { if nvd == nil { - return nil + return nil, nil } // var cpes = []Cpe{} // for _, c := range nvd.Cpes { @@ -61,12 +61,19 @@ func ConvertNvdJSONToModel(cveID string, nvd *cvedict.NvdJSON) *CveContent { // }) // } - var refs = []Reference{} + refs := []Reference{} + exploits := []Exploit{} for _, r := range nvd.References { refs = append(refs, Reference{ Link: r.Link, Source: r.Source, }) + if strings.Contains(r.Tags, "Exploit") { + exploits = append(exploits, Exploit{ + ExploitType: "NVD", + URL: r.Link, + }) + } } cweIDs := []string{} @@ -95,5 +102,5 @@ func ConvertNvdJSONToModel(cveID string, nvd *cvedict.NvdJSON) *CveContent { References: refs, Published: nvd.PublishedDate, LastModified: nvd.LastModifiedDate, - } + }, exploits } diff --git a/models/vulninfos.go b/models/vulninfos.go index 5431c0e6..8009238b 100644 --- a/models/vulninfos.go +++ b/models/vulninfos.go @@ -134,7 +134,7 @@ func (ps PackageFixStatuses) Sort() { return } -// PackageFixStatus has name and other status abount the package +// PackageFixStatus has name and other status about the package type PackageFixStatus struct { Name string `json:"name,omitempty"` NotFixedYet bool `json:"notFixedYet,omitempty"` @@ -147,7 +147,7 @@ type VulnInfo struct { CveID string `json:"cveID,omitempty"` Confidences Confidences `json:"confidences,omitempty"` AffectedPackages PackageFixStatuses `json:"affectedPackages,omitempty"` - DistroAdvisories DistroAdvisories `json:"distroAdvisories,omitempty"` // for Aamazon, RHEL, FreeBSD + DistroAdvisories DistroAdvisories `json:"distroAdvisories,omitempty"` // for Amazon, RHEL, FreeBSD CveContents CveContents `json:"cveContents,omitempty"` Exploits []Exploit `json:"exploits,omitempty"` Metasploits []Metasploit `json:"metasploits,omitempty"` @@ -160,7 +160,7 @@ type VulnInfo struct { VulnType string `json:"vulnType,omitempty"` } -// Alert has XCERT alert information +// Alert has CERT alert information type Alert struct { URL string `json:"url,omitempty"` Title string `json:"title,omitempty"` @@ -233,7 +233,7 @@ func (g WpPackages) Add(pkg WpPackage) WpPackages { return append(g, pkg) } -// Titles returns tilte (TUI) +// Titles returns title (TUI) func (v VulnInfo) Titles(lang, myFamily string) (values []CveContentStr) { if lang == "ja" { if cont, found := v.CveContents[Jvn]; found && 0 < len(cont.Title) { @@ -509,7 +509,7 @@ func (v VulnInfo) MaxCvss2Score() CveContentCvss { } // If CVSS score isn't on NVD, RedHat and JVN, use OVAL and advisory Severity. - // Convert severity to cvss srore roughly, then returns max severity. + // Convert severity to cvss score roughly, then returns max severity. // Only Ubuntu, RedHat and Oracle have severity data in OVAL. order = []CveContentType{Ubuntu, RedHat, Oracle} for _, ctype := range order { @@ -615,10 +615,10 @@ type CveContentCvss struct { type CvssType string const ( - // CVSS2 means CVSS vesion2 + // CVSS2 means CVSS version2 CVSS2 CvssType = "2" - // CVSS3 means CVSS vesion3 + // CVSS3 means CVSS version3 CVSS3 CvssType = "3" ) @@ -800,7 +800,7 @@ type Metasploit struct { URLs []string `json:",omitempty"` } -// AlertDict has target cve's JPCERT and USCERT alert data +// AlertDict has target cve JPCERT and USCERT alert data type AlertDict struct { Ja []Alert `json:"ja"` En []Alert `json:"en"` @@ -821,7 +821,7 @@ func (a AlertDict) FormatSource() string { // Confidences is a list of Confidence type Confidences []Confidence -// AppendIfMissing appends confidence to the list if missiong +// AppendIfMissing appends confidence to the list if missing func (cs *Confidences) AppendIfMissing(confidence Confidence) { for _, c := range *cs { if c.DetectionMethod == confidence.DetectionMethod { @@ -839,7 +839,7 @@ func (cs Confidences) SortByConfident() Confidences { return cs } -// Confidence is a ranking how confident the CVE-ID was deteted correctly +// Confidence is a ranking how confident the CVE-ID was detected correctly // Score: 0 - 100 type Confidence struct { Score int `json:"score"` @@ -898,36 +898,36 @@ const ( ) var ( - // CpeNameMatch is a ranking how confident the CVE-ID was deteted correctly + // CpeNameMatch is a ranking how confident the CVE-ID was detected correctly CpeNameMatch = Confidence{100, CpeNameMatchStr, 1} - // YumUpdateSecurityMatch is a ranking how confident the CVE-ID was deteted correctly + // YumUpdateSecurityMatch is a ranking how confident the CVE-ID was detected correctly YumUpdateSecurityMatch = Confidence{100, YumUpdateSecurityMatchStr, 2} - // PkgAuditMatch is a ranking how confident the CVE-ID was deteted correctly + // PkgAuditMatch is a ranking how confident the CVE-ID was detected correctly PkgAuditMatch = Confidence{100, PkgAuditMatchStr, 2} - // OvalMatch is a ranking how confident the CVE-ID was deteted correctly + // OvalMatch is a ranking how confident the CVE-ID was detected correctly OvalMatch = Confidence{100, OvalMatchStr, 0} - // RedHatAPIMatch ranking how confident the CVE-ID was deteted correctly + // RedHatAPIMatch ranking how confident the CVE-ID was detected correctly RedHatAPIMatch = Confidence{100, RedHatAPIStr, 0} - // DebianSecurityTrackerMatch ranking how confident the CVE-ID was deteted correctly + // DebianSecurityTrackerMatch ranking how confident the CVE-ID was detected correctly DebianSecurityTrackerMatch = Confidence{100, DebianSecurityTrackerMatchStr, 0} - // TrivyMatch ranking how confident the CVE-ID was deteted correctly + // TrivyMatch ranking how confident the CVE-ID was detected correctly TrivyMatch = Confidence{100, TrivyMatchStr, 0} - // ChangelogExactMatch is a ranking how confident the CVE-ID was deteted correctly + // ChangelogExactMatch is a ranking how confident the CVE-ID was detected correctly ChangelogExactMatch = Confidence{95, ChangelogExactMatchStr, 3} - // ChangelogLenientMatch is a ranking how confident the CVE-ID was deteted correctly + // ChangelogLenientMatch is a ranking how confident the CVE-ID was detected correctly ChangelogLenientMatch = Confidence{50, ChangelogLenientMatchStr, 4} - // GitHubMatch is a ranking how confident the CVE-ID was deteted correctly + // GitHubMatch is a ranking how confident the CVE-ID was detected correctly GitHubMatch = Confidence{97, GitHubMatchStr, 2} - // WPVulnDBMatch is a ranking how confident the CVE-ID was deteted correctly + // WPVulnDBMatch is a ranking how confident the CVE-ID was detected correctly WPVulnDBMatch = Confidence{100, WPVulnDBMatchStr, 0} ) diff --git a/report/report.go b/report/report.go index 315f7129..e753b5af 100644 --- a/report/report.go +++ b/report/report.go @@ -245,8 +245,6 @@ func DetectWordPressCves(r *models.ScanResult) error { // FillCveInfo fill scanResult with cve info. func FillCveInfo(dbclient DBClient, r *models.ScanResult) error { - - // Fill CVE information util.Log.Infof("Fill CVE detailed with gost") if err := gost.NewClient(r.Family).FillCVEsWithRedHat(dbclient.GostDB, r); err != nil { return xerrors.Errorf("Failed to fill with gost: %w", err) @@ -291,7 +289,7 @@ func fillCvesWithNvdJvn(driver cvedb.DB, r *models.ScanResult) error { return err } for _, d := range ds { - nvd := models.ConvertNvdJSONToModel(d.CveID, d.NvdJSON) + nvd, exploits := models.ConvertNvdJSONToModel(d.CveID, d.NvdJSON) jvn := models.ConvertJvnToModel(d.CveID, d.Jvn) alerts := fillCertAlerts(&d) @@ -306,6 +304,7 @@ func fillCvesWithNvdJvn(driver cvedb.DB, r *models.ScanResult) error { } } vinfo.AlertDict = alerts + vinfo.Exploits = append(vinfo.Exploits, exploits...) r.ScannedCves[cveID] = vinfo break } diff --git a/report/tui.go b/report/tui.go index d7be3483..8abc4463 100644 --- a/report/tui.go +++ b/report/tui.go @@ -626,7 +626,9 @@ func summaryLines(r models.ScanResult) string { } exploits := "" - if 0 < len(vinfo.Exploits) || 0 < len(vinfo.Metasploits) { + if 0 < len(vinfo.Metasploits) { + exploits = "EXP" + } else if 0 < len(vinfo.Exploits) { exploits = "POC" }