Compare commits

..

17 Commits

Author SHA1 Message Date
Kota Kanbe
8659668177 fix(cpescan): bug in NvdVendorProductMatch (#1320)
* fix(cpescan): bug in NvdVendorProductMatch

* update go mod
2021-10-13 12:55:01 +09:00
Kota Kanbe
e07b6a9160 feat(report): show Amazon ALAS link to report (#1318) 2021-10-12 09:09:58 +09:00
Kota Kanbe
aac5ef1438 feat: update-trivy (#1316)
* feat: update-trivy

* add v2 parser

* implement v2

* refactor

* feat: add show version to future-vuls

* add test case for v2

* trivy v0.20.0

* support --list-all-pkgs

* fix lint err

* add test case for jar

* add a test case for gemspec in container

* remove v1 parser and change Library struct

* Changed the field name in the model struct LibraryScanner

* add comment

* fix comment

* fix comment

* chore

* add struct tag
2021-10-08 17:22:06 +09:00
sadayuki-matsuno
d780a73297 add log json option (#1317) 2021-10-07 16:00:01 +09:00
Kota Kanbe
9ef8cee36e refactor(exploitdb): use pipeline effectively (#1314)
https://github.com/vulsio/go-exploitdb/pull/64
2021-10-01 09:10:49 +09:00
Kota Kanbe
77808a2c05 feat(go-cve): add error handling (#1313) 2021-09-30 12:42:43 +09:00
MaineK00n
177e553d12 feat(go-exploitdb): add error handling (#1310)
* feat(go-exploitdb): add error handling

* chore: rename

* go get -u go-exploitdb

Co-authored-by: Kota Kanbe <kotakanbe@gmail.com>
2021-09-30 11:33:18 +09:00
MaineK00n
40f8272a28 feat(go-msfdb): add error handling and support http mode (#1308)
* feat(go-msfdb): add error handling

* feat(go-msfdb): support http mode

* go get -u go-msfdb

Co-authored-by: Kota Kanbe <kotakanbe@gmail.com>
2021-09-30 11:16:41 +09:00
MaineK00n
a7eb1141ae feat(gost): add error handling (#1311)
* feat(gost): add error handling

* go get -u gost

Co-authored-by: Kota Kanbe <kotakanbe@gmail.com>
2021-09-30 10:51:41 +09:00
Kota Kanbe
c73ed7f32f chore: update find-lock file type (#1309) 2021-09-24 16:23:23 +09:00
Kota Kanbe
f047a6fe0c breaking-change: Update vuls-dictionaries (#1307)
* chore: udpate dictionaries

* update gost

* chore: update gost

* chore(go-cve-dict): use v0.8.1

* chore: change linter from golint to revive

* chore(linter): set revive config

* chore: fix commands and update golangci-lint version

* fix: lint errs

* chore: update gost

Co-authored-by: MaineK00n <mainek00n.1229@gmail.com>
2021-09-21 05:10:29 +09:00
MaineK00n
7f15a86d6a chore: change repository owner (#1306) 2021-09-16 11:05:37 +09:00
Kota Kanbe
da1e515253 breaking-change(goval): change-redis-architecture (#1305)
https://github.com/kotakanbe/goval-dictionary/pull/145
2021-09-15 08:25:14 +09:00
MaineK00n
591786fde6 feat(oval): support new goval-dictionary model (#1280)
* feat(oval): support new goval-dictionary model

* chore: fix lint err

* chore: set len of slice to 0

* fix(oval): avoid contamination of AffectedPackages by writing directly to defPacks

* fix(oval): avoid contamination of AffectedPackages by writing directly to defPacks

* feat(report): do not add duplicate CveContent

* chore: goval-dictionary update

* chore: go mod tidy

* fix(oval): preload Advisory.Cves for Ubuntu

https://github.com/kotakanbe/goval-dictionary/pull/152

Co-authored-by: Kota Kanbe <kotakanbe@gmail.com>
2021-09-13 10:19:59 +09:00
Kota Kanbe
47e6ea249d chore: fix lint warning (#1301) 2021-09-12 20:35:56 +09:00
Kota Kanbe
4a72295de7 feat(saas): support for library-only scanning (#1300) 2021-09-10 15:38:35 +09:00
MaineK00n
9ed5f2cac5 feat(debian): support Debian 11(bullseye) (#1298)
* feat(debian): support bullseye

* fix(debian): fix test case
2021-09-08 10:47:34 +09:00
67 changed files with 2431 additions and 6254 deletions

View File

@@ -16,7 +16,7 @@ jobs:
uses: golangci/golangci-lint-action@v2
with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
version: v1.32
version: v1.42
args: --timeout=10m
# Optional: working directory, useful for monorepos

View File

@@ -1,14 +1,44 @@
name: golang-ci
linters-settings:
errcheck:
revive:
# see https://github.com/mgechev/revive#available-rules for details.
ignore-generated-header: true
severity: warning
confidence: 0.8
rules:
- name: blank-imports
- name: context-as-argument
- name: context-keys-type
- name: dot-imports
- name: error-return
- name: error-strings
- name: error-naming
- name: exported
- name: if-return
- name: increment-decrement
- name: var-naming
- name: var-declaration
- name: package-comments
- name: range
- name: receiver-naming
- name: time-naming
- name: unexported-return
- name: indent-error-flow
- name: errorf
- name: empty-block
- name: superfluous-else
- name: unused-parameter
- name: unreachable-code
- name: redefines-builtin-id
# errcheck:
#exclude: /path/to/file.txt
linters:
disable-all: true
enable:
- goimports
- golint
- revive
- govet
- misspell
- errcheck

30
.revive.toml Normal file
View File

@@ -0,0 +1,30 @@
ignoreGeneratedHeader = false
severity = "warning"
confidence = 0.8
errorCode = 0
warningCode = 0
[rule.blank-imports]
[rule.context-as-argument]
[rule.context-keys-type]
[rule.dot-imports]
[rule.error-return]
[rule.error-strings]
[rule.error-naming]
[rule.exported]
[rule.if-return]
[rule.increment-decrement]
[rule.var-naming]
[rule.var-declaration]
[rule.package-comments]
[rule.range]
[rule.receiver-naming]
[rule.time-naming]
[rule.unexported-return]
[rule.indent-error-flow]
[rule.errorf]
[rule.empty-block]
[rule.superfluous-else]
[rule.unused-parameter]
[rule.unreachable-code]
[rule.redefines-builtin-id]

View File

@@ -17,8 +17,7 @@ PKGS = $(shell go list ./...)
VERSION := $(shell git describe --tags --abbrev=0)
REVISION := $(shell git rev-parse --short HEAD)
BUILDTIME := $(shell date "+%Y%m%d_%H%M%S")
LDFLAGS := -X 'github.com/future-architect/vuls/config.Version=$(VERSION)' \
-X 'github.com/future-architect/vuls/config.Revision=build-$(BUILDTIME)_$(REVISION)'
LDFLAGS := -X 'github.com/future-architect/vuls/config.Version=$(VERSION)' -X 'github.com/future-architect/vuls/config.Revision=build-$(BUILDTIME)_$(REVISION)'
GO := GO111MODULE=on go
CGO_UNABLED := CGO_ENABLED=0 go
GO_OFF := GO111MODULE=off go
@@ -42,8 +41,8 @@ install-scanner: ./cmd/scanner/main.go
$(CGO_UNABLED) install -tags=scanner -ldflags "$(LDFLAGS)" ./cmd/scanner
lint:
$(GO_OFF) get -u golang.org/x/lint/golint
golint $(PKGS)
$(GO_OFF) get -u github.com/mgechev/revive
revive -config ./.revive.toml -formatter plain $(PKGS)
vet:
echo $(PKGS) | xargs env $(GO) vet || exit;
@@ -78,11 +77,11 @@ clean:
# trivy-to-vuls
build-trivy-to-vuls: pretest fmt
$(GO) build -o trivy-to-vuls contrib/trivy/cmd/*.go
$(GO) build -a -ldflags "$(LDFLAGS)" -o trivy-to-vuls contrib/trivy/cmd/*.go
# future-vuls
build-future-vuls: pretest fmt
$(GO) build -o future-vuls contrib/future-vuls/cmd/*.go
$(GO) build -a -ldflags "$(LDFLAGS)" -o future-vuls contrib/future-vuls/cmd/*.go
# integration-test

View File

@@ -7,6 +7,6 @@ type JSONLoader struct {
}
// Load load the configuration JSON file specified by path arg.
func (c JSONLoader) Load(path, sudoPass, keyPass string) (err error) {
func (c JSONLoader) Load(_, _, _ string) (err error) {
return xerrors.New("Not implement yet")
}

View File

@@ -110,6 +110,7 @@ func GetEOL(family, release string) (eol EOL, found bool) {
"8": {Ended: true},
"9": {StandardSupportUntil: time.Date(2022, 6, 30, 23, 59, 59, 0, time.UTC)},
"10": {StandardSupportUntil: time.Date(2024, 6, 30, 23, 59, 59, 0, time.UTC)},
"11": {StandardSupportUntil: time.Date(2026, 6, 30, 23, 59, 59, 0, time.UTC)},
}[major(release)]
case constant.Raspbian:
// Not found

View File

@@ -290,6 +290,14 @@ func TestEOL_IsStandardSupportEnded(t *testing.T) {
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "Debian 12 is not supported yet",
fields: fields{family: Debian, release: "12"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: false,
},
//alpine

View File

@@ -84,7 +84,7 @@ func (s ScanMode) String() string {
return ss + " mode"
}
func setScanMode(server *ServerInfo, d ServerInfo) error {
func setScanMode(server *ServerInfo) error {
if len(server.ScanMode) == 0 {
server.ScanMode = Conf.Default.ScanMode
}

View File

@@ -15,7 +15,7 @@ type TOMLLoader struct {
}
// Load load the configuration TOML file specified by path arg.
func (c TOMLLoader) Load(pathToToml, keyPass string) error {
func (c TOMLLoader) Load(pathToToml, _ string) error {
// util.Log.Infof("Loading config: %s", pathToToml)
if _, err := toml.DecodeFile(pathToToml, &Conf); err != nil {
return err
@@ -34,11 +34,11 @@ func (c TOMLLoader) Load(pathToToml, keyPass string) error {
index := 0
for name, server := range Conf.Servers {
server.ServerName = name
if err := setDefaultIfEmpty(&server, Conf.Default); err != nil {
if err := setDefaultIfEmpty(&server); err != nil {
return xerrors.Errorf("Failed to set default value to config. server: %s, err: %w", name, err)
}
if err := setScanMode(&server, Conf.Default); err != nil {
if err := setScanMode(&server); err != nil {
return xerrors.Errorf("Failed to set ScanMode: %w", err)
}
@@ -137,7 +137,7 @@ func (c TOMLLoader) Load(pathToToml, keyPass string) error {
return nil
}
func setDefaultIfEmpty(server *ServerInfo, d ServerInfo) error {
func setDefaultIfEmpty(server *ServerInfo) error {
if server.Type != constant.ServerTypePseudo {
if len(server.Host) == 0 {
return xerrors.Errorf("server.host is empty")

View File

@@ -81,6 +81,14 @@ func main() {
return
},
}
var cmdVersion = &cobra.Command{
Use: "version",
Short: "Show version",
Long: "Show version",
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("future-vuls-%s-%s\n", config.Version, config.Revision)
},
}
cmdFvulsUploader.PersistentFlags().StringVar(&serverUUID, "uuid", "", "server uuid. ENV: VULS_SERVER_UUID")
cmdFvulsUploader.PersistentFlags().StringVar(&configFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
cmdFvulsUploader.PersistentFlags().BoolVarP(&stdIn, "stdin", "s", false, "input from stdin. ENV: VULS_STDIN")
@@ -92,6 +100,7 @@ func main() {
var rootCmd = &cobra.Command{Use: "future-vuls"}
rootCmd.AddCommand(cmdFvulsUploader)
rootCmd.AddCommand(cmdVersion)
if err = rootCmd.Execute(); err != nil {
fmt.Println("Failed to execute command", err)
}

View File

@@ -9,8 +9,8 @@ import (
"os"
"path/filepath"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/contrib/trivy/parser"
"github.com/future-architect/vuls/models"
"github.com/spf13/cobra"
)
@@ -34,45 +34,55 @@ func main() {
reader := bufio.NewReader(os.Stdin)
buf := new(bytes.Buffer)
if _, err = buf.ReadFrom(reader); err != nil {
fmt.Printf("Failed to read file. err: %+v\n", err)
os.Exit(1)
return
}
trivyJSON = buf.Bytes()
} else {
if trivyJSON, err = ioutil.ReadFile(jsonFilePath); err != nil {
fmt.Println("Failed to read file", err)
fmt.Printf("Failed to read file. err: %+v\n", err)
os.Exit(1)
return
}
}
scanResult := &models.ScanResult{
JSONVersion: models.JSONVersion,
ScannedCves: models.VulnInfos{},
}
if scanResult, err = parser.Parse(trivyJSON, scanResult); err != nil {
fmt.Println("Failed to execute command", err)
parser, err := parser.NewParser(trivyJSON)
if err != nil {
fmt.Printf("Failed to new parser. err: %+v\n", err)
os.Exit(1)
}
scanResult, err := parser.Parse(trivyJSON)
if err != nil {
fmt.Printf("Failed to parse. err: %+v\n", err)
os.Exit(1)
return
}
var resultJSON []byte
if resultJSON, err = json.MarshalIndent(scanResult, "", " "); err != nil {
fmt.Println("Failed to create json", err)
fmt.Printf("Failed to create json. err: %+v\n", err)
os.Exit(1)
return
}
fmt.Println(string(resultJSON))
return
},
}
var cmdVersion = &cobra.Command{
Use: "version",
Short: "Show version",
Long: "Show version",
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("trivy-to-vuls-%s-%s\n", config.Version, config.Revision)
},
}
cmdTrivyToVuls.Flags().BoolVarP(&stdIn, "stdin", "s", false, "input from stdin")
cmdTrivyToVuls.Flags().StringVarP(&jsonDir, "trivy-json-dir", "d", "./", "trivy json dir")
cmdTrivyToVuls.Flags().StringVarP(&jsonFileName, "trivy-json-file-name", "f", "results.json", "trivy json file name")
var rootCmd = &cobra.Command{Use: "trivy-to-vuls"}
rootCmd.AddCommand(cmdTrivyToVuls)
rootCmd.AddCommand(cmdVersion)
if err = rootCmd.Execute(); err != nil {
fmt.Println("Failed to execute command", err)
fmt.Printf("Failed to execute command. err: %+v\n", err)
os.Exit(1)
}
os.Exit(0)
}

View File

@@ -2,179 +2,32 @@ package parser
import (
"encoding/json"
"sort"
"time"
"github.com/aquasecurity/fanal/analyzer/os"
"github.com/aquasecurity/trivy/pkg/report"
"github.com/aquasecurity/trivy/pkg/types"
v2 "github.com/future-architect/vuls/contrib/trivy/parser/v2"
"github.com/future-architect/vuls/models"
"golang.org/x/xerrors"
)
// Parse :
func Parse(vulnJSON []byte, scanResult *models.ScanResult) (result *models.ScanResult, err error) {
var trivyResults report.Results
if err = json.Unmarshal(vulnJSON, &trivyResults); err != nil {
return nil, err
}
pkgs := models.Packages{}
vulnInfos := models.VulnInfos{}
uniqueLibraryScannerPaths := map[string]models.LibraryScanner{}
for _, trivyResult := range trivyResults {
if IsTrivySupportedOS(trivyResult.Type) {
overrideServerData(scanResult, &trivyResult)
}
for _, vuln := range trivyResult.Vulnerabilities {
if _, ok := vulnInfos[vuln.VulnerabilityID]; !ok {
vulnInfos[vuln.VulnerabilityID] = models.VulnInfo{
CveID: vuln.VulnerabilityID,
Confidences: models.Confidences{
{
Score: 100,
DetectionMethod: models.TrivyMatchStr,
},
},
AffectedPackages: models.PackageFixStatuses{},
CveContents: models.CveContents{},
LibraryFixedIns: models.LibraryFixedIns{},
// VulnType : "",
}
}
vulnInfo := vulnInfos[vuln.VulnerabilityID]
var notFixedYet bool
fixState := ""
if len(vuln.FixedVersion) == 0 {
notFixedYet = true
fixState = "Affected"
}
var references models.References
for _, reference := range vuln.References {
references = append(references, models.Reference{
Source: "trivy",
Link: reference,
})
}
sort.Slice(references, func(i, j int) bool {
return references[i].Link < references[j].Link
})
var published time.Time
if vuln.PublishedDate != nil {
published = *vuln.PublishedDate
}
var lastModified time.Time
if vuln.LastModifiedDate != nil {
lastModified = *vuln.LastModifiedDate
}
vulnInfo.CveContents = models.CveContents{
models.Trivy: []models.CveContent{{
Cvss3Severity: vuln.Severity,
References: references,
Title: vuln.Title,
Summary: vuln.Description,
Published: published,
LastModified: lastModified,
}},
}
// do only if image type is Vuln
if IsTrivySupportedOS(trivyResult.Type) {
pkgs[vuln.PkgName] = models.Package{
Name: vuln.PkgName,
Version: vuln.InstalledVersion,
}
vulnInfo.AffectedPackages = append(vulnInfo.AffectedPackages, models.PackageFixStatus{
Name: vuln.PkgName,
NotFixedYet: notFixedYet,
FixState: fixState,
FixedIn: vuln.FixedVersion,
})
} else {
// LibraryScanの結果
vulnInfo.LibraryFixedIns = append(vulnInfo.LibraryFixedIns, models.LibraryFixedIn{
Key: trivyResult.Type,
Name: vuln.PkgName,
Path: trivyResult.Target,
FixedIn: vuln.FixedVersion,
})
libScanner := uniqueLibraryScannerPaths[trivyResult.Target]
libScanner.Libs = append(libScanner.Libs, types.Library{
Name: vuln.PkgName,
Version: vuln.InstalledVersion,
})
uniqueLibraryScannerPaths[trivyResult.Target] = libScanner
}
vulnInfos[vuln.VulnerabilityID] = vulnInfo
}
}
// flatten and unique libraries
libraryScanners := make([]models.LibraryScanner, 0, len(uniqueLibraryScannerPaths))
for path, v := range uniqueLibraryScannerPaths {
uniqueLibrary := map[string]types.Library{}
for _, lib := range v.Libs {
uniqueLibrary[lib.Name+lib.Version] = lib
}
var libraries []types.Library
for _, library := range uniqueLibrary {
libraries = append(libraries, library)
}
sort.Slice(libraries, func(i, j int) bool {
return libraries[i].Name < libraries[j].Name
})
libscanner := models.LibraryScanner{
Path: path,
Libs: libraries,
}
libraryScanners = append(libraryScanners, libscanner)
}
sort.Slice(libraryScanners, func(i, j int) bool {
return libraryScanners[i].Path < libraryScanners[j].Path
})
scanResult.ScannedCves = vulnInfos
scanResult.Packages = pkgs
scanResult.LibraryScanners = libraryScanners
return scanResult, nil
// Parser is a parser interface
type Parser interface {
Parse(vulnJSON []byte) (result *models.ScanResult, err error)
}
// IsTrivySupportedOS :
func IsTrivySupportedOS(family string) bool {
supportedFamilies := []string{
os.RedHat,
os.Debian,
os.Ubuntu,
os.CentOS,
os.Fedora,
os.Amazon,
os.Oracle,
os.Windows,
os.OpenSUSE,
os.OpenSUSELeap,
os.OpenSUSETumbleweed,
os.SLES,
os.Photon,
os.Alpine,
}
for _, supportedFamily := range supportedFamilies {
if family == supportedFamily {
return true
}
}
return false
// Report is used for judgeing the scheme version of trivy
type Report struct {
SchemaVersion int `json:",omitempty"`
}
func overrideServerData(scanResult *models.ScanResult, trivyResult *report.Result) {
scanResult.Family = trivyResult.Type
scanResult.ServerName = trivyResult.Target
scanResult.Optional = map[string]interface{}{
"trivy-target": trivyResult.Target,
// NewParser make a parser for the schema version of trivy
func NewParser(vulnJSON []byte) (Parser, error) {
r := Report{}
if err := json.Unmarshal(vulnJSON, &r); err != nil {
return nil, xerrors.Errorf("Failed to parse JSON. Please use the latest version of trivy, trivy-to-vuls and future-vuls")
}
switch r.SchemaVersion {
case 2:
return v2.ParserV2{}, nil
default:
return nil, xerrors.Errorf("Failed to parse trivy json. SchemeVersion %d is not supported yet. Please contact support", r.SchemaVersion)
}
scanResult.ScannedAt = time.Now()
scanResult.ScannedBy = "trivy"
scanResult.ScannedVia = "trivy"
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,60 @@
package v2
import (
"encoding/json"
"time"
"github.com/aquasecurity/trivy/pkg/report"
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/contrib/trivy/pkg"
"github.com/future-architect/vuls/models"
)
// ParserV2 is a parser for scheme v2
type ParserV2 struct {
}
// Parse trivy's JSON and convert to the Vuls struct
func (p ParserV2) Parse(vulnJSON []byte) (result *models.ScanResult, err error) {
var report report.Report
if err = json.Unmarshal(vulnJSON, &report); err != nil {
return nil, err
}
scanResult, err := pkg.Convert(report.Results)
if err != nil {
return nil, err
}
setScanResultMeta(scanResult, &report)
return scanResult, nil
}
func setScanResultMeta(scanResult *models.ScanResult, report *report.Report) {
for _, r := range report.Results {
const trivyTarget = "trivy-target"
if pkg.IsTrivySupportedOS(r.Type) {
scanResult.Family = r.Type
scanResult.ServerName = r.Target
scanResult.Optional = map[string]interface{}{
trivyTarget: r.Target,
}
} else if pkg.IsTrivySupportedLib(r.Type) {
if scanResult.Family == "" {
scanResult.Family = constant.ServerTypePseudo
}
if scanResult.ServerName == "" {
scanResult.ServerName = "library scan by trivy"
}
if _, ok := scanResult.Optional[trivyTarget]; !ok {
scanResult.Optional = map[string]interface{}{
trivyTarget: r.Target,
}
}
}
scanResult.ScannedAt = time.Now()
scanResult.ScannedBy = "trivy"
scanResult.ScannedVia = "trivy"
}
}

View File

@@ -0,0 +1,725 @@
package v2
import (
"testing"
"github.com/d4l3k/messagediff"
"github.com/future-architect/vuls/models"
)
func TestParse(t *testing.T) {
cases := map[string]struct {
vulnJSON []byte
expected *models.ScanResult
}{
"image redis": {
vulnJSON: redisTrivy,
expected: redisSR,
},
"image struts": {
vulnJSON: strutsTrivy,
expected: strutsSR,
},
"image osAndLib": {
vulnJSON: osAndLibTrivy,
expected: osAndLibSR,
},
}
for testcase, v := range cases {
actual, err := ParserV2{}.Parse(v.vulnJSON)
if err != nil {
t.Errorf("%s", err)
}
diff, equal := messagediff.PrettyDiff(
v.expected,
actual,
messagediff.IgnoreStructField("ScannedAt"),
messagediff.IgnoreStructField("Title"),
messagediff.IgnoreStructField("Summary"),
messagediff.IgnoreStructField("LastModified"),
messagediff.IgnoreStructField("Published"),
)
if !equal {
t.Errorf("test: %s, diff %s", testcase, diff)
}
}
}
var redisTrivy = []byte(`
{
"SchemaVersion": 2,
"ArtifactName": "redis",
"ArtifactType": "container_image",
"Metadata": {
"OS": {
"Family": "debian",
"Name": "10.10"
},
"ImageID": "sha256:ddcca4b8a6f0367b5de2764dfe76b0a4bfa6d75237932185923705da47004347",
"DiffIDs": [
"sha256:f68ef921efae588b3dd5cc466a1ca9c94c24785f1fa9420bea15ecc2dedbe781",
"sha256:b6fc243eaea74d1a41b242da4c3ec5166db80f38c4d57a10ce8860c00d902ace",
"sha256:ec92e47b7c52dacc26df07ee13e8e81c099b5a5661ccc97b06692a9c9d01e772",
"sha256:4be6d4460d3615186717f21ffc0023b168dce48967d01934bbe31127901d3d5c",
"sha256:992463b683270e164936e9c48fa395d05a7b8b5cc0aa208e4fa81aa9158fcae1",
"sha256:0083597d42d190ddb86c35587a7b196fe18d79382520544b5f715c1e4792b19a"
],
"RepoTags": [
"redis:latest"
],
"RepoDigests": [
"redis@sha256:66ce9bc742609650afc3de7009658473ed601db4e926a5b16d239303383bacad"
],
"ImageConfig": {
"architecture": "amd64",
"container": "fa59f1c2817c9095f8f7272a4ab9b11db0332b33efb3a82c00a3d1fec8763684",
"created": "2021-08-17T14:30:06.550779326Z",
"docker_version": "20.10.7",
"history": [
{
"created": "2021-08-17T01:24:06Z",
"created_by": "/bin/sh -c #(nop) ADD file:87b4e60fe3af680c6815448374365a44e9ea461bc8ade2960b4639c25aed3ba9 in / "
},
{
"created": "2021-08-17T14:30:06Z",
"created_by": "/bin/sh -c #(nop) CMD [\"redis-server\"]",
"empty_layer": true
}
],
"os": "linux",
"rootfs": {
"type": "layers",
"diff_ids": [
"sha256:f68ef921efae588b3dd5cc466a1ca9c94c24785f1fa9420bea15ecc2dedbe781",
"sha256:b6fc243eaea74d1a41b242da4c3ec5166db80f38c4d57a10ce8860c00d902ace",
"sha256:ec92e47b7c52dacc26df07ee13e8e81c099b5a5661ccc97b06692a9c9d01e772",
"sha256:4be6d4460d3615186717f21ffc0023b168dce48967d01934bbe31127901d3d5c",
"sha256:992463b683270e164936e9c48fa395d05a7b8b5cc0aa208e4fa81aa9158fcae1",
"sha256:0083597d42d190ddb86c35587a7b196fe18d79382520544b5f715c1e4792b19a"
]
},
"config": {
"Cmd": [
"redis-server"
],
"Entrypoint": [
"docker-entrypoint.sh"
],
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GOSU_VERSION=1.12",
"REDIS_VERSION=6.2.5",
"REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-6.2.5.tar.gz",
"REDIS_DOWNLOAD_SHA=4b9a75709a1b74b3785e20a6c158cab94cf52298aa381eea947a678a60d551ae"
],
"Image": "sha256:befbd3fc62bffcd0115008969a014faaad07828b2c54b4bcfd2d9fc3aa2508cd",
"Volumes": {
"/data": {}
},
"WorkingDir": "/data"
}
}
},
"Results": [
{
"Target": "redis (debian 10.10)",
"Class": "os-pkgs",
"Type": "debian",
"Packages": [
{
"Name": "adduser",
"Version": "3.118",
"SrcName": "adduser",
"SrcVersion": "3.118",
"Layer": {
"DiffID": "sha256:f68ef921efae588b3dd5cc466a1ca9c94c24785f1fa9420bea15ecc2dedbe781"
}
},
{
"Name": "apt",
"Version": "1.8.2.3",
"SrcName": "apt",
"SrcVersion": "1.8.2.3",
"Layer": {
"DiffID": "sha256:f68ef921efae588b3dd5cc466a1ca9c94c24785f1fa9420bea15ecc2dedbe781"
}
},
{
"Name": "bsdutils",
"Version": "1:2.33.1-0.1",
"SrcName": "util-linux",
"SrcVersion": "2.33.1-0.1",
"Layer": {
"DiffID": "sha256:f68ef921efae588b3dd5cc466a1ca9c94c24785f1fa9420bea15ecc2dedbe781"
}
},
{
"Name": "pkgA",
"Version": "1:2.33.1-0.1",
"SrcName": "util-linux",
"SrcVersion": "2.33.1-0.1",
"Layer": {
"DiffID": "sha256:f68ef921efae588b3dd5cc466a1ca9c94c24785f1fa9420bea15ecc2dedbe781"
}
}
],
"Vulnerabilities": [
{
"VulnerabilityID": "CVE-2011-3374",
"PkgName": "apt",
"InstalledVersion": "1.8.2.3",
"Layer": {
"DiffID": "sha256:f68ef921efae588b3dd5cc466a1ca9c94c24785f1fa9420bea15ecc2dedbe781"
},
"SeveritySource": "debian",
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2011-3374",
"Description": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.",
"Severity": "LOW",
"CweIDs": [
"CWE-347"
],
"CVSS": {
"nvd": {
"V2Vector": "AV:N/AC:M/Au:N/C:N/I:P/A:N",
"V3Vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N",
"V2Score": 4.3,
"V3Score": 3.7
}
},
"References": [
"https://access.redhat.com/security/cve/cve-2011-3374"
],
"PublishedDate": "2019-11-26T00:15:00Z",
"LastModifiedDate": "2021-02-09T16:08:00Z"
}
]
}
]
}
`)
var redisSR = &models.ScanResult{
JSONVersion: 4,
ServerName: "redis (debian 10.10)",
Family: "debian",
ScannedBy: "trivy",
ScannedVia: "trivy",
ScannedCves: models.VulnInfos{
"CVE-2011-3374": {
CveID: "CVE-2011-3374",
Confidences: models.Confidences{
models.Confidence{
Score: 100,
DetectionMethod: "TrivyMatch",
},
},
AffectedPackages: models.PackageFixStatuses{
models.PackageFixStatus{
Name: "apt",
NotFixedYet: true,
FixState: "Affected",
FixedIn: "",
}},
CveContents: models.CveContents{
"trivy": []models.CveContent{{
Title: "",
Summary: "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.",
Cvss3Severity: "LOW",
References: models.References{
{Source: "trivy", Link: "https://access.redhat.com/security/cve/cve-2011-3374"},
},
}},
},
LibraryFixedIns: models.LibraryFixedIns{},
},
},
LibraryScanners: models.LibraryScanners{},
Packages: models.Packages{
"apt": models.Package{
Name: "apt",
Version: "1.8.2.3",
},
"adduser": models.Package{
Name: "adduser",
Version: "3.118",
},
"bsdutils": models.Package{
Name: "bsdutils",
Version: "1:2.33.1-0.1",
},
"pkgA": models.Package{
Name: "pkgA",
Version: "1:2.33.1-0.1",
},
},
SrcPackages: models.SrcPackages{
"util-linux": models.SrcPackage{
Name: "util-linux",
Version: "2.33.1-0.1",
BinaryNames: []string{"bsdutils", "pkgA"},
},
},
Optional: map[string]interface{}{
"trivy-target": "redis (debian 10.10)",
},
}
var strutsTrivy = []byte(`
{
"SchemaVersion": 2,
"ArtifactName": "/data/struts-1.2.7/lib",
"ArtifactType": "filesystem",
"Metadata": {
"ImageConfig": {
"architecture": "",
"created": "0001-01-01T00:00:00Z",
"os": "",
"rootfs": {
"type": "",
"diff_ids": null
},
"config": {}
}
},
"Results": [
{
"Target": "Java",
"Class": "lang-pkgs",
"Type": "jar",
"Packages": [
{
"Name": "oro:oro",
"Version": "2.0.7",
"Layer": {}
},
{
"Name": "struts:struts",
"Version": "1.2.7",
"Layer": {}
},
{
"Name": "commons-beanutils:commons-beanutils",
"Version": "1.7.0",
"Layer": {}
}
],
"Vulnerabilities": [
{
"VulnerabilityID": "CVE-2014-0114",
"PkgName": "commons-beanutils:commons-beanutils",
"InstalledVersion": "1.7.0",
"FixedVersion": "1.9.2",
"Layer": {},
"SeveritySource": "nvd",
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2014-0114",
"Title": "Apache Struts 1: Class Loader manipulation via request parameters",
"Description": "Apache Commons BeanUtils, as distributed in lib/commons-beanutils-1.8.0.jar in Apache Struts 1.x through 1.3.10 and in other products requiring commons-beanutils through 1.9.2, does not suppress the class property, which allows remote attackers to \"manipulate\" the ClassLoader and execute arbitrary code via the class parameter, as demonstrated by the passing of this parameter to the getClass method of the ActionForm object in Struts 1.",
"Severity": "HIGH",
"CweIDs": [
"CWE-20"
],
"CVSS": {
"nvd": {
"V2Vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P",
"V2Score": 7.5
},
"redhat": {
"V2Vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P",
"V2Score": 7.5
}
},
"References": [
"http://advisories.mageia.org/MGASA-2014-0219.html"
],
"PublishedDate": "2014-04-30T10:49:00Z",
"LastModifiedDate": "2021-01-26T18:15:00Z"
},
{
"VulnerabilityID": "CVE-2012-1007",
"PkgName": "struts:struts",
"InstalledVersion": "1.2.7",
"Layer": {},
"SeveritySource": "nvd",
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2012-1007",
"Title": "struts: multiple XSS flaws",
"Description": "Multiple cross-site scripting (XSS) vulnerabilities in Apache Struts 1.3.10 allow remote attackers to inject arbitrary web script or HTML via (1) the name parameter to struts-examples/upload/upload-submit.do, or the message parameter to (2) struts-cookbook/processSimple.do or (3) struts-cookbook/processDyna.do.",
"Severity": "MEDIUM",
"CweIDs": [
"CWE-79"
],
"CVSS": {
"nvd": {
"V2Vector": "AV:N/AC:M/Au:N/C:N/I:P/A:N",
"V2Score": 4.3
},
"redhat": {
"V2Vector": "AV:N/AC:M/Au:N/C:N/I:P/A:N",
"V2Score": 4.3
}
},
"References": [
"https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2012-1007"
],
"PublishedDate": "2012-02-07T04:09:00Z",
"LastModifiedDate": "2018-10-17T01:29:00Z"
}
]
}
]
}`)
var strutsSR = &models.ScanResult{
JSONVersion: 4,
ServerName: "library scan by trivy",
Family: "pseudo",
ScannedBy: "trivy",
ScannedVia: "trivy",
ScannedCves: models.VulnInfos{
"CVE-2014-0114": {
CveID: "CVE-2014-0114",
Confidences: models.Confidences{
models.Confidence{
Score: 100,
DetectionMethod: "TrivyMatch",
},
},
CveContents: models.CveContents{
"trivy": []models.CveContent{{
Title: "Apache Struts 1: Class Loader manipulation via request parameters",
Summary: "Apache Commons BeanUtils, as distributed in lib/commons-beanutils-1.8.0.jar in Apache Struts 1.x through 1.3.10 and in other products requiring commons-beanutils through 1.9.2, does not suppress the class property, which allows remote attackers to \"manipulate\" the ClassLoader and execute arbitrary code via the class parameter, as demonstrated by the passing of this parameter to the getClass method of the ActionForm object in Struts 1.",
Cvss3Severity: "HIGH",
References: models.References{
{Source: "trivy", Link: "http://advisories.mageia.org/MGASA-2014-0219.html"},
},
}},
},
LibraryFixedIns: models.LibraryFixedIns{
models.LibraryFixedIn{
Key: "jar",
Name: "commons-beanutils:commons-beanutils",
FixedIn: "1.9.2",
//TODO use Artifactname?
Path: "Java",
},
},
AffectedPackages: models.PackageFixStatuses{},
},
"CVE-2012-1007": {
CveID: "CVE-2012-1007",
Confidences: models.Confidences{
models.Confidence{
Score: 100,
DetectionMethod: "TrivyMatch",
},
},
CveContents: models.CveContents{
"trivy": []models.CveContent{{
Title: "struts: multiple XSS flaws",
Summary: "Multiple cross-site scripting (XSS) vulnerabilities in Apache Struts 1.3.10 allow remote attackers to inject arbitrary web script or HTML via (1) the name parameter to struts-examples/upload/upload-submit.do, or the message parameter to (2) struts-cookbook/processSimple.do or (3) struts-cookbook/processDyna.do.",
Cvss3Severity: "MEDIUM",
References: models.References{
{Source: "trivy", Link: "https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2012-1007"},
},
}},
},
LibraryFixedIns: models.LibraryFixedIns{
models.LibraryFixedIn{
Key: "jar",
Name: "struts:struts",
FixedIn: "",
//TODO use Artifactname?
Path: "Java",
},
},
AffectedPackages: models.PackageFixStatuses{},
},
},
LibraryScanners: models.LibraryScanners{
models.LibraryScanner{
Type: "jar",
LockfilePath: "Java",
Libs: []models.Library{
{
Name: "commons-beanutils:commons-beanutils",
Version: "1.7.0",
},
{
Name: "oro:oro",
Version: "2.0.7",
},
{
Name: "struts:struts",
Version: "1.2.7",
},
},
},
},
Packages: models.Packages{},
SrcPackages: models.SrcPackages{},
Optional: map[string]interface{}{
"trivy-target": "Java",
},
}
var osAndLibTrivy = []byte(`
{
"SchemaVersion": 2,
"ArtifactName": "quay.io/fluentd_elasticsearch/fluentd:v2.9.0",
"ArtifactType": "container_image",
"Metadata": {
"OS": {
"Family": "debian",
"Name": "10.2"
},
"ImageID": "sha256:5a992077baba51b97f27591a10d54d2f2723dc9c81a3fe419e261023f2554933",
"DiffIDs": [
"sha256:25165eb51d15842f870f97873e0a58409d5e860e6108e3dd829bd10e484c0065"
],
"RepoTags": [
"quay.io/fluentd_elasticsearch/fluentd:v2.9.0"
],
"RepoDigests": [
"quay.io/fluentd_elasticsearch/fluentd@sha256:54716d825ec9791ffb403ac17a1e82159c98ac6161e02b2a054595ad01aa6726"
],
"ImageConfig": {
"architecture": "amd64",
"container": "232f3fc7ddffd71dc3ff52c6c0c3a5feea2f51acffd9b53850a8fc6f1a15319a",
"created": "2020-03-04T13:59:39.161374106Z",
"docker_version": "19.03.4",
"history": [
{
"created": "2020-03-04T13:59:39.161374106Z",
"created_by": "/bin/sh -c #(nop) CMD [\"/run.sh\"]",
"empty_layer": true
}
],
"os": "linux",
"rootfs": {
"type": "layers",
"diff_ids": [
"sha256:25165eb51d15842f870f97873e0a58409d5e860e6108e3dd829bd10e484c0065"
]
},
"config": {
"Cmd": [
"/run.sh"
],
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2"
],
"Image": "sha256:2a538358cddc4824e9eff1531e0c63ae5e3cda85d2984c647df9b1c816b9b86b",
"ExposedPorts": {
"80/tcp": {}
}
}
}
},
"Results": [
{
"Target": "quay.io/fluentd_elasticsearch/fluentd:v2.9.0 (debian 10.2)",
"Class": "os-pkgs",
"Type": "debian",
"Packages": [
{
"Name": "libgnutls30",
"Version": "3.6.7-4",
"SrcName": "gnutls28",
"SrcVersion": "3.6.7-4",
"Layer": {
"Digest": "sha256:000eee12ec04cc914bf96e8f5dee7767510c2aca3816af6078bd9fbe3150920c",
"DiffID": "sha256:831c5620387fb9efec59fc82a42b948546c6be601e3ab34a87108ecf852aa15f"
}
}
],
"Vulnerabilities": [
{
"VulnerabilityID": "CVE-2021-20231",
"PkgName": "libgnutls30",
"InstalledVersion": "3.6.7-4",
"FixedVersion": "3.6.7-4+deb10u7",
"Layer": {
"Digest": "sha256:000eee12ec04cc914bf96e8f5dee7767510c2aca3816af6078bd9fbe3150920c",
"DiffID": "sha256:831c5620387fb9efec59fc82a42b948546c6be601e3ab34a87108ecf852aa15f"
},
"SeveritySource": "nvd",
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2021-20231",
"Title": "gnutls: Use after free in client key_share extension",
"Description": "A flaw was found in gnutls. A use after free issue in client sending key_share extension may lead to memory corruption and other consequences.",
"Severity": "CRITICAL",
"CweIDs": [
"CWE-416"
],
"CVSS": {
"nvd": {
"V2Vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P",
"V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"V2Score": 7.5,
"V3Score": 9.8
},
"redhat": {
"V3Vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L",
"V3Score": 3.7
}
},
"References": [
"https://bugzilla.redhat.com/show_bug.cgi?id=1922276"
],
"PublishedDate": "2021-03-12T19:15:00Z",
"LastModifiedDate": "2021-06-01T14:07:00Z"
}
]
},
{
"Target": "Ruby",
"Class": "lang-pkgs",
"Type": "gemspec",
"Packages": [
{
"Name": "activesupport",
"Version": "6.0.2.1",
"License": "MIT",
"Layer": {
"Digest": "sha256:a8877cad19f14a7044524a145ce33170085441a7922458017db1631dcd5f7602",
"DiffID": "sha256:75e43d55939745950bc3f8fad56c5834617c4339f0f54755e69a0dd5372624e9"
},
"FilePath": "var/lib/gems/2.5.0/specifications/activesupport-6.0.2.1.gemspec"
}
],
"Vulnerabilities": [
{
"VulnerabilityID": "CVE-2020-8165",
"PkgName": "activesupport",
"PkgPath": "var/lib/gems/2.5.0/specifications/activesupport-6.0.2.1.gemspec",
"InstalledVersion": "6.0.2.1",
"FixedVersion": "6.0.3.1, 5.2.4.3",
"Layer": {
"Digest": "sha256:a8877cad19f14a7044524a145ce33170085441a7922458017db1631dcd5f7602",
"DiffID": "sha256:75e43d55939745950bc3f8fad56c5834617c4339f0f54755e69a0dd5372624e9"
},
"SeveritySource": "nvd",
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2020-8165",
"Title": "rubygem-activesupport: potentially unintended unmarshalling of user-provided objects in MemCacheStore and RedisCacheStore",
"Description": "A deserialization of untrusted data vulnernerability exists in rails \u003c 5.2.4.3, rails \u003c 6.0.3.1 that can allow an attacker to unmarshal user-provided objects in MemCacheStore and RedisCacheStore potentially resulting in an RCE.",
"Severity": "CRITICAL",
"CweIDs": [
"CWE-502"
],
"CVSS": {
"nvd": {
"V2Vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P",
"V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"V2Score": 7.5,
"V3Score": 9.8
},
"redhat": {
"V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"V3Score": 9.8
}
},
"References": [
"https://www.debian.org/security/2020/dsa-4766"
],
"PublishedDate": "2020-06-19T18:15:00Z",
"LastModifiedDate": "2020-10-17T12:15:00Z"
}
]
}
]
}`)
var osAndLibSR = &models.ScanResult{
JSONVersion: 4,
ServerName: "quay.io/fluentd_elasticsearch/fluentd:v2.9.0 (debian 10.2)",
Family: "debian",
ScannedBy: "trivy",
ScannedVia: "trivy",
ScannedCves: models.VulnInfos{
"CVE-2021-20231": {
CveID: "CVE-2021-20231",
Confidences: models.Confidences{
models.Confidence{
Score: 100,
DetectionMethod: "TrivyMatch",
},
},
AffectedPackages: models.PackageFixStatuses{
models.PackageFixStatus{
Name: "libgnutls30",
NotFixedYet: false,
FixState: "",
FixedIn: "3.6.7-4+deb10u7",
}},
CveContents: models.CveContents{
"trivy": []models.CveContent{{
Title: "gnutls: Use after free in client key_share extension",
Summary: "A flaw was found in gnutls. A use after free issue in client sending key_share extension may lead to memory corruption and other consequences.",
Cvss3Severity: "CRITICAL",
References: models.References{
{Source: "trivy", Link: "https://bugzilla.redhat.com/show_bug.cgi?id=1922276"},
},
}},
},
LibraryFixedIns: models.LibraryFixedIns{},
},
"CVE-2020-8165": {
CveID: "CVE-2020-8165",
Confidences: models.Confidences{
models.Confidence{
Score: 100,
DetectionMethod: "TrivyMatch",
},
},
AffectedPackages: models.PackageFixStatuses{},
CveContents: models.CveContents{
"trivy": []models.CveContent{{
Title: "rubygem-activesupport: potentially unintended unmarshalling of user-provided objects in MemCacheStore and RedisCacheStore",
Summary: "A deserialization of untrusted data vulnernerability exists in rails \u003c 5.2.4.3, rails \u003c 6.0.3.1 that can allow an attacker to unmarshal user-provided objects in MemCacheStore and RedisCacheStore potentially resulting in an RCE.",
Cvss3Severity: "CRITICAL",
References: models.References{
{Source: "trivy", Link: "https://www.debian.org/security/2020/dsa-4766"},
},
}},
},
LibraryFixedIns: models.LibraryFixedIns{
models.LibraryFixedIn{
Key: "gemspec",
Name: "activesupport",
FixedIn: "6.0.3.1, 5.2.4.3",
Path: "Ruby",
},
},
},
},
LibraryScanners: models.LibraryScanners{
models.LibraryScanner{
Type: "gemspec",
LockfilePath: "Ruby",
Libs: []models.Library{
{
Name: "activesupport",
Version: "6.0.2.1",
FilePath: "var/lib/gems/2.5.0/specifications/activesupport-6.0.2.1.gemspec",
},
},
},
},
Packages: models.Packages{
"libgnutls30": models.Package{
Name: "libgnutls30",
Version: "3.6.7-4",
},
},
SrcPackages: models.SrcPackages{
"gnutls28": models.SrcPackage{
Name: "gnutls28",
Version: "3.6.7-4",
BinaryNames: []string{"libgnutls30"},
},
},
Optional: map[string]interface{}{
"trivy-target": "quay.io/fluentd_elasticsearch/fluentd:v2.9.0 (debian 10.2)",
},
}

View File

@@ -0,0 +1,226 @@
package pkg
import (
"sort"
"time"
ftypes "github.com/aquasecurity/fanal/types"
"github.com/aquasecurity/fanal/analyzer/os"
"github.com/aquasecurity/trivy/pkg/report"
"github.com/future-architect/vuls/models"
)
// Convert :
func Convert(results report.Results) (result *models.ScanResult, err error) {
scanResult := &models.ScanResult{
JSONVersion: models.JSONVersion,
ScannedCves: models.VulnInfos{},
}
pkgs := models.Packages{}
srcPkgs := models.SrcPackages{}
vulnInfos := models.VulnInfos{}
uniqueLibraryScannerPaths := map[string]models.LibraryScanner{}
for _, trivyResult := range results {
for _, vuln := range trivyResult.Vulnerabilities {
if _, ok := vulnInfos[vuln.VulnerabilityID]; !ok {
vulnInfos[vuln.VulnerabilityID] = models.VulnInfo{
CveID: vuln.VulnerabilityID,
Confidences: models.Confidences{
{
Score: 100,
DetectionMethod: models.TrivyMatchStr,
},
},
AffectedPackages: models.PackageFixStatuses{},
CveContents: models.CveContents{},
LibraryFixedIns: models.LibraryFixedIns{},
// VulnType : "",
}
}
vulnInfo := vulnInfos[vuln.VulnerabilityID]
var notFixedYet bool
fixState := ""
if len(vuln.FixedVersion) == 0 {
notFixedYet = true
fixState = "Affected"
}
var references models.References
for _, reference := range vuln.References {
references = append(references, models.Reference{
Source: "trivy",
Link: reference,
})
}
sort.Slice(references, func(i, j int) bool {
return references[i].Link < references[j].Link
})
var published time.Time
if vuln.PublishedDate != nil {
published = *vuln.PublishedDate
}
var lastModified time.Time
if vuln.LastModifiedDate != nil {
lastModified = *vuln.LastModifiedDate
}
vulnInfo.CveContents = models.CveContents{
models.Trivy: []models.CveContent{{
Cvss3Severity: vuln.Severity,
References: references,
Title: vuln.Title,
Summary: vuln.Description,
Published: published,
LastModified: lastModified,
}},
}
// do onlyIif image type is Vuln
if IsTrivySupportedOS(trivyResult.Type) {
pkgs[vuln.PkgName] = models.Package{
Name: vuln.PkgName,
Version: vuln.InstalledVersion,
}
vulnInfo.AffectedPackages = append(vulnInfo.AffectedPackages, models.PackageFixStatus{
Name: vuln.PkgName,
NotFixedYet: notFixedYet,
FixState: fixState,
FixedIn: vuln.FixedVersion,
})
} else {
vulnInfo.LibraryFixedIns = append(vulnInfo.LibraryFixedIns, models.LibraryFixedIn{
Key: trivyResult.Type,
Name: vuln.PkgName,
Path: trivyResult.Target,
FixedIn: vuln.FixedVersion,
})
libScanner := uniqueLibraryScannerPaths[trivyResult.Target]
libScanner.Type = trivyResult.Type
libScanner.Libs = append(libScanner.Libs, models.Library{
Name: vuln.PkgName,
Version: vuln.InstalledVersion,
FilePath: vuln.PkgPath,
})
uniqueLibraryScannerPaths[trivyResult.Target] = libScanner
}
vulnInfos[vuln.VulnerabilityID] = vulnInfo
}
// --list-all-pkgs flg of trivy will output all installed packages, so collect them.
if trivyResult.Class == report.ClassOSPkg {
for _, p := range trivyResult.Packages {
pkgs[p.Name] = models.Package{
Name: p.Name,
Version: p.Version,
}
if p.Name != p.SrcName {
if v, ok := srcPkgs[p.SrcName]; !ok {
srcPkgs[p.SrcName] = models.SrcPackage{
Name: p.SrcName,
Version: p.SrcVersion,
BinaryNames: []string{p.Name},
}
} else {
v.AddBinaryName(p.Name)
srcPkgs[p.SrcName] = v
}
}
}
} else if trivyResult.Class == report.ClassLangPkg {
libScanner := uniqueLibraryScannerPaths[trivyResult.Target]
libScanner.Type = trivyResult.Type
for _, p := range trivyResult.Packages {
libScanner.Libs = append(libScanner.Libs, models.Library{
Name: p.Name,
Version: p.Version,
FilePath: p.FilePath,
})
}
uniqueLibraryScannerPaths[trivyResult.Target] = libScanner
}
}
// flatten and unique libraries
libraryScanners := make([]models.LibraryScanner, 0, len(uniqueLibraryScannerPaths))
for path, v := range uniqueLibraryScannerPaths {
uniqueLibrary := map[string]models.Library{}
for _, lib := range v.Libs {
uniqueLibrary[lib.Name+lib.Version] = lib
}
var libraries []models.Library
for _, library := range uniqueLibrary {
libraries = append(libraries, library)
}
sort.Slice(libraries, func(i, j int) bool {
return libraries[i].Name < libraries[j].Name
})
libscanner := models.LibraryScanner{
Type: v.Type,
LockfilePath: path,
Libs: libraries,
}
libraryScanners = append(libraryScanners, libscanner)
}
sort.Slice(libraryScanners, func(i, j int) bool {
return libraryScanners[i].LockfilePath < libraryScanners[j].LockfilePath
})
scanResult.ScannedCves = vulnInfos
scanResult.Packages = pkgs
scanResult.SrcPackages = srcPkgs
scanResult.LibraryScanners = libraryScanners
return scanResult, nil
}
// IsTrivySupportedOS :
func IsTrivySupportedOS(family string) bool {
supportedFamilies := map[string]interface{}{
os.RedHat: struct{}{},
os.Debian: struct{}{},
os.Ubuntu: struct{}{},
os.CentOS: struct{}{},
os.Rocky: struct{}{},
os.Alma: struct{}{},
os.Fedora: struct{}{},
os.Amazon: struct{}{},
os.Oracle: struct{}{},
os.Windows: struct{}{},
os.OpenSUSE: struct{}{},
os.OpenSUSELeap: struct{}{},
os.OpenSUSETumbleweed: struct{}{},
os.SLES: struct{}{},
os.Photon: struct{}{},
os.Alpine: struct{}{},
}
_, ok := supportedFamilies[family]
return ok
}
// IsTrivySupportedLib :
func IsTrivySupportedLib(typestr string) bool {
supportedLibs := map[string]interface{}{
ftypes.Bundler: struct{}{},
ftypes.GemSpec: struct{}{},
ftypes.Cargo: struct{}{},
ftypes.Composer: struct{}{},
ftypes.Npm: struct{}{},
ftypes.NuGet: struct{}{},
ftypes.Pip: struct{}{},
ftypes.Pipenv: struct{}{},
ftypes.Poetry: struct{}{},
ftypes.PythonPkg: struct{}{},
ftypes.NodePkg: struct{}{},
ftypes.Yarn: struct{}{},
ftypes.Jar: struct{}{},
ftypes.GoBinary: struct{}{},
ftypes.GoMod: struct{}{},
}
_, ok := supportedLibs[typestr]
return ok
}

View File

@@ -16,9 +16,9 @@ import (
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/util"
cvedb "github.com/kotakanbe/go-cve-dictionary/db"
cvelog "github.com/kotakanbe/go-cve-dictionary/log"
cvemodels "github.com/kotakanbe/go-cve-dictionary/models"
cvedb "github.com/vulsio/go-cve-dictionary/db"
cvelog "github.com/vulsio/go-cve-dictionary/log"
cvemodels "github.com/vulsio/go-cve-dictionary/models"
)
type goCveDictClient struct {
@@ -27,7 +27,7 @@ type goCveDictClient struct {
}
func newGoCveDictClient(cnf config.VulnDictInterface, o logging.LogOpts) (*goCveDictClient, error) {
if err := cvelog.SetLogger(o.LogToFile, o.LogDir, o.Debug, false); err != nil {
if err := cvelog.SetLogger(o.LogToFile, o.LogDir, o.Debug, o.LogJSON); err != nil {
return nil, err
}
@@ -44,21 +44,18 @@ func (api goCveDictClient) closeDB() error {
if api.driver == nil {
return nil
}
if err := api.driver.CloseDB(); err != nil {
return xerrors.Errorf("Failed to close DB: %+v", err)
}
return nil
return api.driver.CloseDB()
}
func (api goCveDictClient) fetchCveDetails(cveIDs []string) (cveDetails []cvemodels.CveDetail, err error) {
for _, cveID := range cveIDs {
cveDetail, err := api.driver.Get(cveID)
if err != nil {
return nil, xerrors.Errorf("Failed to fetch CVE. err: %w", err)
}
cveDetails = append(cveDetails, *cveDetail)
m, err := api.driver.GetMulti(cveIDs)
if err != nil {
return nil, xerrors.Errorf("Failed to GetMulti. err: %w", err)
}
return
for _, v := range m {
cveDetails = append(cveDetails, v)
}
return cveDetails, nil
}
type response struct {
@@ -156,7 +153,7 @@ func (api goCveDictClient) detectCveByCpeURI(cpeURI string, useJVN bool) (cves [
query := map[string]string{"name": cpeURI}
logging.Log.Debugf("HTTP Request to %s, query: %#v", url, query)
if cves, err = api.httpPost(cpeURI, url, query); err != nil {
if cves, err = api.httpPost(url, query); err != nil {
return nil, err
}
} else {
@@ -180,7 +177,7 @@ func (api goCveDictClient) detectCveByCpeURI(cpeURI string, useJVN bool) (cves [
return nvdCves, nil
}
func (api goCveDictClient) httpPost(key, url string, query map[string]string) ([]cvemodels.CveDetail, error) {
func (api goCveDictClient) httpPost(url string, query map[string]string) ([]cvemodels.CveDetail, error) {
var body string
var errs []error
var resp *http.Response

View File

@@ -18,7 +18,7 @@ import (
"github.com/future-architect/vuls/oval"
"github.com/future-architect/vuls/reporter"
"github.com/future-architect/vuls/util"
cvemodels "github.com/kotakanbe/go-cve-dictionary/models"
cvemodels "github.com/vulsio/go-cve-dictionary/models"
"golang.org/x/xerrors"
)
@@ -145,9 +145,23 @@ func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
}
for i, r := range rs {
r.ScannedCves = r.ScannedCves.FilterByCvssOver(config.Conf.CvssScoreOver)
r.ScannedCves = r.ScannedCves.FilterUnfixed(config.Conf.IgnoreUnfixed)
r.ScannedCves = r.ScannedCves.FilterByConfidenceOver(config.Conf.ConfidenceScoreOver)
nFiltered := 0
logging.Log.Infof("%s: total %d CVEs detected", r.FormatServerName(), len(r.ScannedCves))
if 0 < config.Conf.CvssScoreOver {
r.ScannedCves, nFiltered = r.ScannedCves.FilterByCvssOver(config.Conf.CvssScoreOver)
logging.Log.Infof("%s: %d CVEs filtered by --cvss-over=%d", r.FormatServerName(), nFiltered, config.Conf.CvssScoreOver)
}
if config.Conf.IgnoreUnfixed {
r.ScannedCves, nFiltered = r.ScannedCves.FilterUnfixed(config.Conf.IgnoreUnfixed)
logging.Log.Infof("%s: %d CVEs filtered by --ignore-unfixed=%d", r.FormatServerName(), nFiltered)
}
if 0 < config.Conf.ConfidenceScoreOver {
r.ScannedCves, nFiltered = r.ScannedCves.FilterByConfidenceOver(config.Conf.ConfidenceScoreOver)
logging.Log.Infof("%s: %d CVEs filtered by --confidence-over=%d", r.FormatServerName(), nFiltered, config.Conf.ConfidenceScoreOver)
}
// IgnoreCves
ignoreCves := []string{}
@@ -156,7 +170,10 @@ func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
} else if con, ok := config.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {
ignoreCves = con.IgnoreCves
}
r.ScannedCves = r.ScannedCves.FilterIgnoreCves(ignoreCves)
if 0 < len(ignoreCves) {
r.ScannedCves, nFiltered = r.ScannedCves.FilterIgnoreCves(ignoreCves)
logging.Log.Infof("%s: %d CVEs filtered by ignoreCves=%s", r.FormatServerName(), nFiltered, ignoreCves)
}
// ignorePkgs
ignorePkgsRegexps := []string{}
@@ -165,11 +182,15 @@ func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
} else if s, ok := config.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok {
ignorePkgsRegexps = s.IgnorePkgsRegexp
}
r.ScannedCves = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)
if 0 < len(ignorePkgsRegexps) {
r.ScannedCves, nFiltered = r.ScannedCves.FilterIgnorePkgs(ignorePkgsRegexps)
logging.Log.Infof("%s: %d CVEs filtered by ignorePkgsRegexp=%s", r.FormatServerName(), nFiltered, ignorePkgsRegexps)
}
// IgnoreUnscored
if config.Conf.IgnoreUnscoredCves {
r.ScannedCves = r.ScannedCves.FindScoredVulns()
r.ScannedCves, nFiltered = r.ScannedCves.FindScoredVulns()
logging.Log.Infof("%s: %d CVEs filtered by --ignore-unscored-cves=%s", r.FormatServerName(), nFiltered, config.Conf.IgnoreUnscoredCves)
}
r.FilterInactiveWordPressLibs(config.Conf.WpScan.DetectInactive)
@@ -202,7 +223,7 @@ func DetectPkgCves(r *models.ScanResult, ovalCnf config.GovalDictConf, gostCnf c
} else if r.Family == constant.ServerTypePseudo {
logging.Log.Infof("pseudo type. Skip OVAL and gost detection")
} else {
return xerrors.Errorf("Failed to fill CVEs. r.Release is empty")
logging.Log.Infof("r.Release is empty. detect as pseudo type. Skip OVAL and gost detection")
}
for i, v := range r.ScannedCves {
@@ -307,9 +328,23 @@ func FillCvesWithNvdJvn(r *models.ScanResult, cnf config.GoCveDictConf, logOpts
if vinfo.CveContents == nil {
vinfo.CveContents = models.CveContents{}
}
for _, con := range append(nvds, jvns...) {
for _, con := range nvds {
if !con.Empty() {
vinfo.CveContents[con.Type] = append(vinfo.CveContents[con.Type], con)
vinfo.CveContents[con.Type] = []models.CveContent{con}
}
}
for _, con := range jvns {
if !con.Empty() {
found := false
for _, cveCont := range vinfo.CveContents[con.Type] {
if con.SourceLink == cveCont.SourceLink {
found = true
break
}
}
if !found {
vinfo.CveContents[con.Type] = append(vinfo.CveContents[con.Type], con)
}
}
}
vinfo.AlertDict = alerts
@@ -364,11 +399,11 @@ func detectPkgsCvesWithOval(cnf config.GovalDictConf, r *models.ScanResult) erro
}
if !ok {
if r.Family == constant.Debian {
logging.Log.Debug("Skip OVAL and Scan with gost alone.")
logging.Log.Infof("Skip OVAL and Scan with gost alone.")
logging.Log.Infof("%s: %d CVEs are detected with OVAL", r.FormatServerName(), 0)
return nil
}
return xerrors.Errorf("OVAL entries of %s %s are not found. Fetch OVAL before reporting. For details, see `https://github.com/kotakanbe/goval-dictionary#usage`", r.Family, r.Release)
return xerrors.Errorf("OVAL entries of %s %s are not found. Fetch OVAL before reporting. For details, see `https://github.com/vulsio/goval-dictionary#usage`", r.Family, r.Release)
}
logging.Log.Debugf("Check if oval fresh: %s %s", r.Family, r.Release)

View File

@@ -8,7 +8,7 @@ import (
"testing"
"github.com/future-architect/vuls/models"
cvemodels "github.com/kotakanbe/go-cve-dictionary/models"
cvemodels "github.com/vulsio/go-cve-dictionary/models"
)
func Test_getMaxConfidence(t *testing.T) {

View File

@@ -28,7 +28,7 @@ func FillWithExploit(r *models.ScanResult, cnf config.ExploitConf) (nExploitCve
cveIDs = append(cveIDs, cveID)
}
prefix, _ := util.URLPathJoin(cnf.GetURL(), "cves")
responses, err := getCvesViaHTTP(cveIDs, prefix)
responses, err := getExploitsViaHTTP(cveIDs, prefix)
if err != nil {
return 0, err
}
@@ -37,7 +37,7 @@ func FillWithExploit(r *models.ScanResult, cnf config.ExploitConf) (nExploitCve
if err := json.Unmarshal([]byte(res.json), &exps); err != nil {
return 0, err
}
exploits := ConvertToModels(exps)
exploits := ConvertToModelsExploit(exps)
v, ok := r.ScannedCves[res.request.cveID]
if ok {
v.Exploits = exploits
@@ -46,7 +46,6 @@ func FillWithExploit(r *models.ScanResult, cnf config.ExploitConf) (nExploitCve
nExploitCve++
}
} else {
driver, locked, err := newExploitDB(&cnf)
if locked {
return 0, xerrors.Errorf("SQLite3 is locked: %s", cnf.GetSQLite3Path())
@@ -63,11 +62,14 @@ func FillWithExploit(r *models.ScanResult, cnf config.ExploitConf) (nExploitCve
if cveID == "" {
continue
}
es := driver.GetExploitByCveID(cveID)
es, err := driver.GetExploitByCveID(cveID)
if err != nil {
return 0, err
}
if len(es) == 0 {
continue
}
exploits := ConvertToModels(es)
exploits := ConvertToModelsExploit(es)
vuln.Exploits = exploits
r.ScannedCves[cveID] = vuln
nExploitCve++
@@ -76,8 +78,8 @@ func FillWithExploit(r *models.ScanResult, cnf config.ExploitConf) (nExploitCve
return nExploitCve, nil
}
// ConvertToModels converts gost model to vuls model
func ConvertToModels(es []exploitmodels.Exploit) (exploits []models.Exploit) {
// ConvertToModelsExploit converts exploit model to vuls model
func ConvertToModelsExploit(es []exploitmodels.Exploit) (exploits []models.Exploit) {
for _, e := range es {
var documentURL, shellURL *string
if e.OffensiveSecurity != nil {
@@ -103,14 +105,14 @@ func ConvertToModels(es []exploitmodels.Exploit) (exploits []models.Exploit) {
}
type exploitResponse struct {
request request
request exploitRequest
json string
}
func getCvesViaHTTP(cveIDs []string, urlPrefix string) (
func getExploitsViaHTTP(cveIDs []string, urlPrefix string) (
responses []exploitResponse, err error) {
nReq := len(cveIDs)
reqChan := make(chan request, nReq)
reqChan := make(chan exploitRequest, nReq)
resChan := make(chan exploitResponse, nReq)
errChan := make(chan error, nReq)
defer close(reqChan)
@@ -119,7 +121,7 @@ func getCvesViaHTTP(cveIDs []string, urlPrefix string) (
go func() {
for _, cveID := range cveIDs {
reqChan <- request{
reqChan <- exploitRequest{
cveID: cveID,
}
}
@@ -129,18 +131,16 @@ func getCvesViaHTTP(cveIDs []string, urlPrefix string) (
tasks := util.GenWorkers(concurrency)
for i := 0; i < nReq; i++ {
tasks <- func() {
select {
case req := <-reqChan:
url, err := util.URLPathJoin(
urlPrefix,
req.cveID,
)
if err != nil {
errChan <- err
} else {
logging.Log.Debugf("HTTP Request to %s", url)
httpGet(url, req, resChan, errChan)
}
req := <-reqChan
url, err := util.URLPathJoin(
urlPrefix,
req.cveID,
)
if err != nil {
errChan <- err
} else {
logging.Log.Debugf("HTTP Request to %s", url)
httpGetExploit(url, req, resChan, errChan)
}
}
}
@@ -154,23 +154,20 @@ func getCvesViaHTTP(cveIDs []string, urlPrefix string) (
case err := <-errChan:
errs = append(errs, err)
case <-timeout:
return nil, xerrors.New("Timeout Fetching OVAL")
return nil, xerrors.New("Timeout Fetching Exploit")
}
}
if len(errs) != 0 {
return nil, xerrors.Errorf("Failed to fetch OVAL. err: %w", errs)
return nil, xerrors.Errorf("Failed to fetch Exploit. err: %w", errs)
}
return
}
type request struct {
osMajorVersion string
packName string
isSrcPack bool
cveID string
type exploitRequest struct {
cveID string
}
func httpGet(url string, req request, resChan chan<- exploitResponse, errChan chan<- error) {
func httpGetExploit(url string, req exploitRequest, resChan chan<- exploitResponse, errChan chan<- error) {
var body string
var errs []error
var resp *http.Response

View File

@@ -126,7 +126,7 @@ func DetectGitHubSecurityAlerts(r *models.ScanResult, owner, repo, token string,
if val, ok := r.ScannedCves[cveID]; ok {
val.GitHubSecurityAlerts = val.GitHubSecurityAlerts.Add(m)
val.CveContents[models.GitHub] = append(val.CveContents[models.GitHub], cveContent)
val.CveContents[models.GitHub] = []models.CveContent{cveContent}
r.ScannedCves[cveID] = val
} else {
v := models.VulnInfo{

View File

@@ -4,47 +4,182 @@
package detector
import (
"encoding/json"
"net/http"
"time"
"github.com/cenkalti/backoff"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
metasploitdb "github.com/takuzoo3868/go-msfdb/db"
metasploitmodels "github.com/takuzoo3868/go-msfdb/models"
"github.com/future-architect/vuls/util"
"github.com/parnurzeal/gorequest"
metasploitdb "github.com/vulsio/go-msfdb/db"
metasploitmodels "github.com/vulsio/go-msfdb/models"
"golang.org/x/xerrors"
)
// FillWithMetasploit fills metasploit module information that has in module
func FillWithMetasploit(r *models.ScanResult, cnf config.MetasploitConf) (nMetasploitCve int, err error) {
if cnf.IsFetchViaHTTP() {
var cveIDs []string
for cveID := range r.ScannedCves {
cveIDs = append(cveIDs, cveID)
}
prefix, err := util.URLPathJoin(cnf.GetURL(), "cves")
if err != nil {
return 0, err
}
responses, err := getMetasploitsViaHTTP(cveIDs, prefix)
if err != nil {
return 0, err
}
for _, res := range responses {
msfs := []metasploitmodels.Metasploit{}
if err := json.Unmarshal([]byte(res.json), &msfs); err != nil {
return 0, err
}
metasploits := ConvertToModelsMsf(msfs)
v, ok := r.ScannedCves[res.request.cveID]
if ok {
v.Metasploits = metasploits
}
r.ScannedCves[res.request.cveID] = v
nMetasploitCve++
}
} else {
driver, locked, err := newMetasploitDB(&cnf)
if locked {
return 0, xerrors.Errorf("SQLite3 is locked: %s", cnf.GetSQLite3Path())
} else if err != nil {
return 0, err
}
defer func() {
if err := driver.CloseDB(); err != nil {
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
}()
driver, locked, err := newMetasploitDB(&cnf)
if locked {
return 0, xerrors.Errorf("SQLite3 is locked: %s", cnf.GetSQLite3Path())
} else if err != nil {
return 0, err
for cveID, vuln := range r.ScannedCves {
if cveID == "" {
continue
}
ms, err := driver.GetModuleByCveID(cveID)
if err != nil {
return 0, err
}
if len(ms) == 0 {
continue
}
modules := ConvertToModelsMsf(ms)
vuln.Metasploits = modules
r.ScannedCves[cveID] = vuln
nMetasploitCve++
}
}
defer func() {
if err := driver.CloseDB(); err != nil {
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
}()
for cveID, vuln := range r.ScannedCves {
if cveID == "" {
continue
}
ms := driver.GetModuleByCveID(cveID)
if len(ms) == 0 {
continue
}
modules := ConvertToModelsMsf(ms)
vuln.Metasploits = modules
r.ScannedCves[cveID] = vuln
nMetasploitCve++
}
return nMetasploitCve, nil
}
// ConvertToModelsMsf converts gost model to vuls model
type metasploitResponse struct {
request metasploitRequest
json string
}
func getMetasploitsViaHTTP(cveIDs []string, urlPrefix string) (
responses []metasploitResponse, err error) {
nReq := len(cveIDs)
reqChan := make(chan metasploitRequest, nReq)
resChan := make(chan metasploitResponse, nReq)
errChan := make(chan error, nReq)
defer close(reqChan)
defer close(resChan)
defer close(errChan)
go func() {
for _, cveID := range cveIDs {
reqChan <- metasploitRequest{
cveID: cveID,
}
}
}()
concurrency := 10
tasks := util.GenWorkers(concurrency)
for i := 0; i < nReq; i++ {
tasks <- func() {
req := <-reqChan
url, err := util.URLPathJoin(
urlPrefix,
req.cveID,
)
if err != nil {
errChan <- err
} else {
logging.Log.Debugf("HTTP Request to %s", url)
httpGetMetasploit(url, req, resChan, errChan)
}
}
}
timeout := time.After(2 * 60 * time.Second)
var errs []error
for i := 0; i < nReq; i++ {
select {
case res := <-resChan:
responses = append(responses, res)
case err := <-errChan:
errs = append(errs, err)
case <-timeout:
return nil, xerrors.New("Timeout Fetching Metasploit")
}
}
if len(errs) != 0 {
return nil, xerrors.Errorf("Failed to fetch Metasploit. err: %w", errs)
}
return
}
type metasploitRequest struct {
cveID string
}
func httpGetMetasploit(url string, req metasploitRequest, resChan chan<- metasploitResponse, errChan chan<- error) {
var body string
var errs []error
var resp *http.Response
count, retryMax := 0, 3
f := func() (err error) {
// resp, body, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End()
resp, body, errs = gorequest.New().Timeout(10 * time.Second).Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
count++
if count == retryMax {
return nil
}
return xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %+v", url, resp, errs)
}
return nil
}
notify := func(err error, t time.Duration) {
logging.Log.Warnf("Failed to HTTP GET. retrying in %s seconds. err: %+v", t, err)
}
err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify)
if err != nil {
errChan <- xerrors.Errorf("HTTP Error %w", err)
return
}
if count == retryMax {
errChan <- xerrors.New("Retry count exceeded")
return
}
resChan <- metasploitResponse{
request: req,
json: body,
}
}
// ConvertToModelsMsf converts metasploit model to vuls model
func ConvertToModelsMsf(ms []metasploitmodels.Metasploit) (modules []models.Metasploit) {
for _, m := range ms {
var links []string

View File

@@ -68,10 +68,9 @@ func loadPrevious(currs models.ScanResults, resultsDir string) (prevs models.Sca
prevs = append(prevs, *r)
logging.Log.Infof("Previous json found: %s", path)
break
} else {
logging.Log.Infof("Previous json is different family.Release: %s, pre: %s.%s cur: %s.%s",
path, r.Family, r.Release, result.Family, result.Release)
}
logging.Log.Infof("Previous json is different family.Release: %s, pre: %s.%s cur: %s.%s",
path, r.Family, r.Release, result.Family, result.Release)
}
}
return prevs, nil
@@ -145,7 +144,7 @@ func getPlusDiffCves(previous, current models.ScanResult) models.VulnInfos {
// TODO commented out because a bug of diff logic when multiple oval defs found for a certain CVE-ID and same updated_at
// if these OVAL defs have different affected packages, this logic detects as updated.
// This logic will be uncomented after integration with gost https://github.com/knqyf263/gost
// This logic will be uncomented after integration with gost https://github.com/vulsio/gost
// } else if isCveFixed(v, previous) {
// updated[v.CveID] = v
// logging.Log.Debugf("fixed: %s", v.CveID)

89
go.mod
View File

@@ -4,14 +4,14 @@ go 1.17
require (
github.com/Azure/azure-sdk-for-go v50.2.0+incompatible
github.com/BurntSushi/toml v0.3.1
github.com/BurntSushi/toml v0.4.1
github.com/Ullaakut/nmap/v2 v2.1.2-0.20210406060955-59a52fe80a4f
github.com/VividCortex/ewma v1.2.0 // indirect
github.com/aquasecurity/fanal v0.0.0-20210719144537-c73c1e9f21bf
github.com/aquasecurity/trivy v0.19.2
github.com/aquasecurity/trivy-db v0.0.0-20210531102723-aaab62dec6ee
github.com/aquasecurity/fanal v0.0.0-20211005172059-69527b46560c
github.com/aquasecurity/trivy v0.20.0
github.com/aquasecurity/trivy-db v0.0.0-20210916043317-726b7b72a47b
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
github.com/aws/aws-sdk-go v1.37.0
github.com/aws/aws-sdk-go v1.40.49
github.com/boltdb/bolt v1.3.1
github.com/briandowns/spinner v1.16.0 // indirect
github.com/cenkalti/backoff v2.2.1+incompatible
@@ -20,28 +20,24 @@ require (
github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21
github.com/emersion/go-smtp v0.14.0
github.com/fatih/color v1.12.0 // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/go-redis/redis/v8 v8.11.3 // indirect
github.com/go-redis/redis/v8 v8.11.4 // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/google/subcommands v1.2.0
github.com/gosuri/uitable v0.0.4
github.com/hashicorp/go-uuid v1.0.2
github.com/hashicorp/go-version v1.3.0
github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c
github.com/jackc/pgx/v4 v4.13.0 // indirect
github.com/jesseduffield/gocui v0.3.0
github.com/k0kubun/pp v3.0.1+incompatible
github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f
github.com/knqyf263/go-cpe v0.0.0-20201213041631-54f6ab28673f
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d
github.com/knqyf263/go-rpm-version v0.0.0-20170716094938-74609b86c936
github.com/knqyf263/gost v0.2.0
github.com/kotakanbe/go-cve-dictionary v0.7.2-0.20210907024016-69922490c76a
github.com/kotakanbe/go-pingscanner v0.1.0
github.com/kotakanbe/goval-dictionary v0.3.6-0.20210625044258-9be85404d7dd
github.com/kotakanbe/logrus-prefixed-formatter v0.0.0-20180123152602-928f7356cb96
github.com/mattn/go-isatty v0.0.13 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mitchellh/go-homedir v1.1.0
@@ -49,57 +45,68 @@ require (
github.com/nsf/termbox-go v0.0.0-20200418040025-38ba6e5628f1 // indirect
github.com/olekukonko/tablewriter v0.0.5
github.com/parnurzeal/gorequest v0.2.16
github.com/pelletier/go-toml v1.9.4 // indirect
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5
github.com/sirupsen/logrus v1.8.0
github.com/sirupsen/logrus v1.8.1
github.com/spf13/afero v1.6.0
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/cobra v1.2.1
github.com/takuzoo3868/go-msfdb v0.1.6
github.com/vulsio/go-exploitdb v0.2.0
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
golang.org/x/net v0.0.0-20210902165921-8d991716f632 // indirect
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602
github.com/vulsio/go-cve-dictionary v0.8.2-0.20211013020338-ec22aa70ffdb
github.com/vulsio/go-exploitdb v0.4.2-0.20210930235136-c10d2716b7e2
github.com/vulsio/go-msfdb v0.2.1-0.20210928020521-9b56a938f544
github.com/vulsio/gost v0.4.1-0.20210928234623-3e6372ba2821
github.com/vulsio/goval-dictionary v0.6.1
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
golang.org/x/net v0.0.0-20211011170408-caeb26a5c8c0 // indirect
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/text v0.3.7 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
gopkg.in/ini.v1 v1.63.2 // indirect
gorm.io/driver/mysql v1.1.2 // indirect
gorm.io/gorm v1.21.14 // indirect
gorm.io/driver/postgres v1.1.2 // indirect
gorm.io/driver/sqlite v1.1.6 // indirect
k8s.io/utils v0.0.0-20210111153108-fddb29f9d009
)
require (
github.com/Azure/go-autorest/autorest v0.10.2 // indirect
github.com/Azure/go-autorest/autorest/adal v0.8.3 // indirect
github.com/Azure/go-autorest/autorest/date v0.2.0 // indirect
github.com/Azure/go-autorest/logger v0.1.0 // indirect
github.com/Azure/go-autorest/tracing v0.5.0 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest v0.11.1 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.5 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/logger v0.2.0 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver v1.5.0 // indirect
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
github.com/aquasecurity/go-dep-parser v0.0.0-20210520015931-0dd56983cc62 // indirect
github.com/PuerkitoBio/goquery v1.7.1 // indirect
github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/aquasecurity/go-dep-parser v0.0.0-20210919151457-76db061b9305 // indirect
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce // indirect
github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798 // indirect
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 // indirect
github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492 // indirect
github.com/caarlos0/env/v6 v6.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/go-redis/redis v6.15.9+incompatible // indirect
github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-containerregistry v0.6.0 // indirect
github.com/google/go-github/v33 v33.0.0 // indirect
github.com/google/go-querystring v1.0.0 // indirect
github.com/google/uuid v1.2.0 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/google/wire v0.4.0 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/grokify/html-strip-tags-go v0.0.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.1 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/htcat/htcat v1.0.2 // indirect
github.com/huandu/xstrings v1.3.2 // indirect
github.com/imdario/mergo v0.3.9 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
@@ -109,45 +116,39 @@ require (
github.com/jackc/pgproto3/v2 v2.1.1 // indirect
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
github.com/jackc/pgtype v1.8.1 // indirect
github.com/jackc/pgx/v4 v4.13.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.2 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/labstack/gommon v0.3.0 // indirect
github.com/magefile/mage v1.11.0 // indirect
github.com/magiconair/properties v1.8.5 // indirect
github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08 // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-colorable v0.1.11 // indirect
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
github.com/mitchellh/copystructure v1.1.1 // indirect
github.com/mitchellh/mapstructure v1.4.1 // indirect
github.com/mitchellh/mapstructure v1.4.2 // indirect
github.com/mitchellh/reflectwalk v1.0.1 // indirect
github.com/pelletier/go-toml v1.9.4 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/satori/go.uuid v1.2.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.8.1 // indirect
github.com/spf13/viper v1.9.0 // indirect
github.com/stretchr/objx v0.3.0 // indirect
github.com/stretchr/testify v1.7.0 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.1 // indirect
github.com/ymomoi/goval-parser v0.0.0-20170813122243-0a0be1dd9d08 // indirect
go.etcd.io/bbolt v1.3.5 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.17.0 // indirect
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 // indirect
go.uber.org/zap v1.19.1 // indirect
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac // indirect
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.26.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect
gopkg.in/ini.v1 v1.63.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
gorm.io/driver/postgres v1.1.0 // indirect
gorm.io/driver/sqlite v1.1.4 // indirect
gorm.io/gorm v1.21.16 // indirect
moul.io/http2curl v1.0.0 // indirect
)

516
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -10,7 +10,7 @@ import (
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
debver "github.com/knqyf263/go-deb-version"
gostmodels "github.com/knqyf263/gost/models"
gostmodels "github.com/vulsio/gost/models"
"golang.org/x/xerrors"
)
@@ -31,6 +31,7 @@ func (deb Debian) supported(major string) bool {
"8": "jessie",
"9": "stretch",
"10": "buster",
"11": "bullseye",
}[major]
return ok
}
@@ -112,7 +113,10 @@ func (deb Debian) detectCVEsWithFixState(r *models.ScanResult, fixStatus string)
return 0, nil
}
for _, pack := range r.Packages {
cves, fixes := deb.getCvesDebianWithfixStatus(fixStatus, major(r.Release), pack.Name)
cves, fixes, err := deb.getCvesDebianWithfixStatus(fixStatus, major(r.Release), pack.Name)
if err != nil {
return 0, err
}
packCvesList = append(packCvesList, packCves{
packName: pack.Name,
isSrcPack: false,
@@ -123,7 +127,10 @@ func (deb Debian) detectCVEsWithFixState(r *models.ScanResult, fixStatus string)
// SrcPack
for _, pack := range r.SrcPackages {
cves, fixes := deb.getCvesDebianWithfixStatus(fixStatus, major(r.Release), pack.Name)
cves, fixes, err := deb.getCvesDebianWithfixStatus(fixStatus, major(r.Release), pack.Name)
if err != nil {
return 0, err
}
packCvesList = append(packCvesList, packCves{
packName: pack.Name,
isSrcPack: true,
@@ -142,7 +149,7 @@ func (deb Debian) detectCVEsWithFixState(r *models.ScanResult, fixStatus string)
if v.CveContents == nil {
v.CveContents = models.NewCveContents(cve)
} else {
v.CveContents[models.DebianSecurityTracker] = append(v.CveContents[models.DebianSecurityTracker], cve)
v.CveContents[models.DebianSecurityTracker] = []models.CveContent{cve}
v.Confidences = models.Confidences{models.DebianSecurityTrackerMatch}
}
} else {
@@ -232,21 +239,25 @@ func isGostDefAffected(versionRelease, gostVersion string) (affected bool, err e
return vera.LessThan(verb), nil
}
func (deb Debian) getCvesDebianWithfixStatus(fixStatus, release, pkgName string) (cves []models.CveContent, fixes []models.PackageFixStatus) {
var f func(string, string) map[string]gostmodels.DebianCVE
func (deb Debian) getCvesDebianWithfixStatus(fixStatus, release, pkgName string) ([]models.CveContent, []models.PackageFixStatus, error) {
var f func(string, string) (map[string]gostmodels.DebianCVE, error)
if fixStatus == "resolved" {
f = deb.DBDriver.DB.GetFixedCvesDebian
} else {
f = deb.DBDriver.DB.GetUnfixedCvesDebian
}
for _, cveDeb := range f(release, pkgName) {
cves = append(cves, *deb.ConvertToModel(&cveDeb))
fixes = append(fixes, checkPackageFixStatus(&cveDeb)...)
debCves, err := f(release, pkgName)
if err != nil {
return nil, nil, err
}
return
cves := []models.CveContent{}
fixes := []models.PackageFixStatus{}
for _, devbCve := range debCves {
cves = append(cves, *deb.ConvertToModel(&devbCve))
fixes = append(fixes, checkPackageFixStatus(&devbCve)...)
}
return cves, fixes, nil
}
// ConvertToModel converts gost model to vuls model

View File

@@ -39,10 +39,17 @@ func TestDebian_Supported(t *testing.T) {
want: true,
},
{
name: "11 is not supported yet",
name: "11 is supported",
args: args{
major: "11",
},
want: true,
},
{
name: "12 is not supported yet",
args: args{
major: "12",
},
want: false,
},
{

View File

@@ -7,7 +7,7 @@ import (
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/knqyf263/gost/db"
"github.com/vulsio/gost/db"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/constant"

View File

@@ -8,7 +8,7 @@ import (
"testing"
"github.com/future-architect/vuls/models"
gostmodels "github.com/knqyf263/gost/models"
gostmodels "github.com/vulsio/gost/models"
)
func TestSetPackageStates(t *testing.T) {

View File

@@ -8,7 +8,7 @@ import (
"strings"
"github.com/future-architect/vuls/models"
gostmodels "github.com/knqyf263/gost/models"
gostmodels "github.com/vulsio/gost/models"
)
// Microsoft is Gost client for windows
@@ -25,7 +25,11 @@ func (ms Microsoft) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err err
for cveID := range r.ScannedCves {
cveIDs = append(cveIDs, cveID)
}
for cveID, msCve := range ms.DBDriver.DB.GetMicrosoftMulti(cveIDs) {
msCves, err := ms.DBDriver.DB.GetMicrosoftMulti(cveIDs)
if err != nil {
return 0, nil
}
for cveID, msCve := range msCves {
if _, ok := r.ScannedCves[cveID]; !ok {
continue
}
@@ -34,7 +38,7 @@ func (ms Microsoft) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err err
if v.CveContents == nil {
v.CveContents = models.CveContents{}
}
v.CveContents[models.Microsoft] = append(v.CveContents[models.Microsoft], *cveCont)
v.CveContents[models.Microsoft] = []models.CveContent{*cveCont}
v.Mitigations = append(v.Mitigations, mitigations...)
r.ScannedCves[cveID] = v
}

View File

@@ -13,6 +13,6 @@ type Pseudo struct {
}
// DetectCVEs fills cve information that has in Gost
func (pse Pseudo) DetectCVEs(r *models.ScanResult, _ bool) (int, error) {
func (pse Pseudo) DetectCVEs(_ *models.ScanResult, _ bool) (int, error) {
return 0, nil
}

View File

@@ -11,7 +11,7 @@ import (
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
gostmodels "github.com/knqyf263/gost/models"
gostmodels "github.com/vulsio/gost/models"
)
// RedHat is Gost client for RedHat family linux
@@ -45,7 +45,10 @@ func (red RedHat) DetectCVEs(r *models.ScanResult, ignoreWillNotFix bool) (nCVEs
}
for _, pack := range r.Packages {
// CVE-ID: RedhatCVE
cves := red.DBDriver.DB.GetUnfixedCvesRedhat(major(r.Release), pack.Name, ignoreWillNotFix)
cves, err := red.DBDriver.DB.GetUnfixedCvesRedhat(major(r.Release), pack.Name, ignoreWillNotFix)
if err != nil {
return 0, err
}
for _, cve := range cves {
if newly := red.setUnfixedCveToScanResult(&cve, r); newly {
nCVEs++
@@ -85,7 +88,11 @@ func (red RedHat) fillCvesWithRedHatAPI(r *models.ScanResult) error {
if red.DBDriver.DB == nil {
return nil
}
for _, redCve := range red.DBDriver.DB.GetRedhatMulti(cveIDs) {
redCves, err := red.DBDriver.DB.GetRedhatMulti(cveIDs)
if err != nil {
return err
}
for _, redCve := range redCves {
if len(redCve.Name) == 0 {
continue
}
@@ -103,7 +110,7 @@ func (red RedHat) setFixedCveToScanResult(cve *gostmodels.RedhatCVE, r *models.S
if v.CveContents == nil {
v.CveContents = models.NewCveContents(*cveCont)
} else {
v.CveContents[models.RedHatAPI] = append(v.CveContents[models.RedHatAPI], *cveCont)
v.CveContents[models.RedHatAPI] = []models.CveContent{*cveCont}
}
} else {
v = models.VulnInfo{
@@ -123,7 +130,7 @@ func (red RedHat) setUnfixedCveToScanResult(cve *gostmodels.RedhatCVE, r *models
if v.CveContents == nil {
v.CveContents = models.NewCveContents(*cveCont)
} else {
v.CveContents[models.RedHatAPI] = append(v.CveContents[models.RedHatAPI], *cveCont)
v.CveContents[models.RedHatAPI] = []models.CveContent{*cveCont}
}
} else {
v = models.VulnInfo{

View File

@@ -10,7 +10,7 @@ import (
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
gostmodels "github.com/knqyf263/gost/models"
gostmodels "github.com/vulsio/gost/models"
)
// Ubuntu is Gost client for Ubuntu
@@ -80,7 +80,10 @@ func (ubu Ubuntu) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err error
return 0, nil
}
for _, pack := range r.Packages {
ubuCves := ubu.DBDriver.DB.GetUnfixedCvesUbuntu(ubuReleaseVer, pack.Name)
ubuCves, err := ubu.DBDriver.DB.GetUnfixedCvesUbuntu(ubuReleaseVer, pack.Name)
if err != nil {
return 0, nil
}
cves := []models.CveContent{}
for _, ubucve := range ubuCves {
cves = append(cves, *ubu.ConvertToModel(&ubucve))
@@ -94,7 +97,10 @@ func (ubu Ubuntu) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err error
// SrcPack
for _, pack := range r.SrcPackages {
ubuCves := ubu.DBDriver.DB.GetUnfixedCvesUbuntu(ubuReleaseVer, pack.Name)
ubuCves, err := ubu.DBDriver.DB.GetUnfixedCvesUbuntu(ubuReleaseVer, pack.Name)
if err != nil {
return 0, nil
}
cves := []models.CveContent{}
for _, ubucve := range ubuCves {
cves = append(cves, *ubu.ConvertToModel(&ubucve))
@@ -116,7 +122,7 @@ func (ubu Ubuntu) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err error
if v.CveContents == nil {
v.CveContents = models.NewCveContents(cve)
} else {
v.CveContents[models.UbuntuAPI] = append(v.CveContents[models.UbuntuAPI], cve)
v.CveContents[models.UbuntuAPI] = []models.CveContent{cve}
}
} else {
v = models.VulnInfo{

View File

@@ -6,7 +6,7 @@ import (
"time"
"github.com/future-architect/vuls/models"
gostmodels "github.com/knqyf263/gost/models"
gostmodels "github.com/vulsio/gost/models"
)
func TestUbuntu_Supported(t *testing.T) {

View File

@@ -6469,13 +6469,13 @@
"cveDict": {
"Name": "cveDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/go-cve-dictionary/cve.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-cve-dictionary/cve.sqlite3",
"DebugSQL": false
},
"ovalDict": {
"Name": "ovalDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/goval-dictionary/oval.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/goval-dictionary/oval.sqlite3",
"DebugSQL": false
},
"gost": {
@@ -6493,7 +6493,7 @@
"metasploit": {
"Name": "metasploit",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/takuzoo3868/go-msfdb/go-msfdb.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-msfdb/go-msfdb.sqlite3",
"DebugSQL": false
}
},

View File

@@ -5569,13 +5569,13 @@
"cveDict": {
"Name": "cveDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/go-cve-dictionary/cve.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-cve-dictionary/cve.sqlite3",
"DebugSQL": false
},
"ovalDict": {
"Name": "ovalDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/goval-dictionary/oval.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/goval-dictionary/oval.sqlite3",
"DebugSQL": false
},
"gost": {
@@ -5593,7 +5593,7 @@
"metasploit": {
"Name": "metasploit",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/takuzoo3868/go-msfdb/go-msfdb.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-msfdb/go-msfdb.sqlite3",
"DebugSQL": false
}
},

View File

@@ -5566,13 +5566,13 @@
"cveDict": {
"Name": "cveDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/go-cve-dictionary/cve.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-cve-dictionary/cve.sqlite3",
"DebugSQL": false
},
"ovalDict": {
"Name": "ovalDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/goval-dictionary/oval.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/goval-dictionary/oval.sqlite3",
"DebugSQL": false
},
"gost": {
@@ -5590,7 +5590,7 @@
"metasploit": {
"Name": "metasploit",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/takuzoo3868/go-msfdb/go-msfdb.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-msfdb/go-msfdb.sqlite3",
"DebugSQL": false
}
},

View File

@@ -5093,13 +5093,13 @@
"cveDict": {
"Name": "cveDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/go-cve-dictionary/cve.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-cve-dictionary/cve.sqlite3",
"DebugSQL": false
},
"ovalDict": {
"Name": "ovalDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/goval-dictionary/oval.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/goval-dictionary/oval.sqlite3",
"DebugSQL": false
},
"gost": {
@@ -5117,7 +5117,7 @@
"metasploit": {
"Name": "metasploit",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/takuzoo3868/go-msfdb/go-msfdb.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-msfdb/go-msfdb.sqlite3",
"DebugSQL": false
}
},

View File

@@ -44,6 +44,7 @@
"version": "",
"rebootRequired": false
},
"enabledDnfModules": ["nodejs:12"],
"packages": {
"NetworkManager": {
"name": "NetworkManager",
@@ -5906,6 +5907,15 @@
}
]
},
"nodejs": {
"name": "nodejs",
"version": "1:12.14.1",
"release": "1.module+el8.1.0+5466+30f75628",
"newVersion": "1:12.14.1",
"newRelease": "1.module+el8.1.0+5466+30f75629",
"arch": "x86_64",
"repository": "rhel-8-appstream-rhui-rpms"
},
"sed": {
"name": "sed",
"version": "4.5",
@@ -6861,13 +6871,13 @@
"cveDict": {
"Name": "cveDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/go-cve-dictionary/cve.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-cve-dictionary/cve.sqlite3",
"DebugSQL": false
},
"ovalDict": {
"Name": "ovalDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/goval-dictionary/oval.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/goval-dictionary/oval.sqlite3",
"DebugSQL": false
},
"gost": {
@@ -6885,7 +6895,7 @@
"metasploit": {
"Name": "metasploit",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/takuzoo3868/go-msfdb/go-msfdb.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-msfdb/go-msfdb.sqlite3",
"DebugSQL": false
}
},

View File

@@ -8544,13 +8544,13 @@
"cveDict": {
"Name": "cveDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/go-cve-dictionary/cve.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-cve-dictionary/cve.sqlite3",
"DebugSQL": false
},
"ovalDict": {
"Name": "ovalDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/goval-dictionary/oval.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/goval-dictionary/oval.sqlite3",
"DebugSQL": false
},
"gost": {
@@ -8568,7 +8568,7 @@
"metasploit": {
"Name": "metasploit",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/takuzoo3868/go-msfdb/go-msfdb.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-msfdb/go-msfdb.sqlite3",
"DebugSQL": false
}
},

View File

@@ -8494,13 +8494,13 @@
"cveDict": {
"Name": "cveDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/go-cve-dictionary/cve.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-cve-dictionary/cve.sqlite3",
"DebugSQL": false
},
"ovalDict": {
"Name": "ovalDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/goval-dictionary/oval.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/goval-dictionary/oval.sqlite3",
"DebugSQL": false
},
"gost": {
@@ -8518,7 +8518,7 @@
"metasploit": {
"Name": "metasploit",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/takuzoo3868/go-msfdb/go-msfdb.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-msfdb/go-msfdb.sqlite3",
"DebugSQL": false
}
},

View File

@@ -22,6 +22,7 @@ type LogOpts struct {
DebugSQL bool `json:"debugSQL,omitempty"`
LogToFile bool `json:"logToFile,omitempty"`
LogDir string `json:"logDir,omitempty"`
LogJSON bool `json:"logJSON"`
Quiet bool `json:"quiet,omitempty"`
}

View File

@@ -15,7 +15,20 @@ type CveContents map[CveContentType][]CveContent
func NewCveContents(conts ...CveContent) CveContents {
m := CveContents{}
for _, cont := range conts {
m[cont.Type] = append(m[cont.Type], cont)
if cont.Type == Jvn {
found := false
for _, cveCont := range m[cont.Type] {
if cont.SourceLink == cveCont.SourceLink {
found = true
break
}
}
if !found {
m[cont.Type] = append(m[cont.Type], cont)
}
} else {
m[cont.Type] = []CveContent{cont}
}
}
return m
}
@@ -229,6 +242,7 @@ func (v CveContents) UniqCweIDs(myFamily string) (values []CveContentStr) {
return values
}
// Sort elements for integration-testing
func (v CveContents) Sort() {
for contType, contents := range v {
// CVSS3 desc, CVSS2 desc, SourceLink asc

View File

@@ -10,19 +10,18 @@ import (
"github.com/aquasecurity/trivy/pkg/types"
"golang.org/x/xerrors"
// "github.com/aquasecurity/go-dep-parser/pkg/types"
)
// LibraryScanners is an array of LibraryScanner
type LibraryScanners []LibraryScanner
// Find : find by name
func (lss LibraryScanners) Find(path, name string) map[string]types.Library {
filtered := map[string]types.Library{}
func (lss LibraryScanners) Find(path, name string) map[string]Library {
filtered := map[string]Library{}
for _, ls := range lss {
for _, lib := range ls.Libs {
if ls.Path == path && lib.Name == name {
filtered[ls.Path] = lib
if ls.LockfilePath == path && lib.Name == name {
filtered[ls.LockfilePath] = lib
break
}
}
@@ -41,8 +40,20 @@ func (lss LibraryScanners) Total() (total int) {
// LibraryScanner has libraries information
type LibraryScanner struct {
Type string
Path string
Libs []types.Library
Libs []Library
// The path to the Lockfile is stored.
LockfilePath string `json:"path,omitempty"`
}
// Library holds the attribute of a package library
type Library struct {
Name string
Version string
// The Path to the library in the container image. Empty string when Lockfile scan.
// This field is used to convert the result JSON of a `trivy image` using trivy-to-vuls.
FilePath string
}
// Scan : scan target library
@@ -93,7 +104,7 @@ func (s LibraryScanner) getVulnDetail(tvuln types.DetectedVulnerability) (vinfo
Key: s.GetLibraryKey(),
Name: tvuln.PkgName,
FixedIn: tvuln.FixedVersion,
Path: s.Path,
Path: s.LockfilePath,
},
}
return vinfo, nil
@@ -106,33 +117,39 @@ func getCveContents(cveID string, vul trivyDBTypes.Vulnerability) (contents map[
refs = append(refs, Reference{Source: "trivy", Link: refURL})
}
content := CveContent{
Type: Trivy,
CveID: cveID,
Title: vul.Title,
Summary: vul.Description,
Cvss3Severity: string(vul.Severity),
References: refs,
contents[Trivy] = []CveContent{
{
Type: Trivy,
CveID: cveID,
Title: vul.Title,
Summary: vul.Description,
Cvss3Severity: string(vul.Severity),
References: refs,
},
}
contents[Trivy] = append(contents[Trivy], content)
return contents
}
// LibraryMap is filename and library type
var LibraryMap = map[string]string{
"package-lock.json": "node",
"yarn.lock": "node",
"Gemfile.lock": "ruby",
"Cargo.lock": "rust",
"composer.lock": "php",
"Pipfile.lock": "python",
"poetry.lock": "python",
"go.sum": "gomod",
"package-lock.json": "node",
"yarn.lock": "node",
"Gemfile.lock": "ruby",
"Cargo.lock": "rust",
"composer.lock": "php",
"Pipfile.lock": "python",
"poetry.lock": "python",
"packages.lock.json": ".net",
"go.sum": "gomod",
}
// GetLibraryKey returns target library key
func (s LibraryScanner) GetLibraryKey() string {
fileName := filepath.Base(s.Path)
fileName := filepath.Base(s.LockfilePath)
switch s.Type {
case "jar", "war", "ear":
return "java"
}
return LibraryMap[fileName]
}

View File

@@ -3,8 +3,6 @@ package models
import (
"reflect"
"testing"
"github.com/aquasecurity/trivy/pkg/types"
)
func TestLibraryScanners_Find(t *testing.T) {
@@ -16,14 +14,14 @@ func TestLibraryScanners_Find(t *testing.T) {
name string
lss LibraryScanners
args args
want map[string]types.Library
want map[string]Library
}{
{
name: "single file",
lss: LibraryScanners{
{
Path: "/pathA",
Libs: []types.Library{
LockfilePath: "/pathA",
Libs: []Library{
{
Name: "libA",
Version: "1.0.0",
@@ -32,7 +30,7 @@ func TestLibraryScanners_Find(t *testing.T) {
},
},
args: args{"/pathA", "libA"},
want: map[string]types.Library{
want: map[string]Library{
"/pathA": {
Name: "libA",
Version: "1.0.0",
@@ -43,8 +41,8 @@ func TestLibraryScanners_Find(t *testing.T) {
name: "multi file",
lss: LibraryScanners{
{
Path: "/pathA",
Libs: []types.Library{
LockfilePath: "/pathA",
Libs: []Library{
{
Name: "libA",
Version: "1.0.0",
@@ -52,8 +50,8 @@ func TestLibraryScanners_Find(t *testing.T) {
},
},
{
Path: "/pathB",
Libs: []types.Library{
LockfilePath: "/pathB",
Libs: []Library{
{
Name: "libA",
Version: "1.0.5",
@@ -62,7 +60,7 @@ func TestLibraryScanners_Find(t *testing.T) {
},
},
args: args{"/pathA", "libA"},
want: map[string]types.Library{
want: map[string]Library{
"/pathA": {
Name: "libA",
Version: "1.0.0",
@@ -73,8 +71,8 @@ func TestLibraryScanners_Find(t *testing.T) {
name: "miss",
lss: LibraryScanners{
{
Path: "/pathA",
Libs: []types.Library{
LockfilePath: "/pathA",
Libs: []Library{
{
Name: "libA",
Version: "1.0.0",
@@ -83,7 +81,7 @@ func TestLibraryScanners_Find(t *testing.T) {
},
},
args: args{"/pathA", "libB"},
want: map[string]types.Library{},
want: map[string]Library{},
},
}
for _, tt := range tests {

View File

@@ -6,7 +6,7 @@ package models
import (
"strings"
cvedict "github.com/kotakanbe/go-cve-dictionary/models"
cvedict "github.com/vulsio/go-cve-dictionary/models"
)
// ConvertJvnToModel convert JVN to CveContent

View File

@@ -28,43 +28,46 @@ func (v VulnInfos) Find(f func(VulnInfo) bool) VulnInfos {
}
// FilterByCvssOver return scored vulnerabilities
func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {
func (v VulnInfos) FilterByCvssOver(over float64) (_ VulnInfos, nFiltered int) {
return v.Find(func(v VulnInfo) bool {
if over <= v.MaxCvssScore().Value.Score {
return true
}
nFiltered++
return false
})
}), nFiltered
}
// FilterByConfidenceOver scored vulnerabilities
func (v VulnInfos) FilterByConfidenceOver(over int) VulnInfos {
func (v VulnInfos) FilterByConfidenceOver(over int) (_ VulnInfos, nFiltered int) {
return v.Find(func(v VulnInfo) bool {
for _, c := range v.Confidences {
if over <= c.Score {
return true
}
}
nFiltered++
return false
})
}), nFiltered
}
// FilterIgnoreCves filter function.
func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {
func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) (_ VulnInfos, nFiltered int) {
return v.Find(func(v VulnInfo) bool {
for _, c := range ignoreCveIDs {
if v.CveID == c {
nFiltered++
return false
}
}
return true
})
}), nFiltered
}
// FilterUnfixed filter unfixed CVE-IDs
func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {
func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) (_ VulnInfos, nFiltered int) {
if !ignoreUnfixed {
return v
return v, 0
}
return v.Find(func(v VulnInfo) bool {
// Report cves detected by CPE because Vuls can't know 'fixed' or 'unfixed'
@@ -75,24 +78,26 @@ func (v VulnInfos) FilterUnfixed(ignoreUnfixed bool) VulnInfos {
for _, p := range v.AffectedPackages {
NotFixedAll = NotFixedAll && p.NotFixedYet
}
if NotFixedAll {
nFiltered++
}
return !NotFixedAll
})
}), nFiltered
}
// FilterIgnorePkgs is filter function.
func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {
func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) (_ VulnInfos, nFiltered int) {
regexps := []*regexp.Regexp{}
for _, pkgRegexp := range ignorePkgsRegexps {
re, err := regexp.Compile(pkgRegexp)
if err != nil {
logging.Log.Warnf("Failed to parse %s. err: %+v", pkgRegexp, err)
continue
} else {
regexps = append(regexps, re)
}
regexps = append(regexps, re)
}
if len(regexps) == 0 {
return v
return v, 0
}
return v.Find(func(v VulnInfo) bool {
@@ -110,19 +115,21 @@ func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {
return true
}
}
nFiltered++
return false
})
}), nFiltered
}
// FindScoredVulns return scored vulnerabilities
func (v VulnInfos) FindScoredVulns() VulnInfos {
func (v VulnInfos) FindScoredVulns() (_ VulnInfos, nFiltered int) {
return v.Find(func(vv VulnInfo) bool {
if 0 < vv.MaxCvss2Score().Value.Score ||
0 < vv.MaxCvss3Score().Value.Score {
return true
}
nFiltered++
return false
})
}), nFiltered
}
// ToSortedSlice returns slice of VulnInfos that is sorted by Score, CVE-ID
@@ -893,7 +900,7 @@ const (
// ChangelogExactMatchStr :
ChangelogExactMatchStr = "ChangelogExactMatch"
// ChangelogRoughMatch :
// ChangelogRoughMatchStr :
ChangelogRoughMatchStr = "ChangelogRoughMatch"
// GitHubMatchStr :

View File

@@ -1247,10 +1247,11 @@ func TestVulnInfos_FilterByCvssOver(t *testing.T) {
over float64
}
tests := []struct {
name string
v VulnInfos
args args
want VulnInfos
name string
v VulnInfos
args args
want VulnInfos
nwant int
}{
{
name: "over 7.0",
@@ -1296,6 +1297,7 @@ func TestVulnInfos_FilterByCvssOver(t *testing.T) {
),
},
},
nwant: 1,
want: VulnInfos{
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
@@ -1404,9 +1406,13 @@ func TestVulnInfos_FilterByCvssOver(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.v.FilterByCvssOver(tt.args.over); !reflect.DeepEqual(got, tt.want) {
got, ngot := tt.v.FilterByCvssOver(tt.args.over)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("VulnInfos.FindByCvssOver() = %v, want %v", got, tt.want)
}
if ngot != tt.nwant {
t.Errorf("VulnInfos.FindByCvssOver() = %d, want %d", ngot, tt.nwant)
}
})
}
}
@@ -1416,10 +1422,11 @@ func TestVulnInfos_FilterIgnoreCves(t *testing.T) {
ignoreCveIDs []string
}
tests := []struct {
name string
v VulnInfos
args args
want VulnInfos
name string
v VulnInfos
args args
want VulnInfos
nwant int
}{
{
name: "filter ignored",
@@ -1435,6 +1442,7 @@ func TestVulnInfos_FilterIgnoreCves(t *testing.T) {
CveID: "CVE-2017-0003",
},
},
nwant: 1,
want: VulnInfos{
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
@@ -1447,9 +1455,13 @@ func TestVulnInfos_FilterIgnoreCves(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.v.FilterIgnoreCves(tt.args.ignoreCveIDs); !reflect.DeepEqual(got, tt.want) {
got, ngot := tt.v.FilterIgnoreCves(tt.args.ignoreCveIDs)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("VulnInfos.FindIgnoreCves() = %v, want %v", got, tt.want)
}
if ngot != tt.nwant {
t.Errorf("VulnInfos.FindByCvssOver() = %d, want %d", ngot, tt.nwant)
}
})
}
}
@@ -1459,10 +1471,11 @@ func TestVulnInfos_FilterUnfixed(t *testing.T) {
ignoreUnfixed bool
}
tests := []struct {
name string
v VulnInfos
args args
want VulnInfos
name string
v VulnInfos
args args
want VulnInfos
nwant int
}{
{
name: "filter ok",
@@ -1500,6 +1513,7 @@ func TestVulnInfos_FilterUnfixed(t *testing.T) {
},
},
},
nwant: 1,
want: VulnInfos{
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
@@ -1528,9 +1542,13 @@ func TestVulnInfos_FilterUnfixed(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.v.FilterUnfixed(tt.args.ignoreUnfixed); !reflect.DeepEqual(got, tt.want) {
got, ngot := tt.v.FilterUnfixed(tt.args.ignoreUnfixed)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("VulnInfos.FilterUnfixed() = %v, want %v", got, tt.want)
}
if ngot != tt.nwant {
t.Errorf("VulnInfos.FindByCvssOver() = %d, want %d", ngot, tt.nwant)
}
})
}
}
@@ -1540,10 +1558,11 @@ func TestVulnInfos_FilterIgnorePkgs(t *testing.T) {
ignorePkgsRegexps []string
}
tests := []struct {
name string
v VulnInfos
args args
want VulnInfos
name string
v VulnInfos
args args
want VulnInfos
nwant int
}{
{
name: "filter pkgs 1",
@@ -1559,6 +1578,7 @@ func TestVulnInfos_FilterIgnorePkgs(t *testing.T) {
CveID: "CVE-2017-0002",
},
},
nwant: 1,
want: VulnInfos{
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
@@ -1577,6 +1597,7 @@ func TestVulnInfos_FilterIgnorePkgs(t *testing.T) {
},
},
},
nwant: 0,
want: VulnInfos{
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
@@ -1599,14 +1620,19 @@ func TestVulnInfos_FilterIgnorePkgs(t *testing.T) {
},
},
},
want: VulnInfos{},
nwant: 1,
want: VulnInfos{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.v.FilterIgnorePkgs(tt.args.ignorePkgsRegexps); !reflect.DeepEqual(got, tt.want) {
got, ngot := tt.v.FilterIgnorePkgs(tt.args.ignorePkgsRegexps)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("VulnInfos.FilterIgnorePkgs() = %v, want %v", got, tt.want)
}
if ngot != tt.nwant {
t.Errorf("VulnInfos.FilterIgnorePkgs() = %d, want %d", ngot, tt.nwant)
}
})
}
}
@@ -1616,10 +1642,11 @@ func TestVulnInfos_FilterByConfidenceOver(t *testing.T) {
over int
}
tests := []struct {
name string
v VulnInfos
args args
want VulnInfos
name string
v VulnInfos
args args
want VulnInfos
nwant int
}{
{
name: "over 0",
@@ -1650,7 +1677,8 @@ func TestVulnInfos_FilterByConfidenceOver(t *testing.T) {
args: args{
over: 20,
},
want: map[string]VulnInfo{},
nwant: 1,
want: map[string]VulnInfo{},
},
{
name: "over 100",
@@ -1679,9 +1707,13 @@ func TestVulnInfos_FilterByConfidenceOver(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.v.FilterByConfidenceOver(tt.args.over); !reflect.DeepEqual(got, tt.want) {
got, ngot := tt.v.FilterByConfidenceOver(tt.args.over)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("VulnInfos.FilterByConfidenceOver() = %v, want %v", got, tt.want)
}
if ngot != tt.nwant {
t.Errorf("VulnInfos.FilterByConfidenceOver() = %d, want %d", ngot, tt.nwant)
}
})
}
}

View File

@@ -54,8 +54,8 @@ func (o Alpine) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
return len(relatedDefs.entries), nil
}
func (o Alpine) update(r *models.ScanResult, defPacks defPacks) {
cveID := defPacks.def.Advisory.Cves[0].CveID
func (o Alpine) update(r *models.ScanResult, defpacks defPacks) {
cveID := defpacks.def.Advisory.Cves[0].CveID
vinfo, ok := r.ScannedCves[cveID]
if !ok {
logging.Log.Debugf("%s is newly detected by OVAL", cveID)
@@ -65,7 +65,7 @@ func (o Alpine) update(r *models.ScanResult, defPacks defPacks) {
}
}
vinfo.AffectedPackages = defPacks.toPackStatuses()
vinfo.AffectedPackages = defpacks.toPackStatuses()
vinfo.AffectedPackages.Sort()
r.ScannedCves[cveID] = vinfo
}

View File

@@ -12,7 +12,7 @@ import (
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
ovalmodels "github.com/vulsio/goval-dictionary/models"
)
// DebianBase is the base struct of Debian and Ubuntu
@@ -20,73 +20,75 @@ type DebianBase struct {
Base
}
func (o DebianBase) update(r *models.ScanResult, defPacks defPacks) {
ovalContent := *o.convertToModel(&defPacks.def)
ovalContent.Type = models.NewCveContentType(o.family)
vinfo, ok := r.ScannedCves[defPacks.def.Debian.CveID]
if !ok {
logging.Log.Debugf("%s is newly detected by OVAL", defPacks.def.Debian.CveID)
vinfo = models.VulnInfo{
CveID: defPacks.def.Debian.CveID,
Confidences: []models.Confidence{models.OvalMatch},
CveContents: models.NewCveContents(ovalContent),
func (o DebianBase) update(r *models.ScanResult, defpacks defPacks) {
for _, cve := range defpacks.def.Advisory.Cves {
ovalContent := o.convertToModel(cve.CveID, &defpacks.def)
if ovalContent == nil {
continue
}
} else {
cveContents := vinfo.CveContents
ctype := models.NewCveContentType(o.family)
if _, ok := vinfo.CveContents[ctype]; ok {
logging.Log.Debugf("%s OVAL will be overwritten",
defPacks.def.Debian.CveID)
vinfo, ok := r.ScannedCves[cve.CveID]
if !ok {
logging.Log.Debugf("%s is newly detected by OVAL", cve.CveID)
vinfo = models.VulnInfo{
CveID: cve.CveID,
Confidences: []models.Confidence{models.OvalMatch},
CveContents: models.NewCveContents(*ovalContent),
}
} else {
logging.Log.Debugf("%s is also detected by OVAL",
defPacks.def.Debian.CveID)
cveContents = models.CveContents{}
}
if r.Family != constant.Raspbian {
cveContents := vinfo.CveContents
if _, ok := vinfo.CveContents[ovalContent.Type]; ok {
logging.Log.Debugf("%s OVAL will be overwritten", cve.CveID)
} else {
logging.Log.Debugf("%s is also detected by OVAL", cve.CveID)
cveContents = models.CveContents{}
}
vinfo.Confidences.AppendIfMissing(models.OvalMatch)
} else {
if len(vinfo.Confidences) == 0 {
vinfo.Confidences.AppendIfMissing(models.OvalMatch)
cveContents[ovalContent.Type] = []models.CveContent{*ovalContent}
vinfo.CveContents = cveContents
}
// uniq(vinfo.AffectedPackages[].Name + defPacks.binpkgFixstat(map[string(=package name)]fixStat{}))
collectBinpkgFixstat := defPacks{
binpkgFixstat: map[string]fixStat{},
}
for packName, fixStatus := range defpacks.binpkgFixstat {
collectBinpkgFixstat.binpkgFixstat[packName] = fixStatus
}
for _, pack := range vinfo.AffectedPackages {
collectBinpkgFixstat.binpkgFixstat[pack.Name] = fixStat{
notFixedYet: pack.NotFixedYet,
fixedIn: pack.FixedIn,
isSrcPack: false,
}
}
cveContents[ctype] = append(cveContents[ctype], ovalContent)
vinfo.CveContents = cveContents
}
// uniq(vinfo.PackNames + defPacks.binpkgStat)
for _, pack := range vinfo.AffectedPackages {
defPacks.binpkgFixstat[pack.Name] = fixStat{
notFixedYet: pack.NotFixedYet,
fixedIn: pack.FixedIn,
isSrcPack: false,
}
}
// Update package status of source packages.
// In the case of Debian based Linux, sometimes source package name is defined as affected package in OVAL.
// To display binary package name showed in apt-get, need to convert source name to binary name.
for binName := range defPacks.binpkgFixstat {
if srcPack, ok := r.SrcPackages.FindByBinName(binName); ok {
for _, p := range defPacks.def.AffectedPacks {
if p.Name == srcPack.Name {
defPacks.binpkgFixstat[binName] = fixStat{
notFixedYet: p.NotFixedYet,
fixedIn: p.Version,
isSrcPack: true,
srcPackName: srcPack.Name,
// Update package status of source packages.
// In the case of Debian based Linux, sometimes source package name is defined as affected package in OVAL.
// To display binary package name showed in apt-get, need to convert source name to binary name.
for binName := range defpacks.binpkgFixstat {
if srcPack, ok := r.SrcPackages.FindByBinName(binName); ok {
for _, p := range defpacks.def.AffectedPacks {
if p.Name == srcPack.Name {
collectBinpkgFixstat.binpkgFixstat[binName] = fixStat{
notFixedYet: p.NotFixedYet,
fixedIn: p.Version,
isSrcPack: true,
srcPackName: srcPack.Name,
}
}
}
}
}
}
vinfo.AffectedPackages = defPacks.toPackStatuses()
vinfo.AffectedPackages.Sort()
r.ScannedCves[defPacks.def.Debian.CveID] = vinfo
vinfo.AffectedPackages = collectBinpkgFixstat.toPackStatuses()
vinfo.AffectedPackages.Sort()
r.ScannedCves[cve.CveID] = vinfo
}
}
func (o DebianBase) convertToModel(def *ovalmodels.Definition) *models.CveContent {
refs := []models.Reference{}
func (o DebianBase) convertToModel(cveID string, def *ovalmodels.Definition) *models.CveContent {
refs := make([]models.Reference, 0, len(def.References))
for _, r := range def.References {
refs = append(refs, models.Reference{
Link: r.RefURL,
@@ -95,14 +97,23 @@ func (o DebianBase) convertToModel(def *ovalmodels.Definition) *models.CveConten
})
}
return &models.CveContent{
CveID: def.Debian.CveID,
Title: def.Title,
Summary: def.Description,
Cvss2Severity: def.Advisory.Severity,
Cvss3Severity: def.Advisory.Severity,
References: refs,
for _, cve := range def.Advisory.Cves {
if cve.CveID != cveID {
continue
}
return &models.CveContent{
Type: models.NewCveContentType(o.family),
CveID: cve.CveID,
Title: def.Title,
Summary: def.Description,
Cvss2Severity: def.Advisory.Severity,
Cvss3Severity: def.Advisory.Severity,
References: refs,
}
}
return nil
}
// Debian is the interface for Debian OVAL
@@ -183,9 +194,9 @@ func (o Debian) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
for _, vuln := range r.ScannedCves {
if conts, ok := vuln.CveContents[models.Debian]; ok {
for _, cont := range conts {
for i, cont := range conts {
cont.SourceLink = "https://security-tracker.debian.org/tracker/" + cont.CveID
vuln.CveContents[models.Debian] = append(vuln.CveContents[models.Debian], cont)
vuln.CveContents[models.Debian][i] = cont
}
}
}
@@ -502,9 +513,9 @@ func (o Ubuntu) fillWithOval(r *models.ScanResult, kernelNamesInOval []string) (
for _, vuln := range r.ScannedCves {
if conts, ok := vuln.CveContents[models.Ubuntu]; ok {
for _, cont := range conts {
for i, cont := range conts {
cont.SourceLink = "http://people.ubuntu.com/~ubuntu-security/cve/" + cont.CveID
vuln.CveContents[models.Ubuntu] = append(vuln.CveContents[models.Ubuntu], cont)
vuln.CveContents[models.Ubuntu][i] = cont
}
}
}

View File

@@ -8,7 +8,7 @@ import (
"testing"
"github.com/future-architect/vuls/models"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
ovalmodels "github.com/vulsio/goval-dictionary/models"
)
func TestPackNamesOfUpdateDebian(t *testing.T) {
@@ -30,8 +30,8 @@ func TestPackNamesOfUpdateDebian(t *testing.T) {
},
defPacks: defPacks{
def: ovalmodels.Definition{
Debian: ovalmodels.Debian{
CveID: "CVE-2000-1000",
Advisory: ovalmodels.Advisory{
Cves: []ovalmodels.Cve{{CveID: "CVE-2000-1000"}},
},
},
binpkgFixstat: map[string]fixStat{
@@ -53,15 +53,68 @@ func TestPackNamesOfUpdateDebian(t *testing.T) {
},
},
},
{
in: models.ScanResult{
ScannedCves: models.VulnInfos{
"CVE-2000-1000": models.VulnInfo{
AffectedPackages: models.PackageFixStatuses{
{Name: "packA"},
},
},
"CVE-2000-1001": models.VulnInfo{
AffectedPackages: models.PackageFixStatuses{
{Name: "packC"},
},
},
},
},
defPacks: defPacks{
def: ovalmodels.Definition{
Advisory: ovalmodels.Advisory{
Cves: []ovalmodels.Cve{
{
CveID: "CVE-2000-1000",
},
{
CveID: "CVE-2000-1001",
},
},
},
},
binpkgFixstat: map[string]fixStat{
"packB": {
notFixedYet: false,
},
},
},
out: models.ScanResult{
ScannedCves: models.VulnInfos{
"CVE-2000-1000": models.VulnInfo{
AffectedPackages: models.PackageFixStatuses{
{Name: "packA"},
{Name: "packB", NotFixedYet: false},
},
},
"CVE-2000-1001": models.VulnInfo{
AffectedPackages: models.PackageFixStatuses{
{Name: "packB", NotFixedYet: false},
{Name: "packC"},
},
},
},
},
},
}
// util.Log = util.NewCustomLogger()
for i, tt := range tests {
Debian{}.update(&tt.in, tt.defPacks)
e := tt.out.ScannedCves["CVE-2000-1000"].AffectedPackages
a := tt.in.ScannedCves["CVE-2000-1000"].AffectedPackages
if !reflect.DeepEqual(a, e) {
t.Errorf("[%d] expected: %#v\n actual: %#v\n", i, e, a)
for cveid := range tt.out.ScannedCves {
e := tt.out.ScannedCves[cveid].AffectedPackages
a := tt.in.ScannedCves[cveid].AffectedPackages
if !reflect.DeepEqual(a, e) {
t.Errorf("[%d] expected: %v\n actual: %v\n", i, e, a)
}
}
}
}

View File

@@ -11,8 +11,8 @@ import (
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
"github.com/kotakanbe/goval-dictionary/db"
"github.com/parnurzeal/gorequest"
"github.com/vulsio/goval-dictionary/db"
"golang.org/x/xerrors"
)
@@ -103,7 +103,7 @@ func (b Base) CheckIfOvalFresh(osFamily, release string) (ok bool, err error) {
since := time.Now()
since = since.AddDate(0, 0, -3)
if lastModified.Before(since) {
logging.Log.Warnf("OVAL for %s %s is old, last modified is %s. It's recommended to update OVAL to improve scanning accuracy. How to update OVAL database, see https://github.com/kotakanbe/goval-dictionary#usage",
logging.Log.Warnf("OVAL for %s %s is old, last modified is %s. It's recommended to update OVAL to improve scanning accuracy. How to update OVAL database, see https://github.com/vulsio/goval-dictionary#usage",
osFamily, release, lastModified)
return false, nil
}

View File

@@ -12,7 +12,7 @@ import (
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
ovalmodels "github.com/vulsio/goval-dictionary/models"
)
// RedHatBase is the base struct for RedHat, CentOS, Alma and Rocky
@@ -52,16 +52,29 @@ func (o RedHatBase) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
switch models.NewCveContentType(o.family) {
case models.RedHat:
if conts, ok := vuln.CveContents[models.RedHat]; ok {
for _, cont := range conts {
for i, cont := range conts {
cont.SourceLink = "https://access.redhat.com/security/cve/" + cont.CveID
vuln.CveContents[models.RedHat] = append(vuln.CveContents[models.RedHat], cont)
vuln.CveContents[models.RedHat][i] = cont
}
}
case models.Oracle:
if conts, ok := vuln.CveContents[models.Oracle]; ok {
for _, cont := range conts {
for i, cont := range conts {
cont.SourceLink = fmt.Sprintf("https://linux.oracle.com/cve/%s.html", cont.CveID)
vuln.CveContents[models.Oracle] = append(vuln.CveContents[models.Oracle], cont)
vuln.CveContents[models.Oracle][i] = cont
}
}
case models.Amazon:
for _, d := range vuln.DistroAdvisories {
if conts, ok := vuln.CveContents[models.Amazon]; ok {
for i, cont := range conts {
if strings.HasPrefix(d.AdvisoryID, "ALAS2-") {
cont.SourceLink = fmt.Sprintf("https://alas.aws.amazon.com/AL2/%s.html", strings.ReplaceAll(d.AdvisoryID, "ALAS2", "ALAS"))
} else if strings.HasPrefix(d.AdvisoryID, "ALAS-") {
cont.SourceLink = fmt.Sprintf("https://alas.aws.amazon.com/%s.html", d.AdvisoryID)
}
vuln.CveContents[models.Amazon][i] = cont
}
}
}
}
@@ -102,57 +115,66 @@ var kernelRelatedPackNames = map[string]bool{
"python-perf": true,
}
func (o RedHatBase) update(r *models.ScanResult, defPacks defPacks) (nCVEs int) {
ctype := models.NewCveContentType(o.family)
for _, cve := range defPacks.def.Advisory.Cves {
ovalContent := *o.convertToModel(cve.CveID, &defPacks.def)
func (o RedHatBase) update(r *models.ScanResult, defpacks defPacks) (nCVEs int) {
for _, cve := range defpacks.def.Advisory.Cves {
ovalContent := o.convertToModel(cve.CveID, &defpacks.def)
if ovalContent == nil {
continue
}
vinfo, ok := r.ScannedCves[cve.CveID]
if !ok {
logging.Log.Debugf("%s is newly detected by OVAL: DefID: %s", cve.CveID, defPacks.def.DefinitionID)
logging.Log.Debugf("%s is newly detected by OVAL: DefID: %s", cve.CveID, defpacks.def.DefinitionID)
vinfo = models.VulnInfo{
CveID: cve.CveID,
Confidences: models.Confidences{models.OvalMatch},
CveContents: models.NewCveContents(ovalContent),
CveContents: models.NewCveContents(*ovalContent),
}
nCVEs++
} else {
cveContents := vinfo.CveContents
if v, ok := vinfo.CveContents[ctype]; ok {
if v, ok := vinfo.CveContents[ovalContent.Type]; ok {
for _, vv := range v {
if vv.LastModified.After(ovalContent.LastModified) {
logging.Log.Debugf("%s ignored. DefID: %s ", cve.CveID, defPacks.def.DefinitionID)
logging.Log.Debugf("%s ignored. DefID: %s ", cve.CveID, defpacks.def.DefinitionID)
} else {
logging.Log.Debugf("%s OVAL will be overwritten. DefID: %s", cve.CveID, defPacks.def.DefinitionID)
logging.Log.Debugf("%s OVAL will be overwritten. DefID: %s", cve.CveID, defpacks.def.DefinitionID)
}
}
} else {
logging.Log.Debugf("%s also detected by OVAL. DefID: %s", cve.CveID, defPacks.def.DefinitionID)
logging.Log.Debugf("%s also detected by OVAL. DefID: %s", cve.CveID, defpacks.def.DefinitionID)
cveContents = models.CveContents{}
}
vinfo.Confidences.AppendIfMissing(models.OvalMatch)
cveContents[ctype] = append(cveContents[ctype], ovalContent)
cveContents[ovalContent.Type] = []models.CveContent{*ovalContent}
vinfo.CveContents = cveContents
}
vinfo.DistroAdvisories.AppendIfMissing(
o.convertToDistroAdvisory(&defPacks.def))
o.convertToDistroAdvisory(&defpacks.def))
// uniq(vinfo.AffectedPackages[].Name + defPacks.binpkgFixstat(map[string(=package name)]fixStat{}))
collectBinpkgFixstat := defPacks{
binpkgFixstat: map[string]fixStat{},
}
for packName, fixStatus := range defpacks.binpkgFixstat {
collectBinpkgFixstat.binpkgFixstat[packName] = fixStatus
}
// uniq(vinfo.PackNames + defPacks.actuallyAffectedPackNames)
for _, pack := range vinfo.AffectedPackages {
if stat, ok := defPacks.binpkgFixstat[pack.Name]; !ok {
defPacks.binpkgFixstat[pack.Name] = fixStat{
if stat, ok := collectBinpkgFixstat.binpkgFixstat[pack.Name]; !ok {
collectBinpkgFixstat.binpkgFixstat[pack.Name] = fixStat{
notFixedYet: pack.NotFixedYet,
fixedIn: pack.FixedIn,
}
} else if stat.notFixedYet {
defPacks.binpkgFixstat[pack.Name] = fixStat{
collectBinpkgFixstat.binpkgFixstat[pack.Name] = fixStat{
notFixedYet: true,
fixedIn: pack.FixedIn,
}
}
}
vinfo.AffectedPackages = defPacks.toPackStatuses()
vinfo.AffectedPackages = collectBinpkgFixstat.toPackStatuses()
vinfo.AffectedPackages.Sort()
r.ScannedCves[cve.CveID] = vinfo
}
@@ -178,18 +200,19 @@ func (o RedHatBase) convertToDistroAdvisory(def *ovalmodels.Definition) *models.
}
func (o RedHatBase) convertToModel(cveID string, def *ovalmodels.Definition) *models.CveContent {
refs := make([]models.Reference, 0, len(def.References))
for _, r := range def.References {
refs = append(refs, models.Reference{
Link: r.RefURL,
Source: r.Source,
RefID: r.RefID,
})
}
for _, cve := range def.Advisory.Cves {
if cve.CveID != cveID {
continue
}
var refs []models.Reference
for _, r := range def.References {
refs = append(refs, models.Reference{
Link: r.RefURL,
Source: r.Source,
RefID: r.RefID,
})
}
score2, vec2 := o.parseCvss2(cve.Cvss2)
score3, vec3 := o.parseCvss3(cve.Cvss3)

View File

@@ -8,7 +8,7 @@ import (
"testing"
"github.com/future-architect/vuls/models"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
ovalmodels "github.com/vulsio/goval-dictionary/models"
)
func TestParseCvss2(t *testing.T) {
@@ -129,15 +129,68 @@ func TestPackNamesOfUpdate(t *testing.T) {
},
},
},
{
in: models.ScanResult{
ScannedCves: models.VulnInfos{
"CVE-2000-1000": models.VulnInfo{
AffectedPackages: models.PackageFixStatuses{
{Name: "packA"},
},
},
"CVE-2000-1001": models.VulnInfo{
AffectedPackages: models.PackageFixStatuses{
{Name: "packC"},
},
},
},
},
defPacks: defPacks{
def: ovalmodels.Definition{
Advisory: ovalmodels.Advisory{
Cves: []ovalmodels.Cve{
{
CveID: "CVE-2000-1000",
},
{
CveID: "CVE-2000-1001",
},
},
},
},
binpkgFixstat: map[string]fixStat{
"packB": {
notFixedYet: false,
},
},
},
out: models.ScanResult{
ScannedCves: models.VulnInfos{
"CVE-2000-1000": models.VulnInfo{
AffectedPackages: models.PackageFixStatuses{
{Name: "packA"},
{Name: "packB", NotFixedYet: false},
},
},
"CVE-2000-1001": models.VulnInfo{
AffectedPackages: models.PackageFixStatuses{
{Name: "packB", NotFixedYet: false},
{Name: "packC"},
},
},
},
},
},
}
// util.Log = util.Logger{}.NewCustomLogger()
for i, tt := range tests {
RedHat{}.update(&tt.in, tt.defPacks)
e := tt.out.ScannedCves["CVE-2000-1000"].AffectedPackages
a := tt.in.ScannedCves["CVE-2000-1000"].AffectedPackages
if !reflect.DeepEqual(a, e) {
t.Errorf("[%d] expected: %v\n actual: %v\n", i, e, a)
for cveid := range tt.out.ScannedCves {
e := tt.out.ScannedCves[cveid].AffectedPackages
a := tt.in.ScannedCves[cveid].AffectedPackages
if !reflect.DeepEqual(a, e) {
t.Errorf("[%d] expected: %v\n actual: %v\n", i, e, a)
}
}
}
}

View File

@@ -8,7 +8,7 @@ import (
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
ovalmodels "github.com/vulsio/goval-dictionary/models"
)
// SUSE is the struct of SUSE Linux
@@ -55,23 +55,23 @@ func (o SUSE) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
for _, vuln := range r.ScannedCves {
if conts, ok := vuln.CveContents[models.SUSE]; ok {
for _, cont := range conts {
for i, cont := range conts {
cont.SourceLink = "https://security-tracker.debian.org/tracker/" + cont.CveID
vuln.CveContents[models.SUSE] = append(vuln.CveContents[models.SUSE], cont)
vuln.CveContents[models.SUSE][i] = cont
}
}
}
return len(relatedDefs.entries), nil
}
func (o SUSE) update(r *models.ScanResult, defPacks defPacks) {
ovalContent := *o.convertToModel(&defPacks.def)
func (o SUSE) update(r *models.ScanResult, defpacks defPacks) {
ovalContent := *o.convertToModel(&defpacks.def)
ovalContent.Type = models.NewCveContentType(o.family)
vinfo, ok := r.ScannedCves[defPacks.def.Title]
vinfo, ok := r.ScannedCves[defpacks.def.Title]
if !ok {
logging.Log.Debugf("%s is newly detected by OVAL", defPacks.def.Title)
logging.Log.Debugf("%s is newly detected by OVAL", defpacks.def.Title)
vinfo = models.VulnInfo{
CveID: defPacks.def.Title,
CveID: defpacks.def.Title,
Confidences: models.Confidences{models.OvalMatch},
CveContents: models.NewCveContents(ovalContent),
}
@@ -79,26 +79,33 @@ func (o SUSE) update(r *models.ScanResult, defPacks defPacks) {
cveContents := vinfo.CveContents
ctype := models.NewCveContentType(o.family)
if _, ok := vinfo.CveContents[ctype]; ok {
logging.Log.Debugf("%s OVAL will be overwritten", defPacks.def.Title)
logging.Log.Debugf("%s OVAL will be overwritten", defpacks.def.Title)
} else {
logging.Log.Debugf("%s is also detected by OVAL", defPacks.def.Title)
logging.Log.Debugf("%s is also detected by OVAL", defpacks.def.Title)
cveContents = models.CveContents{}
}
vinfo.Confidences.AppendIfMissing(models.OvalMatch)
cveContents[ctype] = append(cveContents[ctype], ovalContent)
cveContents[ctype] = []models.CveContent{ovalContent}
vinfo.CveContents = cveContents
}
// uniq(vinfo.PackNames + defPacks.actuallyAffectedPackNames)
// uniq(vinfo.AffectedPackages[].Name + defPacks.binpkgFixstat(map[string(=package name)]fixStat{}))
collectBinpkgFixstat := defPacks{
binpkgFixstat: map[string]fixStat{},
}
for packName, fixStatus := range defpacks.binpkgFixstat {
collectBinpkgFixstat.binpkgFixstat[packName] = fixStatus
}
for _, pack := range vinfo.AffectedPackages {
defPacks.binpkgFixstat[pack.Name] = fixStat{
collectBinpkgFixstat.binpkgFixstat[pack.Name] = fixStat{
notFixedYet: pack.NotFixedYet,
fixedIn: pack.FixedIn,
}
}
vinfo.AffectedPackages = defPacks.toPackStatuses()
vinfo.AffectedPackages = collectBinpkgFixstat.toPackStatuses()
vinfo.AffectedPackages.Sort()
r.ScannedCves[defPacks.def.Title] = vinfo
r.ScannedCves[defpacks.def.Title] = vinfo
}
func (o SUSE) convertToModel(def *ovalmodels.Definition) *models.CveContent {

View File

@@ -20,9 +20,9 @@ import (
apkver "github.com/knqyf263/go-apk-version"
debver "github.com/knqyf263/go-deb-version"
rpmver "github.com/knqyf263/go-rpm-version"
"github.com/kotakanbe/goval-dictionary/db"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
"github.com/parnurzeal/gorequest"
"github.com/vulsio/goval-dictionary/db"
ovalmodels "github.com/vulsio/goval-dictionary/models"
"golang.org/x/xerrors"
)

View File

@@ -10,7 +10,7 @@ import (
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/models"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
ovalmodels "github.com/vulsio/goval-dictionary/models"
)
func TestUpsert(t *testing.T) {

View File

@@ -621,7 +621,7 @@ func getPlusDiffCves(previous, current models.ScanResult) models.VulnInfos {
// TODO commented out because a bug of diff logic when multiple oval defs found for a certain CVE-ID and same updated_at
// if these OVAL defs have different affected packages, this logic detects as updated.
// This logic will be uncomented after integration with gost https://github.com/knqyf263/gost
// This logic will be uncomented after integration with gost https://github.com/vulsio/gost
// } else if isCveFixed(v, previous) {
// updated[v.CveID] = v
// logging.Log.Debugf("fixed: %s", v.CveID)

View File

@@ -19,7 +19,7 @@ import (
// EnsureUUIDs generate a new UUID of the scan target server if UUID is not assigned yet.
// And then set the generated UUID to config.toml and scan results.
func EnsureUUIDs(servers map[string]config.ServerInfo, path string, scanResults models.ScanResults) (err error) {
needsOverwrite, err := ensure(servers, path, scanResults, uuid.GenerateUUID)
needsOverwrite, err := ensure(servers, scanResults, uuid.GenerateUUID)
if err != nil {
return xerrors.Errorf("Failed to ensure UUIDs. err: %w", err)
}
@@ -30,7 +30,7 @@ func EnsureUUIDs(servers map[string]config.ServerInfo, path string, scanResults
return writeToFile(config.Conf, path)
}
func ensure(servers map[string]config.ServerInfo, path string, scanResults models.ScanResults, generateFunc func() (string, error)) (needsOverwrite bool, err error) {
func ensure(servers map[string]config.ServerInfo, scanResults models.ScanResults, generateFunc func() (string, error)) (needsOverwrite bool, err error) {
for i, r := range scanResults {
serverInfo := servers[r.ServerName]
if serverInfo.UUIDs == nil {

View File

@@ -377,7 +377,7 @@ func Test_ensure(t *testing.T) {
}
for i, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotNeedsOverwrite, err := ensure(tt.args.servers, tt.args.path, tt.args.scanResults, tt.args.generateFunc)
gotNeedsOverwrite, err := ensure(tt.args.servers, tt.args.scanResults, tt.args.generateFunc)
if (err != nil) != tt.wantErr {
t.Errorf("ensure() error = %v, wantErr %v", err, tt.wantErr)
return

View File

@@ -26,14 +26,22 @@ import (
"golang.org/x/xerrors"
// Import library scanner
_ "github.com/aquasecurity/fanal/analyzer/library/bundler"
_ "github.com/aquasecurity/fanal/analyzer/library/cargo"
_ "github.com/aquasecurity/fanal/analyzer/library/composer"
_ "github.com/aquasecurity/fanal/analyzer/library/gomod"
_ "github.com/aquasecurity/fanal/analyzer/library/npm"
_ "github.com/aquasecurity/fanal/analyzer/library/pipenv"
_ "github.com/aquasecurity/fanal/analyzer/library/poetry"
_ "github.com/aquasecurity/fanal/analyzer/library/yarn"
_ "github.com/aquasecurity/fanal/analyzer/language/dotnet/nuget"
_ "github.com/aquasecurity/fanal/analyzer/language/golang/binary"
_ "github.com/aquasecurity/fanal/analyzer/language/golang/mod"
_ "github.com/aquasecurity/fanal/analyzer/language/java/jar"
_ "github.com/aquasecurity/fanal/analyzer/language/nodejs/npm"
_ "github.com/aquasecurity/fanal/analyzer/language/nodejs/yarn"
_ "github.com/aquasecurity/fanal/analyzer/language/php/composer"
_ "github.com/aquasecurity/fanal/analyzer/language/python/pip"
_ "github.com/aquasecurity/fanal/analyzer/language/python/pipenv"
_ "github.com/aquasecurity/fanal/analyzer/language/python/poetry"
_ "github.com/aquasecurity/fanal/analyzer/language/ruby/bundler"
_ "github.com/aquasecurity/fanal/analyzer/language/rust/cargo"
// _ "github.com/aquasecurity/fanal/analyzer/language/ruby/gemspec"
// _ "github.com/aquasecurity/fanal/analyzer/language/nodejs/pkg"
// _ "github.com/aquasecurity/fanal/analyzer/language/python/packaging"
nmap "github.com/Ullaakut/nmap/v2"
)

View File

@@ -4,13 +4,18 @@ import (
"reflect"
"testing"
_ "github.com/aquasecurity/fanal/analyzer/library/bundler"
_ "github.com/aquasecurity/fanal/analyzer/library/cargo"
_ "github.com/aquasecurity/fanal/analyzer/library/composer"
_ "github.com/aquasecurity/fanal/analyzer/library/npm"
_ "github.com/aquasecurity/fanal/analyzer/library/pipenv"
_ "github.com/aquasecurity/fanal/analyzer/library/poetry"
_ "github.com/aquasecurity/fanal/analyzer/library/yarn"
_ "github.com/aquasecurity/fanal/analyzer/language/dotnet/nuget"
_ "github.com/aquasecurity/fanal/analyzer/language/golang/binary"
_ "github.com/aquasecurity/fanal/analyzer/language/golang/mod"
_ "github.com/aquasecurity/fanal/analyzer/language/java/jar"
_ "github.com/aquasecurity/fanal/analyzer/language/nodejs/npm"
_ "github.com/aquasecurity/fanal/analyzer/language/nodejs/yarn"
_ "github.com/aquasecurity/fanal/analyzer/language/php/composer"
_ "github.com/aquasecurity/fanal/analyzer/language/python/pip"
_ "github.com/aquasecurity/fanal/analyzer/language/python/pipenv"
_ "github.com/aquasecurity/fanal/analyzer/language/python/poetry"
_ "github.com/aquasecurity/fanal/analyzer/language/ruby/bundler"
_ "github.com/aquasecurity/fanal/analyzer/language/rust/cargo"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
)

View File

@@ -3,24 +3,23 @@ package scanner
import (
"github.com/aquasecurity/fanal/types"
"github.com/future-architect/vuls/models"
trivyTypes "github.com/aquasecurity/trivy/pkg/types"
)
func convertLibWithScanner(apps []types.Application) ([]models.LibraryScanner, error) {
scanners := []models.LibraryScanner{}
for _, app := range apps {
libs := []trivyTypes.Library{}
libs := []models.Library{}
for _, lib := range app.Libraries {
libs = append(libs, trivyTypes.Library{
Name: lib.Library.Name,
Version: lib.Library.Version,
libs = append(libs, models.Library{
Name: lib.Name,
Version: lib.Version,
FilePath: lib.FilePath,
})
}
scanners = append(scanners, models.LibraryScanner{
Type: app.Type,
Path: app.FilePath,
Libs: libs,
Type: app.Type,
LockfilePath: app.FilePath,
Libs: libs,
})
}
return scanners, nil

View File

@@ -34,7 +34,7 @@ func (*DiscoverCmd) Usage() string {
}
// SetFlags set flag
func (p *DiscoverCmd) SetFlags(f *flag.FlagSet) {
func (p *DiscoverCmd) SetFlags(_ *flag.FlagSet) {
}
// Execute execute

View File

@@ -43,7 +43,7 @@ func (p *HistoryCmd) SetFlags(f *flag.FlagSet) {
}
// Execute execute
func (p *HistoryCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
func (p *HistoryCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
dirs, err := reporter.ListValidJSONDirs(config.Conf.ResultsDir)
if err != nil {
return subcommands.ExitFailure

View File

@@ -90,7 +90,7 @@ func (p *ServerCmd) SetFlags(f *flag.FlagSet) {
}
// Execute execute
func (p *ServerCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
func (p *ServerCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
logging.Log = logging.NewCustomLogger(config.Conf.Debug, config.Conf.Quiet, config.Conf.LogToFile, config.Conf.LogDir, "", "")
logging.Log.Infof("vuls-%s-%s", config.Version, config.Revision)
if err := config.Load(p.configPath, ""); err != nil {

View File

@@ -301,10 +301,7 @@ func cursorMoveMiddle(g *gocui.Gui, v *gocui.View) error {
return err
}
}
if err := onMovingCursorRedrawView(g, v); err != nil {
return err
}
return nil
return onMovingCursorRedrawView(g, v)
}
func cursorPageDown(g *gocui.Gui, v *gocui.View) error {
@@ -505,7 +502,7 @@ func showMsg(g *gocui.Gui, v *gocui.View) error {
return nil
}
func delMsg(g *gocui.Gui, v *gocui.View) error {
func delMsg(g *gocui.Gui, _ *gocui.View) error {
if err := g.DeleteView("msg"); err != nil {
return err
}
@@ -513,7 +510,7 @@ func delMsg(g *gocui.Gui, v *gocui.View) error {
return err
}
func quit(g *gocui.Gui, v *gocui.View) error {
func quit(_ *gocui.Gui, _ *gocui.View) error {
return gocui.ErrQuit
}