From 777da589337bae485202f90bb5e86b10423aa50f Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Tue, 7 May 2019 20:29:38 +0900 Subject: [PATCH 1/3] Use fork tablewriter --- go.mod | 2 ++ go.sum | 2 ++ 2 files changed, 4 insertions(+) diff --git a/go.mod b/go.mod index 219b22859deb..b3fdb8995219 100644 --- a/go.mod +++ b/go.mod @@ -37,3 +37,5 @@ require ( ) replace github.com/genuinetools/reg => github.com/tomoyamachi/reg v0.16.2-0.20190418055600-c6010b917a55 + +replace github.com/olekukonko/tablewriter => github.com/knqyf263/tablewriter v0.0.2 diff --git a/go.sum b/go.sum index 60f4da053f46..4bb3bb675362 100644 --- a/go.sum +++ b/go.sum @@ -128,6 +128,8 @@ github.com/knqyf263/go-version v1.1.1 h1:+MpcBC9b7rk5ihag8Y/FLG8get1H2GjniwKQ+9D github.com/knqyf263/go-version v1.1.1/go.mod h1:0tBvHvOBSf5TqGNcY+/ih9o8qo3R16iZCpB9rP0D3VM= github.com/knqyf263/nested v0.0.1 h1:Sv26CegUMhjt19zqbBKntjwESdxe5hxVPSk0+AKjdUc= github.com/knqyf263/nested v0.0.1/go.mod h1:zwhsIhMkBg90DTOJQvxPkKIypEHPYkgWHs4gybdlUmk= +github.com/knqyf263/tablewriter v0.0.2 h1:lGaBruL/oJt8FAlMVy9KU0oQ/6NXAJjvK7wBgZyc+Og= +github.com/knqyf263/tablewriter v0.0.2/go.mod h1:NDOJQAZxabBL3e13jQVktkvbr6bxXXPon8Lyh7fRPPc= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= From bb864308425b046d8264b045d97f8880bc1461b8 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Tue, 7 May 2019 20:30:56 +0900 Subject: [PATCH 2/3] Display advisory information --- pkg/scanner/library/bundler/advisory.go | 48 ++++++++++++++++++++-- pkg/scanner/library/composer/advisory.go | 34 ++++++++++++++- pkg/scanner/library/npm/advisory.go | 43 ++++++++++++++++++- pkg/scanner/library/pipenv/advisory.go | 39 +++++++++++++++++- pkg/scanner/library/scan.go | 2 +- pkg/scanner/scan.go | 12 ++++-- pkg/vulnsrc/vulnerability/const.go | 22 ++++++---- pkg/vulnsrc/vulnerability/types.go | 16 ++++---- pkg/vulnsrc/vulnerability/vulnerability.go | 1 + 9 files changed, 186 insertions(+), 31 deletions(-) diff --git a/pkg/scanner/library/bundler/advisory.go b/pkg/scanner/library/bundler/advisory.go index ca8c9dcc3b74..b93cae358272 100644 --- a/pkg/scanner/library/bundler/advisory.go +++ b/pkg/scanner/library/bundler/advisory.go @@ -1,10 +1,16 @@ package bundler import ( + "fmt" "io/ioutil" "os" "path/filepath" + "github.com/etcd-io/bbolt" + + "github.com/knqyf263/trivy/pkg/db" + "github.com/knqyf263/trivy/pkg/vulnsrc/vulnerability" + "golang.org/x/xerrors" "github.com/knqyf263/trivy/pkg/git" @@ -28,6 +34,9 @@ type Advisory struct { Osvdb string Title string Url string + Description string + CvssV2 float64 `yaml:"cvss_v2"` + CvssV3 float64 `yaml:"cvss_v3"` PatchedVersions []string `yaml:"patched_versions"` UnaffectedVersions []string `yaml:"unaffected_versions"` Related Related @@ -42,14 +51,15 @@ func (s *Scanner) UpdateDB() (err error) { if _, err := git.CloneOrPull(dbURL, repoPath); err != nil { return xerrors.Errorf("error in %s security DB update: %w", s.Type(), err) } - s.db, err = walk() + s.db, err = s.walk() return err } -func walk() (AdvisoryDB, error) { +func (s *Scanner) walk() (AdvisoryDB, error) { advisoryDB := AdvisoryDB{} root := filepath.Join(repoPath, "gems") + var vulns []vulnerability.Vulnerability err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if info.IsDir() { return nil @@ -65,16 +75,48 @@ func walk() (AdvisoryDB, error) { return xerrors.Errorf("failed to unmarshal YAML: %w", err) } + // for detecting vulnerabilities advisories, ok := advisoryDB[advisory.Gem] if !ok { advisories = []Advisory{} } advisoryDB[advisory.Gem] = append(advisories, advisory) + // for displaying vulnerability detail + var vulnerabilityID string + if advisory.Cve != "" { + vulnerabilityID = fmt.Sprintf("CVE-%s", advisory.Cve) + } else if advisory.Osvdb != "" { + vulnerabilityID = fmt.Sprintf("OSVDB-%s", advisory.Osvdb) + } + vulns = append(vulns, vulnerability.Vulnerability{ + ID: vulnerabilityID, + CvssScore: advisory.CvssV2, + CvssScoreV3: advisory.CvssV3, + References: append([]string{advisory.Url}, advisory.Related.Url...), + Title: advisory.Title, + Description: advisory.Description, + }) + return nil }) if err != nil { - return nil, xerrors.Errorf("error in file wakl: %w", err) + return nil, xerrors.Errorf("error in file walk: %w", err) + } + + if err = s.saveVulnerabilities(vulns); err != nil { + return nil, err } return advisoryDB, nil } + +func (s *Scanner) saveVulnerabilities(vulns []vulnerability.Vulnerability) error { + return vulnerability.BatchUpdate(func(b *bbolt.Bucket) error { + for _, vuln := range vulns { + if err := db.Put(b, vuln.ID, vulnerability.RubySec, vuln); err != nil { + return xerrors.Errorf("failed to save %s vulnerability: %w", s.Type(), err) + } + } + return nil + }) +} diff --git a/pkg/scanner/library/composer/advisory.go b/pkg/scanner/library/composer/advisory.go index b455dde3baeb..39047942a42c 100644 --- a/pkg/scanner/library/composer/advisory.go +++ b/pkg/scanner/library/composer/advisory.go @@ -6,7 +6,13 @@ import ( "path/filepath" "strings" + "github.com/etcd-io/bbolt" + + "github.com/knqyf263/trivy/pkg/db" + "golang.org/x/xerrors" + "github.com/knqyf263/trivy/pkg/utils" + "github.com/knqyf263/trivy/pkg/vulnsrc/vulnerability" "github.com/knqyf263/trivy/pkg/git" "gopkg.in/yaml.v2" @@ -38,12 +44,13 @@ func (s *Scanner) UpdateDB() (err error) { if _, err := git.CloneOrPull(dbURL, repoPath); err != nil { return err } - s.db, err = walk() + s.db, err = s.walk() return err } -func walk() (AdvisoryDB, error) { +func (s *Scanner) walk() (AdvisoryDB, error) { advisoryDB := AdvisoryDB{} + var vulns []vulnerability.Vulnerability err := filepath.Walk(repoPath, func(path string, info os.FileInfo, err error) error { if info.IsDir() || !strings.HasPrefix(info.Name(), "CVE-") { return nil @@ -58,16 +65,39 @@ func walk() (AdvisoryDB, error) { if err != nil { return err } + + // for detecting vulnerabilities advisories, ok := advisoryDB[advisory.Reference] if !ok { advisories = []Advisory{} } advisoryDB[advisory.Reference] = append(advisories, advisory) + // for displaying vulnerability detail + vulns = append(vulns, vulnerability.Vulnerability{ + ID: advisory.Cve, + References: []string{advisory.Link}, + Title: advisory.Title, + }) + return nil }) if err != nil { + return nil, xerrors.Errorf("error in file walk: %w", err) + } + if err = s.saveVulnerabilities(vulns); err != nil { return nil, err } return advisoryDB, nil } + +func (s Scanner) saveVulnerabilities(vulns []vulnerability.Vulnerability) error { + return vulnerability.BatchUpdate(func(b *bbolt.Bucket) error { + for _, vuln := range vulns { + if err := db.Put(b, vuln.ID, vulnerability.PhpSecurityAdvisories, vuln); err != nil { + return xerrors.Errorf("failed to save %s vulnerability: %w", s.Type(), err) + } + } + return nil + }) +} diff --git a/pkg/scanner/library/npm/advisory.go b/pkg/scanner/library/npm/advisory.go index 89beb942d36e..81807526600f 100644 --- a/pkg/scanner/library/npm/advisory.go +++ b/pkg/scanner/library/npm/advisory.go @@ -2,12 +2,19 @@ package npm import ( "encoding/json" + "fmt" "os" "path/filepath" "strconv" "strings" + "github.com/etcd-io/bbolt" + + "github.com/knqyf263/trivy/pkg/db" + "golang.org/x/xerrors" + "github.com/knqyf263/trivy/pkg/utils" + "github.com/knqyf263/trivy/pkg/vulnsrc/vulnerability" "github.com/knqyf263/trivy/pkg/git" ) @@ -29,6 +36,7 @@ type Advisory struct { Cves []string VulnerableVersions string `json:"vulnerable_versions"` PatchedVersions string `json:"patched_versions"` + Overview string Recommendation string References []string CvssScoreNumber json.Number `json:"cvss_score"` @@ -39,12 +47,13 @@ func (s *Scanner) UpdateDB() (err error) { if _, err := git.CloneOrPull(dbURL, repoPath); err != nil { return err } - s.db, err = walk() + s.db, err = s.walk() return err } -func walk() (AdvisoryDB, error) { +func (s *Scanner) walk() (AdvisoryDB, error) { advisoryDB := AdvisoryDB{} + var vulns []vulnerability.Vulnerability err := filepath.Walk(filepath.Join(repoPath, "vuln"), func(path string, info os.FileInfo, err error) error { if info.IsDir() || !strings.HasSuffix(info.Name(), ".json") { return nil @@ -68,16 +77,46 @@ func walk() (AdvisoryDB, error) { advisory.CvssScore = -1 } + // for detecting vulnerabilities advisories, ok := advisoryDB[advisory.ModuleName] if !ok { advisories = []Advisory{} } advisoryDB[advisory.ModuleName] = append(advisories, advisory) + // for displaying vulnerability detail + vulnerabilityIDs := advisory.Cves + if len(vulnerabilityIDs) == 0 { + vulnerabilityIDs = []string{fmt.Sprintf("NSWG-ECO-%d", advisory.ID)} + } + for _, vulnID := range vulnerabilityIDs { + vulns = append(vulns, vulnerability.Vulnerability{ + ID: vulnID, + CvssScore: advisory.CvssScore, + References: advisory.References, + Title: advisory.Title, + Description: advisory.Overview, + }) + } + return nil }) if err != nil { + return nil, xerrors.Errorf("error in file walk: %w", err) + } + if err = s.saveVulnerabilities(vulns); err != nil { return nil, err } return advisoryDB, nil } + +func (s Scanner) saveVulnerabilities(vulns []vulnerability.Vulnerability) error { + return vulnerability.BatchUpdate(func(b *bbolt.Bucket) error { + for _, vuln := range vulns { + if err := db.Put(b, vuln.ID, vulnerability.NodejsSecurityWg, vuln); err != nil { + return xerrors.Errorf("failed to save %s vulnerability: %w", s.Type(), err) + } + } + return nil + }) +} diff --git a/pkg/scanner/library/pipenv/advisory.go b/pkg/scanner/library/pipenv/advisory.go index c1329b43453a..52391e6839b8 100644 --- a/pkg/scanner/library/pipenv/advisory.go +++ b/pkg/scanner/library/pipenv/advisory.go @@ -5,9 +5,14 @@ import ( "os" "path/filepath" + "github.com/etcd-io/bbolt" + + "github.com/knqyf263/trivy/pkg/db" + "golang.org/x/xerrors" "github.com/knqyf263/trivy/pkg/utils" + "github.com/knqyf263/trivy/pkg/vulnsrc/vulnerability" "github.com/knqyf263/trivy/pkg/git" ) @@ -34,14 +39,14 @@ func (s *Scanner) UpdateDB() (err error) { if _, err := git.CloneOrPull(dbURL, repoPath); err != nil { return err } - s.db, err = parse() + s.db, err = s.parse() if err != nil { return xerrors.Errorf("failed to parse python safety-db: %w", err) } return nil } -func parse() (AdvisoryDB, error) { +func (s *Scanner) parse() (AdvisoryDB, error) { advisoryDB := AdvisoryDB{} f, err := os.Open(filepath.Join(repoPath, "data", "insecure_full.json")) if err != nil { @@ -49,9 +54,39 @@ func parse() (AdvisoryDB, error) { } defer f.Close() + // for detecting vulnerabilities if err = json.NewDecoder(f).Decode(&advisoryDB); err != nil { return nil, err } + // for displaying vulnerability detail + var vulns []vulnerability.Vulnerability + for _, advisories := range advisoryDB { + for _, advisory := range advisories { + vulnerabilityID := advisory.Cve + if vulnerabilityID == "" { + vulnerabilityID = advisory.ID + } + vulns = append(vulns, vulnerability.Vulnerability{ + ID: vulnerabilityID, + Title: advisory.Advisory, + }) + } + } + if err = s.saveVulnerabilities(vulns); err != nil { + return nil, err + } + return advisoryDB, nil } + +func (s Scanner) saveVulnerabilities(vulns []vulnerability.Vulnerability) error { + return vulnerability.BatchUpdate(func(b *bbolt.Bucket) error { + for _, vuln := range vulns { + if err := db.Put(b, vuln.ID, vulnerability.PythonSafetyDB, vuln); err != nil { + return xerrors.Errorf("failed to save %s vulnerability: %w", s.Type(), err) + } + } + return nil + }) +} diff --git a/pkg/scanner/library/scan.go b/pkg/scanner/library/scan.go index 1a2b568b12a0..5f1e8b7d7fcb 100644 --- a/pkg/scanner/library/scan.go +++ b/pkg/scanner/library/scan.go @@ -96,7 +96,7 @@ func scan(scanner Scanner, pkgs []ptypes.Library) ([]types.Vulnerability, error) return nil, xerrors.Errorf("failed to update %s advisories: %w", scanner.Type(), err) } - log.Logger.Infof("Detect %s vulnerabilities", scanner.Type()) + log.Logger.Infof("Detecting %s vulnerabilities...", scanner.Type()) var vulnerabilities []types.Vulnerability for _, pkg := range pkgs { v, err := version.NewVersion(pkg.Version) diff --git a/pkg/scanner/scan.go b/pkg/scanner/scan.go index c07445c802f6..bafa4668fbab 100644 --- a/pkg/scanner/scan.go +++ b/pkg/scanner/scan.go @@ -25,6 +25,12 @@ import ( "github.com/knqyf263/fanal/extractor" ) +var ( + sources = []string{vulnerability.Nvd, vulnerability.RedHat, vulnerability.Debian, + vulnerability.DebianOVAL, vulnerability.Alpine, vulnerability.RubySec, vulnerability.PhpSecurityAdvisories, + vulnerability.NodejsSecurityWg, vulnerability.PythonSafetyDB} +) + func ScanImage(imageName, filePath string, severities []vulnerability.Severity) (report.Results, error) { var results report.Results var err error @@ -134,8 +140,7 @@ func getDetail(vulnID string) (vulnerability.Severity, string) { } func getSeverity(details map[string]vulnerability.Vulnerability) vulnerability.Severity { - for _, source := range []string{vulnerability.Nvd, vulnerability.RedHat, vulnerability.Debian, - vulnerability.DebianOVAL, vulnerability.Alpine} { + for _, source := range sources { d, ok := details[source] if !ok { continue @@ -154,8 +159,7 @@ func getSeverity(details map[string]vulnerability.Vulnerability) vulnerability.S } func getTitle(details map[string]vulnerability.Vulnerability) string { - for _, source := range []string{vulnerability.Nvd, vulnerability.RedHat, vulnerability.Debian, - vulnerability.DebianOVAL, vulnerability.Alpine} { + for _, source := range sources { d, ok := details[source] if !ok { continue diff --git a/pkg/vulnsrc/vulnerability/const.go b/pkg/vulnsrc/vulnerability/const.go index 577c65afafe5..eeb5c3e2f743 100644 --- a/pkg/vulnsrc/vulnerability/const.go +++ b/pkg/vulnsrc/vulnerability/const.go @@ -2,13 +2,17 @@ package vulnerability const ( // Data source - Nvd = "nvd" - RedHat = "redhat" - Debian = "debian" - DebianOVAL = "debian-oval" - Ubuntu = "ubuntu" - CentOS = "centos" - Fedora = "fedora" - Amazon = "amazon" - Alpine = "alpine" + Nvd = "nvd" + RedHat = "redhat" + Debian = "debian" + DebianOVAL = "debian-oval" + Ubuntu = "ubuntu" + CentOS = "centos" + Fedora = "fedora" + Amazon = "amazon" + Alpine = "alpine" + RubySec = "ruby-advisory-db" + PhpSecurityAdvisories = "php-security-advisories" + NodejsSecurityWg = "nodejs-security-wg" + PythonSafetyDB = "python-safety-db" ) diff --git a/pkg/vulnsrc/vulnerability/types.go b/pkg/vulnsrc/vulnerability/types.go index b917f06c5cdf..d100a69e13d1 100644 --- a/pkg/vulnsrc/vulnerability/types.go +++ b/pkg/vulnsrc/vulnerability/types.go @@ -19,18 +19,18 @@ const ( var ( SeverityNames = []string{ - "CRITICAL", - "HIGH", - "MEDIUM", - "LOW", "UNKNOWN", + "LOW", + "MEDIUM", + "HIGH", + "CRITICAL", } SeverityColor = []func(a ...interface{}) string{ - color.New(color.FgRed).SprintFunc(), - color.New(color.FgHiRed).SprintFunc(), - color.New(color.FgYellow).SprintFunc(), - color.New(color.FgBlue).SprintFunc(), color.New(color.FgCyan).SprintFunc(), + color.New(color.FgBlue).SprintFunc(), + color.New(color.FgYellow).SprintFunc(), + color.New(color.FgHiRed).SprintFunc(), + color.New(color.FgRed).SprintFunc(), } ) diff --git a/pkg/vulnsrc/vulnerability/vulnerability.go b/pkg/vulnsrc/vulnerability/vulnerability.go index 0ed9b5b29bb6..626027b7efc0 100644 --- a/pkg/vulnsrc/vulnerability/vulnerability.go +++ b/pkg/vulnsrc/vulnerability/vulnerability.go @@ -13,6 +13,7 @@ const ( ) type Vulnerability struct { + ID string // e.g. CVE-2019-8331, OSVDB-104365 CvssScore float64 CvssScoreV3 float64 Severity Severity From 29de9a646a8741da96089d50b86cecf13f5939ad Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Tue, 7 May 2019 20:36:04 +0900 Subject: [PATCH 3/3] Update README --- README.md | 4 +++- imgs/logo.png | Bin 0 -> 20643 bytes 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 imgs/logo.png diff --git a/README.md b/README.md index 4b1dd40a1a74..0f7cd2658503 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,12 @@ -# trivy + [![GitHub release](https://img.shields.io/github/release/knqyf263/trivy.svg)](https://github.com/knqyf263/trivy/releases/latest) [![CircleCI](https://circleci.com/gh/knqyf263/trivy.svg?style=svg)](https://circleci.com/gh/knqyf263/trivy) [![Go Report Card](https://goreportcard.com/badge/github.com/knqyf263/trivy)](https://goreportcard.com/report/github.com/knqyf263/trivy) [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/knqyf263/trivy/blob/master/LICENSE) +A Simple and Comprehensive Vulnerability Scanner for Containers + # Abstract Scan containers diff --git a/imgs/logo.png b/imgs/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..b8d821ad6e2d79e8988d4951be282ddd39f5aef6 GIT binary patch literal 20643 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

+Y~9V4$Sr!6uixoLZuBo$YWEF6KU}4 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