Compare commits

..

1 Commits

Author SHA1 Message Date
Kota Kanbe
a6e53e4c1f fix build-tags 2021-06-09 09:23:23 +09:00
95 changed files with 4372 additions and 57671 deletions

View File

@@ -1,45 +0,0 @@
name: Publish Docker image
on:
push:
branches:
- 'master'
tags:
- '*'
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Docker meta
id: meta
uses: docker/metadata-action@v3
with:
images: vuls/vuls
tags: |
type=ref,event=tag
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v2
with:
push: true
tags: |
vuls/vuls:latest
${{ steps.meta.outputs.tags }}
secrets: |
"github_token=${{ secrets.GITHUB_TOKEN }}"

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.42
version: v1.32
args: --timeout=10m
# Optional: working directory, useful for monorepos

6
.gitignore vendored
View File

@@ -1,6 +1,5 @@
.vscode
*.txt
*.swp
*.sqlite3*
*.db
tags
@@ -9,13 +8,10 @@ coverage.out
issues/
vendor/
log/
results
!integration/data/results
results/
config.toml
!setup/docker/*
.DS_Store
dist/
.idea
vuls.*
vuls
!cmd/vuls

View File

@@ -1,44 +1,14 @@
name: golang-ci
linters-settings:
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:
errcheck:
#exclude: /path/to/file.txt
linters:
disable-all: true
enable:
- goimports
- revive
- golint
- govet
- misspell
- errcheck

View File

@@ -1,30 +0,0 @@
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

@@ -10,7 +10,10 @@ ENV REPOSITORY github.com/future-architect/vuls
COPY . $GOPATH/src/$REPOSITORY
RUN cd $GOPATH/src/$REPOSITORY && make install
FROM alpine:3.14
FROM alpine:3.13
LABEL maintainer hikachan sadayuki-matsuno
ENV LOGDIR /var/log/vuls
ENV WORKDIR /vuls

View File

@@ -24,7 +24,7 @@ CGO_UNABLED := CGO_ENABLED=0 go
GO_OFF := GO111MODULE=off go
all: b
all: build
build: ./cmd/vuls/main.go pretest fmt
$(GO) build -a -ldflags "$(LDFLAGS)" -o vuls ./cmd/vuls
@@ -42,15 +42,12 @@ install-scanner: ./cmd/scanner/main.go
$(CGO_UNABLED) install -tags=scanner -ldflags "$(LDFLAGS)" ./cmd/scanner
lint:
$(GO_OFF) get -u github.com/mgechev/revive
revive -config ./.revive.toml -formatter plain $(PKGS)
$(GO_OFF) get -u golang.org/x/lint/golint
golint $(PKGS)
vet:
echo $(PKGS) | xargs env $(GO) vet || exit;
golangci:
golangci-lint run
fmt:
gofmt -s -w $(SRCS)
@@ -60,7 +57,7 @@ mlint:
fmtcheck:
$(foreach file,$(SRCS),gofmt -s -d $(file);)
pretest: lint vet fmtcheck golangci
pretest: lint vet fmtcheck
test:
$(GO) test -cover -v ./... || exit;
@@ -92,7 +89,7 @@ NOW=$(shell date --iso-8601=seconds)
NOW_JSON_DIR := '${BASE_DIR}/$(NOW)'
ONE_SEC_AFTER=$(shell date -d '+1 second' --iso-8601=seconds)
ONE_SEC_AFTER_JSON_DIR := '${BASE_DIR}/$(ONE_SEC_AFTER)'
LIBS := 'gemfile' 'pipfile' 'poetry' 'composer' 'packagelock' 'yarn' 'cargo' 'gomod' 'nvd_exact' 'nvd_rough' 'nvd_vendor_product' 'nvd_match_no_jvn' 'jvn_vendor_product' 'jvn_vendor_product_nover'
LIBS := 'gemfile' 'pipfile' 'poetry' 'composer' 'packagelock' 'yarn' 'cargo' 'gomod'
diff:
# git clone git@github.com:vulsio/vulsctl.git
@@ -111,14 +108,14 @@ endif
sleep 1
./vuls.old scan -config=./integration/int-config.toml --results-dir=${BASE_DIR} ${LIBS}
cp ${BASE_DIR}/current/*.json ${NOW_JSON_DIR}
- cp integration/data/results/*.json ${NOW_JSON_DIR}
cp integration/data/results/*.json ${NOW_JSON_DIR}
./vuls.old report --format-json --refresh-cve --results-dir=${BASE_DIR} -config=./integration/int-config.toml ${NOW}
mkdir -p ${ONE_SEC_AFTER_JSON_DIR}
sleep 1
./vuls.new scan -config=./integration/int-config.toml --results-dir=${BASE_DIR} ${LIBS}
cp ${BASE_DIR}/current/*.json ${ONE_SEC_AFTER_JSON_DIR}
- cp integration/data/results/*.json ${ONE_SEC_AFTER_JSON_DIR}
cp integration/data/results/*.json ${ONE_SEC_AFTER_JSON_DIR}
./vuls.new report --format-json --refresh-cve --results-dir=${BASE_DIR} -config=./integration/int-config.toml ${ONE_SEC_AFTER}
$(call sed-d)
@@ -144,14 +141,14 @@ endif
sleep 1
./vuls.old scan -config=./integration/int-config.toml --results-dir=${BASE_DIR} ${LIBS}
cp -f ${BASE_DIR}/current/*.json ${NOW_JSON_DIR}
- cp integration/data/results/*.json ${NOW_JSON_DIR}
cp integration/data/results/*.json ${NOW_JSON_DIR}
./vuls.old report --format-json --refresh-cve --results-dir=${BASE_DIR} -config=./integration/int-redis-config.toml ${NOW}
mkdir -p ${ONE_SEC_AFTER_JSON_DIR}
sleep 1
./vuls.new scan -config=./integration/int-config.toml --results-dir=${BASE_DIR} ${LIBS}
cp -f ${BASE_DIR}/current/*.json ${ONE_SEC_AFTER_JSON_DIR}
- cp integration/data/results/*.json ${ONE_SEC_AFTER_JSON_DIR}
cp integration/data/results/*.json ${ONE_SEC_AFTER_JSON_DIR}
./vuls.new report --format-json --refresh-cve --results-dir=${BASE_DIR} -config=./integration/int-redis-config.toml ${ONE_SEC_AFTER}
$(call sed-d)
@@ -243,4 +240,4 @@ define count-cve
for jsonfile in ${ONE_SEC_AFTER_JSON_DIR}/*.json ; do \
echo $$jsonfile; cat $$jsonfile | jq ".scannedCves | length" ; \
done
endef
endef

View File

@@ -50,7 +50,7 @@ Vuls is a tool created to solve the problems listed above. It has the following
[Supports major Linux/FreeBSD](https://vuls.io/docs/en/supported-os.html)
- Alpine, Amazon Linux, CentOS, Alma Linux, Rocky Linux, Debian, Oracle Linux, Raspbian, RHEL, SUSE Enterprise Linux, and Ubuntu
- Alpine, Amazon Linux, CentOS, Debian, Oracle Linux, Raspbian, RHEL, SUSE Enterprise Linux, and Ubuntu
- FreeBSD
- Cloud, on-premise, Running Docker Container
@@ -71,7 +71,6 @@ Vuls is a tool created to solve the problems listed above. It has the following
- [Alpine-secdb](https://git.alpinelinux.org/cgit/alpine-secdb/)
- [Red Hat Security Advisories](https://access.redhat.com/security/security-updates/)
- [Debian Security Bug Tracker](https://security-tracker.debian.org/tracker/)
- [Ubuntu CVE Tracker](https://people.canonical.com/~ubuntu-security/cve/)
- Commands(yum, zypper, pkg-audit)
- RHSA / ALAS / ELSA / FreeBSD-SA
@@ -80,8 +79,6 @@ Vuls is a tool created to solve the problems listed above. It has the following
- PoC, Exploit
- [Exploit Database](https://www.exploit-db.com/)
- [Metasploit-Framework modules](https://www.rapid7.com/db/?q=&type=metasploit)
- [qazbnm456/awesome-cve-poc](https://github.com/qazbnm456/awesome-cve-poc)
- [nomi-sec/PoC-in-GitHub](https://github.com/nomi-sec/PoC-in-GitHub)
- CERT
- [US-CERT](https://www.us-cert.gov/ncas/alerts)
@@ -103,15 +100,15 @@ Vuls is a tool created to solve the problems listed above. It has the following
- Scan without root privilege, no dependencies
- Almost no load on the scan target server
- Offline mode scan with no internet access. (CentOS, Alma Linux, Rocky Linux, Debian, Oracle Linux, Red Hat, and Ubuntu)
- Offline mode scan with no internet access. (CentOS, Debian, Oracle Linux, Red Hat, and Ubuntu)
[Fast Root Scan](https://vuls.io/docs/en/architecture-fast-root-scan.html)
- Scan with root privilege
- Almost no load on the scan target server
- Detect processes affected by update using yum-ps (Amazon Linux, CentOS, Alma Linux, Rocky Linux, Oracle Linux, and RedHat)
- Detect processes affected by update using yum-ps (Amazon Linux, CentOS, Oracle Linux, and RedHat)
- Detect processes which updated before but not restarting yet using checkrestart of debian-goodies (Debian and Ubuntu)
- Offline mode scan with no internet access. (CentOS, Alma Linux, Rocky Linux, Debian, Oracle Linux, Red Hat, and Ubuntu)
- Offline mode scan with no internet access. (CentOS, Debian, Oracle Linux, Red Hat, and Ubuntu)
### [Remote, Local scan mode, Server mode](https://vuls.io/docs/en/architecture-remote-local.html)

View File

@@ -42,17 +42,16 @@ type Config struct {
Exploit ExploitConf `json:"exploit,omitempty"`
Metasploit MetasploitConf `json:"metasploit,omitempty"`
Slack SlackConf `json:"-"`
EMail SMTPConf `json:"-"`
HTTP HTTPConf `json:"-"`
Syslog SyslogConf `json:"-"`
AWS AWSConf `json:"-"`
Azure AzureConf `json:"-"`
ChatWork ChatWorkConf `json:"-"`
GoogleChat GoogleChatConf `json:"-"`
Telegram TelegramConf `json:"-"`
WpScan WpScanConf `json:"-"`
Saas SaasConf `json:"-"`
Slack SlackConf `json:"-"`
EMail SMTPConf `json:"-"`
HTTP HTTPConf `json:"-"`
Syslog SyslogConf `json:"-"`
AWS AWSConf `json:"-"`
Azure AzureConf `json:"-"`
ChatWork ChatWorkConf `json:"-"`
Telegram TelegramConf `json:"-"`
WpScan WpScanConf `json:"-"`
Saas SaasConf `json:"-"`
ReportOpts
}
@@ -69,17 +68,17 @@ type ScanOpts struct {
// ReportOpts is options for report
type ReportOpts struct {
CvssScoreOver float64 `json:"cvssScoreOver,omitempty"`
ConfidenceScoreOver int `json:"confidenceScoreOver,omitempty"`
TrivyCacheDBDir string `json:"trivyCacheDBDir,omitempty"`
NoProgress bool `json:"noProgress,omitempty"`
RefreshCve bool `json:"refreshCve,omitempty"`
IgnoreUnfixed bool `json:"ignoreUnfixed,omitempty"`
IgnoreUnscoredCves bool `json:"ignoreUnscoredCves,omitempty"`
DiffPlus bool `json:"diffPlus,omitempty"`
DiffMinus bool `json:"diffMinus,omitempty"`
Diff bool `json:"diff,omitempty"`
Lang string `json:"lang,omitempty"`
// refactored
CvssScoreOver float64 `json:"cvssScoreOver,omitempty"`
TrivyCacheDBDir string `json:"trivyCacheDBDir,omitempty"`
NoProgress bool `json:"noProgress,omitempty"`
RefreshCve bool `json:"refreshCve,omitempty"`
IgnoreUnfixed bool `json:"ignoreUnfixed,omitempty"`
IgnoreUnscoredCves bool `json:"ignoreUnscoredCves,omitempty"`
DiffPlus bool `json:"diffPlus,omitempty"`
DiffMinus bool `json:"diffMinus,omitempty"`
Diff bool `json:"diff,omitempty"`
Lang string `json:"lang,omitempty"`
}
// ValidateOnConfigtest validates
@@ -158,7 +157,6 @@ func (c *Config) ValidateOnReport() bool {
&c.EMail,
&c.Slack,
&c.ChatWork,
&c.GoogleChat,
&c.Telegram,
&c.Syslog,
&c.HTTP,
@@ -230,19 +228,18 @@ type ServerInfo struct {
GitHubRepos map[string]GitHubConf `toml:"githubs" json:"githubs,omitempty"` // key: owner/repo
UUIDs map[string]string `toml:"uuids,omitempty" json:"uuids,omitempty"`
Memo string `toml:"memo,omitempty" json:"memo,omitempty"`
Enablerepo []string `toml:"enablerepo,omitempty" json:"enablerepo,omitempty"` // For CentOS, Alma, Rocky, RHEL, Amazon
Enablerepo []string `toml:"enablerepo,omitempty" json:"enablerepo,omitempty"` // For CentOS, RHEL, Amazon
Optional map[string]interface{} `toml:"optional,omitempty" json:"optional,omitempty"` // Optional key-value set that will be outputted to JSON
Lockfiles []string `toml:"lockfiles,omitempty" json:"lockfiles,omitempty"` // ie) path/to/package-lock.json
FindLock bool `toml:"findLock,omitempty" json:"findLock,omitempty"`
Type string `toml:"type,omitempty" json:"type,omitempty"` // "pseudo" or ""
IgnoredJSONKeys []string `toml:"ignoredJSONKeys,omitempty" json:"ignoredJSONKeys,omitempty"`
IPv4Addrs []string `toml:"-" json:"ipv4Addrs,omitempty"`
IPv6Addrs []string `toml:"-" json:"ipv6Addrs,omitempty"`
IPSIdentifiers map[string]string `toml:"-" json:"ipsIdentifiers,omitempty"`
WordPress *WordPressConf `toml:"wordpress,omitempty" json:"wordpress,omitempty"`
PortScan *PortScanConf `toml:"portscan,omitempty" json:"portscan,omitempty"`
IPv4Addrs []string `toml:"-" json:"ipv4Addrs,omitempty"`
IPv6Addrs []string `toml:"-" json:"ipv6Addrs,omitempty"`
IPSIdentifiers map[string]string `toml:"-" json:"ipsIdentifiers,omitempty"`
// internal use
LogMsgAnsiColor string `toml:"-" json:"-"` // DebugLog Color
Container Container `toml:"-" json:"-"`

View File

@@ -1,32 +0,0 @@
package config
import (
"github.com/asaskevich/govalidator"
"golang.org/x/xerrors"
)
// GoogleChatConf is GoogleChat config
type GoogleChatConf struct {
WebHookURL string `valid:"url" json:"-" toml:"webHookURL,omitempty"`
SkipIfNoCve bool `valid:"type(bool)" json:"-" toml:"skipIfNoCve"`
ServerNameRegexp string `valid:"type(string)" json:"-" toml:"serverNameRegexp,omitempty"`
Enabled bool `valid:"type(bool)" json:"-" toml:"-"`
}
// Validate validates configuration
func (c *GoogleChatConf) Validate() (errs []error) {
if !c.Enabled {
return
}
if len(c.WebHookURL) == 0 {
errs = append(errs, xerrors.New("googleChatConf.webHookURL must not be empty"))
}
if !govalidator.IsRegex(c.ServerNameRegexp) {
errs = append(errs, xerrors.New("googleChatConf.serverNameRegexp must be regex"))
}
_, err := govalidator.ValidateStruct(c)
if err != nil {
errs = append(errs, err)
}
return
}

View File

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

View File

@@ -75,14 +75,6 @@ func GetEOL(family, release string) (eol EOL, found bool) {
"7": {StandardSupportUntil: time.Date(2024, 6, 30, 23, 59, 59, 0, time.UTC)},
"8": {StandardSupportUntil: time.Date(2021, 12, 31, 23, 59, 59, 0, time.UTC)},
}[major(release)]
case constant.Alma:
eol, found = map[string]EOL{
"8": {StandardSupportUntil: time.Date(2029, 12, 31, 23, 59, 59, 0, time.UTC)},
}[major(release)]
case constant.Rocky:
eol, found = map[string]EOL{
"8": {StandardSupportUntil: time.Date(2029, 5, 31, 23, 59, 59, 0, time.UTC)},
}[major(release)]
case constant.Oracle:
eol, found = map[string]EOL{
// Source:
@@ -110,7 +102,6 @@ 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
@@ -141,10 +132,10 @@ func GetEOL(family, release string) (eol EOL, found bool) {
StandardSupportUntil: time.Date(2025, 4, 1, 23, 59, 59, 0, time.UTC),
},
"20.10": {
StandardSupportUntil: time.Date(2021, 7, 22, 23, 59, 59, 0, time.UTC),
StandardSupportUntil: time.Date(2021, 7, 1, 23, 59, 59, 0, time.UTC),
},
"21.04": {
StandardSupportUntil: time.Date(2022, 1, 22, 23, 59, 59, 0, time.UTC),
StandardSupportUntil: time.Date(2022, 1, 1, 23, 59, 59, 0, time.UTC),
},
"21.10": {
StandardSupportUntil: time.Date(2022, 7, 1, 23, 59, 59, 0, time.UTC),
@@ -188,7 +179,6 @@ func GetEOL(family, release string) (eol EOL, found bool) {
"10": {Ended: true},
"11": {StandardSupportUntil: time.Date(2021, 9, 30, 23, 59, 59, 0, time.UTC)},
"12": {StandardSupportUntil: time.Date(2024, 6, 30, 23, 59, 59, 0, time.UTC)},
"13": {StandardSupportUntil: time.Date(2026, 1, 31, 23, 59, 59, 0, time.UTC)},
}[major(release)]
}
return

View File

@@ -111,56 +111,6 @@ func TestEOL_IsStandardSupportEnded(t *testing.T) {
extEnded: false,
found: false,
},
// Alma
{
name: "Alma Linux 8 supported",
fields: fields{family: Alma, release: "8"},
now: time.Date(2021, 7, 2, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "Alma Linux 8 EOL",
fields: fields{family: Alma, release: "8"},
now: time.Date(2029, 2, 1, 0, 0, 0, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "Alma Linux 9 Not Found",
fields: fields{family: Alma, release: "9"},
now: time.Date(2021, 7, 2, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: false,
},
// Rocky
{
name: "Rocky Linux 8 supported",
fields: fields{family: Rocky, release: "8"},
now: time.Date(2021, 7, 2, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "Rocky Linux 8 EOL",
fields: fields{family: Rocky, release: "8"},
now: time.Date(2026, 2, 1, 0, 0, 0, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "Rocky Linux 9 Not Found",
fields: fields{family: Rocky, release: "9"},
now: time.Date(2021, 7, 2, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: false,
},
//Oracle
{
name: "Oracle Linux 7 supported",
@@ -290,14 +240,6 @@ 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
@@ -366,14 +308,6 @@ func TestEOL_IsStandardSupportEnded(t *testing.T) {
extEnded: false,
found: true,
},
{
name: "freebsd 13 supported",
fields: fields{family: FreeBSD, release: "13"},
now: time.Date(2021, 7, 2, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "freebsd 10 eol",
fields: fields{family: FreeBSD, release: "10"},

View File

@@ -84,7 +84,7 @@ func (s ScanMode) String() string {
return ss + " mode"
}
func setScanMode(server *ServerInfo) error {
func setScanMode(server *ServerInfo, d 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, _ string) error {
func (c TOMLLoader) Load(pathToToml, keyPass 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, _ string) error {
index := 0
for name, server := range Conf.Servers {
server.ServerName = name
if err := setDefaultIfEmpty(&server); err != nil {
if err := setDefaultIfEmpty(&server, Conf.Default); err != nil {
return xerrors.Errorf("Failed to set default value to config. server: %s, err: %w", name, err)
}
if err := setScanMode(&server); err != nil {
if err := setScanMode(&server, Conf.Default); err != nil {
return xerrors.Errorf("Failed to set ScanMode: %w", err)
}
@@ -137,7 +137,7 @@ func (c TOMLLoader) Load(pathToToml, _ string) error {
return nil
}
func setDefaultIfEmpty(server *ServerInfo) error {
func setDefaultIfEmpty(server *ServerInfo, d ServerInfo) error {
if server.Type != constant.ServerTypePseudo {
if len(server.Host) == 0 {
return xerrors.Errorf("server.host is empty")

View File

@@ -17,12 +17,6 @@ const (
// CentOS is
CentOS = "centos"
// Alma is
Alma = "alma"
// Rocky is
Rocky = "rocky"
// Fedora is
// Fedora = "fedora"

View File

@@ -6,11 +6,8 @@ import (
"time"
"github.com/aquasecurity/fanal/analyzer/os"
ftypes "github.com/aquasecurity/fanal/types"
"github.com/aquasecurity/trivy/pkg/report"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/models"
)
@@ -25,7 +22,9 @@ func Parse(vulnJSON []byte, scanResult *models.ScanResult) (result *models.ScanR
vulnInfos := models.VulnInfos{}
uniqueLibraryScannerPaths := map[string]models.LibraryScanner{}
for _, trivyResult := range trivyResults {
setScanResultMeta(scanResult, &trivyResult)
if IsTrivySupportedOS(trivyResult.Type) {
overrideServerData(scanResult, &trivyResult)
}
for _, vuln := range trivyResult.Vulnerabilities {
if _, ok := vulnInfos[vuln.VulnerabilityID]; !ok {
vulnInfos[vuln.VulnerabilityID] = models.VulnInfo{
@@ -72,17 +71,17 @@ func Parse(vulnJSON []byte, scanResult *models.ScanResult) (result *models.ScanR
}
vulnInfo.CveContents = models.CveContents{
models.Trivy: []models.CveContent{{
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) {
if IsTrivySupportedOS(trivyResult.Type) {
pkgs[vuln.PkgName] = models.Package{
Name: vuln.PkgName,
Version: vuln.InstalledVersion,
@@ -94,6 +93,7 @@ func Parse(vulnJSON []byte, scanResult *models.ScanResult) (result *models.ScanR
FixedIn: vuln.FixedVersion,
})
} else {
// LibraryScanの結果
vulnInfo.LibraryFixedIns = append(vulnInfo.LibraryFixedIns, models.LibraryFixedIn{
Key: trivyResult.Type,
Name: vuln.PkgName,
@@ -101,7 +101,6 @@ func Parse(vulnJSON []byte, scanResult *models.ScanResult) (result *models.ScanR
FixedIn: vuln.FixedVersion,
})
libScanner := uniqueLibraryScannerPaths[trivyResult.Target]
libScanner.Type = trivyResult.Type
libScanner.Libs = append(libScanner.Libs, types.Library{
Name: vuln.PkgName,
Version: vuln.InstalledVersion,
@@ -129,7 +128,6 @@ func Parse(vulnJSON []byte, scanResult *models.ScanResult) (result *models.ScanR
})
libscanner := models.LibraryScanner{
Type: v.Type,
Path: path,
Libs: libraries,
}
@@ -144,70 +142,39 @@ func Parse(vulnJSON []byte, scanResult *models.ScanResult) (result *models.ScanR
return scanResult, nil
}
const trivyTarget = "trivy-target"
// 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
}
func setScanResultMeta(scanResult *models.ScanResult, trivyResult *report.Result) {
if isTrivySupportedOS(trivyResult.Type) {
scanResult.Family = trivyResult.Type
scanResult.ServerName = trivyResult.Target
scanResult.Optional = map[string]interface{}{
trivyTarget: trivyResult.Target,
}
} else if isTrivySupportedLib(trivyResult.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: trivyResult.Target,
}
}
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,
}
scanResult.ScannedAt = time.Now()
scanResult.ScannedBy = "trivy"
scanResult.ScannedVia = "trivy"
}
// isTrivySupportedOS :
func isTrivySupportedOS(family string) bool {
supportedFamilies := map[string]interface{}{
os.RedHat: struct{}{},
os.Debian: struct{}{},
os.Ubuntu: struct{}{},
os.CentOS: 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
}
func isTrivySupportedLib(typestr string) bool {
supportedLibs := map[string]interface{}{
ftypes.Bundler: struct{}{},
ftypes.Cargo: struct{}{},
ftypes.Composer: struct{}{},
ftypes.Npm: struct{}{},
ftypes.NuGet: struct{}{},
ftypes.Pip: struct{}{},
ftypes.Pipenv: struct{}{},
ftypes.Poetry: struct{}{},
ftypes.Yarn: struct{}{},
ftypes.Jar: struct{}{},
ftypes.GoBinary: struct{}{},
ftypes.GoMod: struct{}{},
}
_, ok := supportedLibs[typestr]
return ok
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package detector
@@ -16,9 +15,9 @@ import (
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/util"
cvedb "github.com/vulsio/go-cve-dictionary/db"
cvelog "github.com/vulsio/go-cve-dictionary/log"
cvemodels "github.com/vulsio/go-cve-dictionary/models"
cvedb "github.com/kotakanbe/go-cve-dictionary/db"
cvelog "github.com/kotakanbe/go-cve-dictionary/log"
cvemodels "github.com/kotakanbe/go-cve-dictionary/models"
)
type goCveDictClient struct {
@@ -27,9 +26,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 {
return nil, err
}
cvelog.SetLogger(o.Debug, o.Quiet, false, o.LogToFile, o.LogDir)
driver, locked, err := newCveDB(cnf)
if locked {
@@ -56,7 +53,11 @@ func (api goCveDictClient) fetchCveDetails(cveIDs []string) (cveDetails []cvemod
if err != nil {
return nil, xerrors.Errorf("Failed to fetch CVE. err: %w", err)
}
cveDetails = append(cveDetails, *cveDetail)
if len(cveDetail.CveID) == 0 {
cveDetails = append(cveDetails, cvemodels.CveDetail{CveID: cveID})
} else {
cveDetails = append(cveDetails, *cveDetail)
}
}
return
}
@@ -102,7 +103,13 @@ func (api goCveDictClient) fetchCveDetailsViaHTTP(cveIDs []string) (cveDetails [
for range cveIDs {
select {
case res := <-resChan:
cveDetails = append(cveDetails, res.CveDetail)
if len(res.CveDetail.CveID) == 0 {
cveDetails = append(cveDetails, cvemodels.CveDetail{
CveID: res.Key,
})
} else {
cveDetails = append(cveDetails, res.CveDetail)
}
case err := <-errChan:
errs = append(errs, err)
case <-timeout:
@@ -147,40 +154,21 @@ func (api goCveDictClient) httpGet(key, url string, resChan chan<- response, err
}
}
func (api goCveDictClient) detectCveByCpeURI(cpeURI string, useJVN bool) (cves []cvemodels.CveDetail, err error) {
func (api goCveDictClient) fetchCveDetailsByCpeName(cpeName string) ([]cvemodels.CveDetail, error) {
if api.cnf.IsFetchViaHTTP() {
url, err := util.URLPathJoin(api.cnf.GetURL(), "cpes")
if err != nil {
return nil, err
}
query := map[string]string{"name": cpeURI}
query := map[string]string{"name": cpeName}
logging.Log.Debugf("HTTP Request to %s, query: %#v", url, query)
if cves, err = api.httpPost(url, query); err != nil {
return nil, err
}
} else {
if cves, err = api.driver.GetByCpeURI(cpeURI); err != nil {
return nil, err
}
return api.httpPost(cpeName, url, query)
}
if useJVN {
return cves, nil
}
nvdCves := []cvemodels.CveDetail{}
for _, cve := range cves {
if !cve.HasNvd() {
continue
}
cve.Jvns = []cvemodels.Jvn{}
nvdCves = append(nvdCves, cve)
}
return nvdCves, nil
return api.driver.GetByCpeURI(cpeName)
}
func (api goCveDictClient) httpPost(url string, query map[string]string) ([]cvemodels.CveDetail, error) {
func (api goCveDictClient) httpPost(key, url string, query map[string]string) ([]cvemodels.CveDetail, error) {
var body string
var errs []error
var resp *http.Response

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package detector
@@ -18,16 +17,10 @@ import (
"github.com/future-architect/vuls/oval"
"github.com/future-architect/vuls/reporter"
"github.com/future-architect/vuls/util"
cvemodels "github.com/vulsio/go-cve-dictionary/models"
cvemodels "github.com/kotakanbe/go-cve-dictionary/models"
"golang.org/x/xerrors"
)
// Cpe :
type Cpe struct {
CpeURI string
UseJVN bool
}
// Detect vulns and fill CVE detailed information
func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
@@ -43,16 +36,7 @@ func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
r.ScannedCves = models.VulnInfos{}
}
if err := DetectLibsCves(&r, config.Conf.TrivyCacheDBDir, config.Conf.NoProgress); err != nil {
return nil, xerrors.Errorf("Failed to fill with Library dependency: %w", err)
}
if err := DetectPkgCves(&r, config.Conf.OvalDict, config.Conf.Gost); err != nil {
return nil, xerrors.Errorf("Failed to detect Pkg CVE: %w", err)
}
cpeURIs, owaspDCXMLPath := []string{}, ""
cpes := []Cpe{}
if len(r.Container.ContainerID) == 0 {
cpeURIs = config.Conf.Servers[r.ServerName].CpeNames
owaspDCXMLPath = config.Conf.Servers[r.ServerName].OwaspDCXMLPath
@@ -72,13 +56,16 @@ func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
}
cpeURIs = append(cpeURIs, cpes...)
}
for _, uri := range cpeURIs {
cpes = append(cpes, Cpe{
CpeURI: uri,
UseJVN: true,
})
if err := DetectLibsCves(&r, config.Conf.TrivyCacheDBDir, config.Conf.NoProgress); err != nil {
return nil, xerrors.Errorf("Failed to fill with Library dependency: %w", err)
}
if err := DetectCpeURIsCves(&r, cpes, config.Conf.CveDict, config.Conf.LogOpts); err != nil {
if err := DetectPkgCves(&r, config.Conf.OvalDict, config.Conf.Gost); err != nil {
return nil, xerrors.Errorf("Failed to detect Pkg CVE: %w", err)
}
if err := DetectCpeURIsCves(&r, cpeURIs, config.Conf.CveDict, config.Conf.LogOpts); err != nil {
return nil, xerrors.Errorf("Failed to detect CVE of `%s`: %w", cpeURIs, err)
}
@@ -147,7 +134,6 @@ 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)
// IgnoreCves
ignoreCves := []string{}
@@ -183,11 +169,6 @@ func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
func DetectPkgCves(r *models.ScanResult, ovalCnf config.GovalDictConf, gostCnf config.GostConf) error {
// Pkg Scan
if r.Release != "" {
// OVAL, gost(Debian Security Tracker) does not support Package for Raspbian, so skip it.
if r.Family == constant.Raspbian {
r = r.RemoveRaspbianPackFromResult()
}
// OVAL
if err := detectPkgsCvesWithOval(ovalCnf, r); err != nil {
return xerrors.Errorf("Failed to detect CVE with OVAL: %w", err)
@@ -202,7 +183,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 {
logging.Log.Infof("r.Release is empty. detect as pseudo type. Skip OVAL and gost detection")
return xerrors.Errorf("Failed to fill CVEs. r.Release is empty")
}
for i, v := range r.ScannedCves {
@@ -298,8 +279,8 @@ func FillCvesWithNvdJvn(r *models.ScanResult, cnf config.GoCveDictConf, logOpts
}
for _, d := range ds {
nvds, exploits, mitigations := models.ConvertNvdToModel(d.CveID, d.Nvds)
jvns := models.ConvertJvnToModel(d.CveID, d.Jvns)
nvd, exploits, mitigations := models.ConvertNvdJSONToModel(d.CveID, d.NvdJSON)
jvn := models.ConvertJvnToModel(d.CveID, d.Jvn)
alerts := fillCertAlerts(&d)
for cveID, vinfo := range r.ScannedCves {
@@ -307,23 +288,9 @@ func FillCvesWithNvdJvn(r *models.ScanResult, cnf config.GoCveDictConf, logOpts
if vinfo.CveContents == nil {
vinfo.CveContents = models.CveContents{}
}
for _, con := range nvds {
if !con.Empty() {
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)
}
for _, con := range []*models.CveContent{nvd, jvn} {
if con != nil && !con.Empty() {
vinfo.CveContents[con.Type] = *con
}
}
vinfo.AlertDict = alerts
@@ -338,8 +305,8 @@ func FillCvesWithNvdJvn(r *models.ScanResult, cnf config.GoCveDictConf, logOpts
}
func fillCertAlerts(cvedetail *cvemodels.CveDetail) (dict models.AlertDict) {
for _, nvd := range cvedetail.Nvds {
for _, cert := range nvd.Certs {
if cvedetail.NvdJSON != nil {
for _, cert := range cvedetail.NvdJSON.Certs {
dict.En = append(dict.En, models.Alert{
URL: cert.Link,
Title: cert.Title,
@@ -347,9 +314,8 @@ func fillCertAlerts(cvedetail *cvemodels.CveDetail) (dict models.AlertDict) {
})
}
}
for _, jvn := range cvedetail.Jvns {
for _, cert := range jvn.Certs {
if cvedetail.Jvn != nil {
for _, cert := range cvedetail.Jvn.Certs {
dict.Ja = append(dict.Ja, models.Alert{
URL: cert.Link,
Title: cert.Title,
@@ -357,7 +323,6 @@ func fillCertAlerts(cvedetail *cvemodels.CveDetail) (dict models.AlertDict) {
})
}
}
return dict
}
@@ -377,12 +342,7 @@ func detectPkgsCvesWithOval(cnf config.GovalDictConf, r *models.ScanResult) erro
return err
}
if !ok {
if r.Family == constant.Debian {
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/vulsio/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/kotakanbe/goval-dictionary#usage`", r.Family, r.Release)
}
logging.Log.Debugf("Check if oval fresh: %s %s", r.Family, r.Release)
@@ -413,26 +373,17 @@ func detectPkgsCvesWithGost(cnf config.GostConf, r *models.ScanResult) error {
}
}()
nCVEs, err := client.DetectCVEs(r, true)
nCVEs, err := client.DetectUnfixed(r, true)
if err != nil {
if r.Family == constant.Debian {
return xerrors.Errorf("Failed to detect CVEs with gost: %w", err)
}
return xerrors.Errorf("Failed to detect unfixed CVEs with gost: %w", err)
}
if r.Family == constant.Debian {
logging.Log.Infof("%s: %d CVEs are detected with gost",
r.FormatServerName(), nCVEs)
} else {
logging.Log.Infof("%s: %d unfixed CVEs are detected with gost",
r.FormatServerName(), nCVEs)
}
logging.Log.Infof("%s: %d unfixed CVEs are detected with gost", r.FormatServerName(), nCVEs)
return nil
}
// DetectCpeURIsCves detects CVEs of given CPE-URIs
func DetectCpeURIsCves(r *models.ScanResult, cpes []Cpe, cnf config.GoCveDictConf, logOpts logging.LogOpts) error {
func DetectCpeURIsCves(r *models.ScanResult, cpeURIs []string, cnf config.GoCveDictConf, logOpts logging.LogOpts) error {
client, err := newGoCveDictClient(&cnf, logOpts)
if err != nil {
return err
@@ -444,34 +395,23 @@ func DetectCpeURIsCves(r *models.ScanResult, cpes []Cpe, cnf config.GoCveDictCon
}()
nCVEs := 0
for _, cpe := range cpes {
details, err := client.detectCveByCpeURI(cpe.CpeURI, cpe.UseJVN)
for _, name := range cpeURIs {
details, err := client.fetchCveDetailsByCpeName(name)
if err != nil {
return err
}
for _, detail := range details {
advisories := []models.DistroAdvisory{}
if !detail.HasNvd() && detail.HasJvn() {
for _, jvn := range detail.Jvns {
advisories = append(advisories, models.DistroAdvisory{
AdvisoryID: jvn.JvnID,
})
}
}
maxConfidence := getMaxConfidence(detail)
if val, ok := r.ScannedCves[detail.CveID]; ok {
val.CpeURIs = util.AppendIfMissing(val.CpeURIs, cpe.CpeURI)
val.Confidences.AppendIfMissing(maxConfidence)
val.DistroAdvisories = advisories
names := val.CpeURIs
names = util.AppendIfMissing(names, name)
val.CpeURIs = names
val.Confidences.AppendIfMissing(models.CpeNameMatch)
r.ScannedCves[detail.CveID] = val
} else {
v := models.VulnInfo{
CveID: detail.CveID,
CpeURIs: []string{cpe.CpeURI},
Confidences: models.Confidences{maxConfidence},
DistroAdvisories: advisories,
CveID: detail.CveID,
CpeURIs: []string{name},
Confidences: models.Confidences{models.CpeNameMatch},
}
r.ScannedCves[detail.CveID] = v
nCVEs++
@@ -482,39 +422,15 @@ func DetectCpeURIsCves(r *models.ScanResult, cpes []Cpe, cnf config.GoCveDictCon
return nil
}
func getMaxConfidence(detail cvemodels.CveDetail) (max models.Confidence) {
if !detail.HasNvd() && detail.HasJvn() {
return models.JvnVendorProductMatch
} else if detail.HasNvd() {
for _, nvd := range detail.Nvds {
confidence := models.Confidence{}
switch nvd.DetectionMethod {
case cvemodels.NvdExactVersionMatch:
confidence = models.NvdExactVersionMatch
case cvemodels.NvdRoughVersionMatch:
confidence = models.NvdRoughVersionMatch
case cvemodels.NvdVendorProductMatch:
confidence = models.NvdVendorProductMatch
}
if max.Score < confidence.Score {
max = confidence
}
}
}
return max
}
// FillCweDict fills CWE
func FillCweDict(r *models.ScanResult) {
uniqCweIDMap := map[string]bool{}
for _, vinfo := range r.ScannedCves {
for _, conts := range vinfo.CveContents {
for _, cont := range conts {
for _, id := range cont.CweIDs {
if strings.HasPrefix(id, "CWE-") {
id = strings.TrimPrefix(id, "CWE-")
uniqCweIDMap[id] = true
}
for _, cont := range vinfo.CveContents {
for _, id := range cont.CweIDs {
if strings.HasPrefix(id, "CWE-") {
id = strings.TrimPrefix(id, "CWE-")
uniqCweIDMap[id] = true
}
}
}

View File

@@ -1,90 +0,0 @@
//go:build !scanner
// +build !scanner
package detector
import (
"reflect"
"testing"
"github.com/future-architect/vuls/models"
cvemodels "github.com/vulsio/go-cve-dictionary/models"
)
func Test_getMaxConfidence(t *testing.T) {
type args struct {
detail cvemodels.CveDetail
}
tests := []struct {
name string
args args
wantMax models.Confidence
}{
{
name: "JvnVendorProductMatch",
args: args{
detail: cvemodels.CveDetail{
Nvds: []cvemodels.Nvd{},
Jvns: []cvemodels.Jvn{{}},
},
},
wantMax: models.JvnVendorProductMatch,
},
{
name: "NvdExactVersionMatch",
args: args{
detail: cvemodels.CveDetail{
Nvds: []cvemodels.Nvd{
{DetectionMethod: cvemodels.NvdRoughVersionMatch},
{DetectionMethod: cvemodels.NvdVendorProductMatch},
{DetectionMethod: cvemodels.NvdExactVersionMatch},
},
Jvns: []cvemodels.Jvn{{DetectionMethod: cvemodels.JvnVendorProductMatch}},
},
},
wantMax: models.NvdExactVersionMatch,
},
{
name: "NvdRoughVersionMatch",
args: args{
detail: cvemodels.CveDetail{
Nvds: []cvemodels.Nvd{
{DetectionMethod: cvemodels.NvdRoughVersionMatch},
{DetectionMethod: cvemodels.NvdVendorProductMatch},
},
Jvns: []cvemodels.Jvn{},
},
},
wantMax: models.NvdRoughVersionMatch,
},
{
name: "NvdVendorProductMatch",
args: args{
detail: cvemodels.CveDetail{
Nvds: []cvemodels.Nvd{
{DetectionMethod: cvemodels.NvdVendorProductMatch},
},
Jvns: []cvemodels.Jvn{{DetectionMethod: cvemodels.JvnVendorProductMatch}},
},
},
wantMax: models.NvdVendorProductMatch,
},
{
name: "empty",
args: args{
detail: cvemodels.CveDetail{
Nvds: []cvemodels.Nvd{},
Jvns: []cvemodels.Jvn{},
},
},
wantMax: models.Confidence{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if gotMax := getMaxConfidence(tt.args.detail); !reflect.DeepEqual(gotMax, tt.wantMax) {
t.Errorf("getMaxConfidence() = %v, want %v", gotMax, tt.wantMax)
}
})
}
}

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package detector
@@ -33,7 +32,7 @@ func FillWithExploit(r *models.ScanResult, cnf config.ExploitConf) (nExploitCve
return 0, err
}
for _, res := range responses {
exps := []exploitmodels.Exploit{}
exps := []*exploitmodels.Exploit{}
if err := json.Unmarshal([]byte(res.json), &exps); err != nil {
return 0, err
}
@@ -77,7 +76,7 @@ func FillWithExploit(r *models.ScanResult, cnf config.ExploitConf) (nExploitCve
}
// ConvertToModels converts gost model to vuls model
func ConvertToModels(es []exploitmodels.Exploit) (exploits []models.Exploit) {
func ConvertToModels(es []*exploitmodels.Exploit) (exploits []models.Exploit) {
for _, e := range es {
var documentURL, shellURL *string
if e.OffensiveSecurity != nil {

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package detector
@@ -126,7 +125,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] = []models.CveContent{cveContent}
val.CveContents[models.GitHub] = cveContent
r.ScannedCves[cveID] = val
} else {
v := models.VulnInfo{

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package detector

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package detector
@@ -7,8 +6,8 @@ import (
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
metasploitdb "github.com/vulsio/go-msfdb/db"
metasploitmodels "github.com/vulsio/go-msfdb/models"
metasploitdb "github.com/takuzoo3868/go-msfdb/db"
metasploitmodels "github.com/takuzoo3868/go-msfdb/models"
"golang.org/x/xerrors"
)
@@ -45,7 +44,7 @@ func FillWithMetasploit(r *models.ScanResult, cnf config.MetasploitConf) (nMetas
}
// ConvertToModelsMsf converts gost model to vuls model
func ConvertToModelsMsf(ms []metasploitmodels.Metasploit) (modules []models.Metasploit) {
func ConvertToModelsMsf(ms []*metasploitmodels.Metasploit) (modules []models.Metasploit) {
for _, m := range ms {
var links []string
if 0 < len(m.References) {
@@ -72,7 +71,7 @@ func newMetasploitDB(cnf config.VulnDictInterface) (driver metasploitdb.DB, lock
if cnf.GetType() == "sqlite3" {
path = cnf.GetSQLite3Path()
}
if driver, locked, err = metasploitdb.NewDB(cnf.GetType(), path, cnf.GetDebugSQL()); err != nil {
if driver, locked, err = metasploitdb.NewDB(cnf.GetType(), path, cnf.GetDebugSQL(), false); err != nil {
if locked {
return nil, true, xerrors.Errorf("metasploitDB is locked. err: %w", err)
}

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package detector
@@ -9,7 +8,6 @@ import (
"io/ioutil"
"os"
"path/filepath"
"reflect"
"regexp"
"sort"
"time"
@@ -68,9 +66,10 @@ 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
@@ -144,7 +143,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/vulsio/gost
// This logic will be uncomented after integration with gost https://github.com/knqyf263/gost
// } else if isCveFixed(v, previous) {
// updated[v.CveID] = v
// logging.Log.Debugf("fixed: %s", v.CveID)
@@ -197,34 +196,30 @@ func isCveInfoUpdated(cveID string, previous, current models.ScanResult) bool {
models.NewCveContentType(current.Family),
}
prevLastModified := map[models.CveContentType][]time.Time{}
prevLastModified := map[models.CveContentType]time.Time{}
preVinfo, ok := previous.ScannedCves[cveID]
if !ok {
return true
}
for _, cType := range cTypes {
if conts, ok := preVinfo.CveContents[cType]; ok {
for _, cont := range conts {
prevLastModified[cType] = append(prevLastModified[cType], cont.LastModified)
}
if content, ok := preVinfo.CveContents[cType]; ok {
prevLastModified[cType] = content.LastModified
}
}
curLastModified := map[models.CveContentType][]time.Time{}
curLastModified := map[models.CveContentType]time.Time{}
curVinfo, ok := current.ScannedCves[cveID]
if !ok {
return true
}
for _, cType := range cTypes {
if conts, ok := curVinfo.CveContents[cType]; ok {
for _, cont := range conts {
curLastModified[cType] = append(curLastModified[cType], cont.LastModified)
}
if content, ok := curVinfo.CveContents[cType]; ok {
curLastModified[cType] = content.LastModified
}
}
for _, t := range cTypes {
if !reflect.DeepEqual(curLastModified[t], prevLastModified[t]) {
if !curLastModified[t].Equal(prevLastModified[t]) {
logging.Log.Debugf("%s LastModified not equal: \n%s\n%s",
cveID, curLastModified[t], prevLastModified[t])
return true

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package detector

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package detector

141
go.mod
View File

@@ -1,29 +1,22 @@
module github.com/future-architect/vuls
go 1.17
go 1.16
require (
github.com/Azure/azure-sdk-for-go v50.2.0+incompatible
github.com/BurntSushi/toml v0.4.1
github.com/BurntSushi/toml v0.3.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-20210815095355-42429a80d0e3
github.com/aquasecurity/trivy v0.19.3-0.20210909113250-19c0b70d2613
github.com/aquasecurity/trivy-db v0.0.0-20210809142931-da8e09204404
github.com/aquasecurity/fanal v0.0.0-20210520034323-54c5a82e861f
github.com/aquasecurity/trivy v0.18.3
github.com/aquasecurity/trivy-db v0.0.0-20210429114658-ae22941a55d0
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
github.com/aws/aws-sdk-go v1.40.22
github.com/aws/aws-sdk-go v1.36.31
github.com/boltdb/bolt v1.3.1
github.com/briandowns/spinner v1.16.0 // indirect
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cheggaaa/pb/v3 v3.0.8 // indirect
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/fsnotify/fsnotify v1.5.1 // indirect
github.com/go-redis/redis/v8 v8.11.3 // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/google/subcommands v1.2.0
github.com/gosuri/uitable v0.0.4
github.com/hashicorp/go-uuid v1.0.2
@@ -35,119 +28,35 @@ require (
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.1.10
github.com/kotakanbe/go-cve-dictionary v0.5.12
github.com/kotakanbe/go-pingscanner v0.1.0
github.com/kotakanbe/goval-dictionary v0.3.6-0.20210429000733-6db1754b1d87
github.com/kotakanbe/logrus-prefixed-formatter v0.0.0-20180123152602-928f7356cb96
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/lib/pq v1.10.1 // indirect
github.com/magiconair/properties v1.8.4 // indirect
github.com/mattn/go-runewidth v0.0.12 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mitchellh/go-homedir v1.1.0
github.com/nlopes/slack v0.6.0
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/pelletier/go-toml v1.8.1 // indirect
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5
github.com/sirupsen/logrus v1.8.1
github.com/sirupsen/logrus v1.8.0
github.com/spf13/afero v1.6.0
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/cobra v1.2.1
github.com/vulsio/go-cve-dictionary v0.8.1
github.com/vulsio/go-exploitdb v0.4.0
github.com/vulsio/go-msfdb v0.2.0
github.com/vulsio/gost v0.4.1-0.20210919121048-2a7957bf1885
github.com/vulsio/goval-dictionary v0.6.1
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-20210514164344-f6687ab2804c
github.com/spf13/cobra v1.1.3
github.com/takuzoo3868/go-msfdb v0.1.5
github.com/vulsio/go-exploitdb v0.1.7
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 // indirect
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 // indirect
golang.org/x/oauth2 v0.0.0-20210125201302-af13f521f196
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/text v0.3.7 // indirect
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 // indirect
golang.org/x/tools v0.1.0 // 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/driver/postgres v1.1.1 // indirect
gorm.io/driver/sqlite v1.1.5 // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
k8s.io/utils v0.0.0-20210111153108-fddb29f9d009
)
require (
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/PuerkitoBio/goquery v1.7.1 // indirect
github.com/andybalholm/cascadia v1.2.0 // indirect
github.com/aquasecurity/go-dep-parser v0.0.0-20210815080135-5be65146849a // 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/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // 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-github/v33 v33.0.0 // indirect
github.com/google/go-querystring v1.0.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.6.8 // 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.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
github.com/jackc/pgconn v1.10.0 // indirect
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
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/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-sqlite3 v2.0.3+incompatible // indirect
github.com/mitchellh/copystructure v1.1.1 // indirect
github.com/mitchellh/mapstructure v1.4.2 // indirect
github.com/mitchellh/reflectwalk v1.0.1 // 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/stretchr/objx v0.3.0 // indirect
github.com/stretchr/testify v1.7.0 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
github.com/ymomoi/goval-parser v0.0.0-20170813122243-0a0be1dd9d08 // 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
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
gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
gorm.io/gorm v1.21.15 // indirect
moul.io/http2curl v1.0.0 // indirect
)

784
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package gost
@@ -6,12 +5,11 @@ package gost
import (
"encoding/json"
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
debver "github.com/knqyf263/go-deb-version"
gostmodels "github.com/vulsio/gost/models"
"golang.org/x/xerrors"
gostmodels "github.com/knqyf263/gost/models"
)
// Debian is Gost client for Debian GNU/Linux
@@ -23,7 +21,6 @@ type packCves struct {
packName string
isSrcPack bool
cves []models.CveContent
fixes models.PackageFixStatuses
}
func (deb Debian) supported(major string) bool {
@@ -31,23 +28,23 @@ func (deb Debian) supported(major string) bool {
"8": "jessie",
"9": "stretch",
"10": "buster",
"11": "bullseye",
}[major]
return ok
}
// DetectCVEs fills cve information that has in Gost
func (deb Debian) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err error) {
// DetectUnfixed fills cve information that has in Gost
func (deb Debian) DetectUnfixed(r *models.ScanResult, _ bool) (nCVEs int, err error) {
if !deb.supported(major(r.Release)) {
// only logging
logging.Log.Warnf("Debian %s is not supported yet", r.Release)
return 0, nil
}
// Add linux and set the version of running kernel to search Gost.
linuxImage := "linux-image-" + r.RunningKernel.Release
// Add linux and set the version of running kernel to search OVAL.
if r.Container.ContainerID == "" {
newVer := ""
if p, ok := r.Packages["linux-image-"+r.RunningKernel.Release]; ok {
if p, ok := r.Packages[linuxImage]; ok {
newVer = p.NewVersion
}
r.Packages["linux"] = models.Package{
@@ -57,35 +54,18 @@ func (deb Debian) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err error
}
}
stashLinuxPackage := r.Packages["linux"]
nFixedCVEs, err := deb.detectCVEsWithFixState(r, "resolved")
if err != nil {
return 0, err
}
r.Packages["linux"] = stashLinuxPackage
nUnfixedCVEs, err := deb.detectCVEsWithFixState(r, "open")
if err != nil {
return 0, err
}
return (nFixedCVEs + nUnfixedCVEs), nil
}
func (deb Debian) detectCVEsWithFixState(r *models.ScanResult, fixStatus string) (nCVEs int, err error) {
if fixStatus != "resolved" && fixStatus != "open" {
return 0, xerrors.Errorf(`Failed to detectCVEsWithFixState. fixStatus is not allowed except "open" and "resolved"(actual: fixStatus -> %s).`, fixStatus)
// Debian Security Tracker does not support Package for Raspbian, so skip it.
var scanResult models.ScanResult
if r.Family != constant.Raspbian {
scanResult = *r
} else {
scanResult = r.RemoveRaspbianPackFromResult()
}
packCvesList := []packCves{}
if deb.DBDriver.Cnf.IsFetchViaHTTP() {
url, _ := util.URLPathJoin(deb.DBDriver.Cnf.GetURL(), "debian", major(r.Release), "pkgs")
s := "unfixed-cves"
if s == "resolved" {
s = "fixed-cves"
}
responses, err := getCvesWithFixStateViaHTTP(r, url, s)
url, _ := util.URLPathJoin(deb.DBDriver.Cnf.GetURL(), "debian", major(scanResult.Release), "pkgs")
responses, err := getAllUnfixedCvesViaHTTP(r, url)
if err != nil {
return 0, err
}
@@ -96,40 +76,43 @@ func (deb Debian) detectCVEsWithFixState(r *models.ScanResult, fixStatus string)
return 0, err
}
cves := []models.CveContent{}
fixes := []models.PackageFixStatus{}
for _, debcve := range debCves {
cves = append(cves, *deb.ConvertToModel(&debcve))
fixes = append(fixes, checkPackageFixStatus(&debcve)...)
}
packCvesList = append(packCvesList, packCves{
packName: res.request.packName,
isSrcPack: res.request.isSrcPack,
cves: cves,
fixes: fixes,
})
}
} else {
if deb.DBDriver.DB == nil {
return 0, nil
}
for _, pack := range r.Packages {
cves, fixes := deb.getCvesDebianWithfixStatus(fixStatus, major(r.Release), pack.Name)
for _, pack := range scanResult.Packages {
cveDebs := deb.DBDriver.DB.GetUnfixedCvesDebian(major(scanResult.Release), pack.Name)
cves := []models.CveContent{}
for _, cveDeb := range cveDebs {
cves = append(cves, *deb.ConvertToModel(&cveDeb))
}
packCvesList = append(packCvesList, packCves{
packName: pack.Name,
isSrcPack: false,
cves: cves,
fixes: fixes,
})
}
// SrcPack
for _, pack := range r.SrcPackages {
cves, fixes := deb.getCvesDebianWithfixStatus(fixStatus, major(r.Release), pack.Name)
for _, pack := range scanResult.SrcPackages {
cveDebs := deb.DBDriver.DB.GetUnfixedCvesDebian(major(scanResult.Release), pack.Name)
cves := []models.CveContent{}
for _, cveDeb := range cveDebs {
cves = append(cves, *deb.ConvertToModel(&cveDeb))
}
packCvesList = append(packCvesList, packCves{
packName: pack.Name,
isSrcPack: true,
cves: cves,
fixes: fixes,
})
}
}
@@ -137,14 +120,13 @@ func (deb Debian) detectCVEsWithFixState(r *models.ScanResult, fixStatus string)
delete(r.Packages, "linux")
for _, p := range packCvesList {
for i, cve := range p.cves {
for _, cve := range p.cves {
v, ok := r.ScannedCves[cve.CveID]
if ok {
if v.CveContents == nil {
v.CveContents = models.NewCveContents(cve)
} else {
v.CveContents[models.DebianSecurityTracker] = []models.CveContent{cve}
v.Confidences = models.Confidences{models.DebianSecurityTrackerMatch}
v.CveContents[models.DebianSecurityTracker] = cve
}
} else {
v = models.VulnInfo{
@@ -152,31 +134,6 @@ func (deb Debian) detectCVEsWithFixState(r *models.ScanResult, fixStatus string)
CveContents: models.NewCveContents(cve),
Confidences: models.Confidences{models.DebianSecurityTrackerMatch},
}
if fixStatus == "resolved" {
versionRelease := ""
if p.isSrcPack {
versionRelease = r.SrcPackages[p.packName].Version
} else {
versionRelease = r.Packages[p.packName].FormatVer()
}
if versionRelease == "" {
break
}
affected, err := isGostDefAffected(versionRelease, p.fixes[i].FixedIn)
if err != nil {
logging.Log.Debugf("Failed to parse versions: %s, Ver: %s, Gost: %s",
err, versionRelease, p.fixes[i].FixedIn)
continue
}
if !affected {
continue
}
}
nCVEs++
}
@@ -191,65 +148,25 @@ func (deb Debian) detectCVEsWithFixState(r *models.ScanResult, fixStatus string)
}
} else {
if p.packName == "linux" {
names = append(names, "linux-image-"+r.RunningKernel.Release)
names = append(names, linuxImage)
} else {
names = append(names, p.packName)
}
}
if fixStatus == "resolved" {
for _, name := range names {
v.AffectedPackages = v.AffectedPackages.Store(models.PackageFixStatus{
Name: name,
FixedIn: p.fixes[i].FixedIn,
})
}
} else {
for _, name := range names {
v.AffectedPackages = v.AffectedPackages.Store(models.PackageFixStatus{
Name: name,
FixState: "open",
NotFixedYet: true,
})
}
for _, name := range names {
v.AffectedPackages = v.AffectedPackages.Store(models.PackageFixStatus{
Name: name,
FixState: "open",
NotFixedYet: true,
})
}
r.ScannedCves[cve.CveID] = v
}
}
return nCVEs, nil
}
func isGostDefAffected(versionRelease, gostVersion string) (affected bool, err error) {
vera, err := debver.NewVersion(versionRelease)
if err != nil {
return false, err
}
verb, err := debver.NewVersion(gostVersion)
if err != nil {
return false, err
}
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
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)...)
}
return
}
// ConvertToModel converts gost model to vuls model
func (deb Debian) ConvertToModel(cve *gostmodels.DebianCVE) *models.CveContent {
severity := ""
@@ -271,22 +188,3 @@ func (deb Debian) ConvertToModel(cve *gostmodels.DebianCVE) *models.CveContent {
},
}
}
func checkPackageFixStatus(cve *gostmodels.DebianCVE) []models.PackageFixStatus {
fixes := []models.PackageFixStatus{}
for _, p := range cve.Package {
for _, r := range p.Release {
f := models.PackageFixStatus{Name: p.PackageName}
if r.Status == "open" {
f.NotFixedYet = true
} else {
f.FixedIn = r.FixedVersion
}
fixes = append(fixes, f)
}
}
return fixes
}

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package gost
@@ -39,17 +38,10 @@ func TestDebian_Supported(t *testing.T) {
want: true,
},
{
name: "11 is supported",
name: "11 is not supported yet",
args: args{
major: "11",
},
want: true,
},
{
name: "12 is not supported yet",
args: args{
major: "12",
},
want: false,
},
{

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package gost
@@ -7,7 +6,7 @@ import (
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/vulsio/gost/db"
"github.com/knqyf263/gost/db"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/constant"
@@ -21,7 +20,7 @@ type DBDriver struct {
// Client is the interface of OVAL client.
type Client interface {
DetectCVEs(*models.ScanResult, bool) (int, error)
DetectUnfixed(*models.ScanResult, bool) (int, error)
CloseDB() error
}
@@ -66,16 +65,14 @@ func NewClient(cnf config.GostConf, family string) (Client, error) {
driver := DBDriver{DB: db, Cnf: &cnf}
switch family {
case constant.RedHat, constant.CentOS, constant.Rocky, constant.Alma:
case constant.RedHat, constant.CentOS:
return RedHat{Base{DBDriver: driver}}, nil
case constant.Debian, constant.Raspbian:
return Debian{Base{DBDriver: driver}}, nil
case constant.Ubuntu:
return Ubuntu{Base{DBDriver: driver}}, nil
case constant.Windows:
return Microsoft{Base{DBDriver: driver}}, nil
default:
return Pseudo{Base{DBDriver: driver}}, nil
return Pseudo{}, nil
}
}

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package gost
@@ -8,7 +7,7 @@ import (
"testing"
"github.com/future-architect/vuls/models"
gostmodels "github.com/vulsio/gost/models"
gostmodels "github.com/knqyf263/gost/models"
)
func TestSetPackageStates(t *testing.T) {

View File

@@ -1,14 +1,12 @@
//go:build !scanner
// +build !scanner
package gost
import (
"sort"
"strings"
"github.com/future-architect/vuls/models"
gostmodels "github.com/vulsio/gost/models"
gostmodels "github.com/knqyf263/gost/models"
)
// Microsoft is Gost client for windows
@@ -16,8 +14,8 @@ type Microsoft struct {
Base
}
// DetectCVEs fills cve information that has in Gost
func (ms Microsoft) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err error) {
// DetectUnfixed fills cve information that has in Gost
func (ms Microsoft) DetectUnfixed(r *models.ScanResult, _ bool) (nCVEs int, err error) {
if ms.DBDriver.DB == nil {
return 0, nil
}
@@ -34,7 +32,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] = []models.CveContent{*cveCont}
v.CveContents[models.Microsoft] = *cveCont
v.Mitigations = append(v.Mitigations, mitigations...)
r.ScannedCves[cveID] = v
}
@@ -43,9 +41,6 @@ func (ms Microsoft) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err err
// ConvertToModel converts gost model to vuls model
func (ms Microsoft) ConvertToModel(cve *gostmodels.MicrosoftCVE) (*models.CveContent, []models.Mitigation) {
sort.Slice(cve.ScoreSets, func(i, j int) bool {
return cve.ScoreSets[i].Vector < cve.ScoreSets[j].Vector
})
v3score := 0.0
var v3Vector string
for _, scoreSet := range cve.ScoreSets {

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package gost
@@ -12,7 +11,7 @@ type Pseudo struct {
Base
}
// DetectCVEs fills cve information that has in Gost
func (pse Pseudo) DetectCVEs(_ *models.ScanResult, _ bool) (int, error) {
// DetectUnfixed fills cve information that has in Gost
func (pse Pseudo) DetectUnfixed(r *models.ScanResult, _ bool) (int, error) {
return 0, nil
}

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package gost
@@ -11,7 +10,7 @@ import (
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
gostmodels "github.com/vulsio/gost/models"
gostmodels "github.com/knqyf263/gost/models"
)
// RedHat is Gost client for RedHat family linux
@@ -19,8 +18,8 @@ type RedHat struct {
Base
}
// DetectCVEs fills cve information that has in Gost
func (red RedHat) DetectCVEs(r *models.ScanResult, ignoreWillNotFix bool) (nCVEs int, err error) {
// DetectUnfixed fills cve information that has in Gost
func (red RedHat) DetectUnfixed(r *models.ScanResult, ignoreWillNotFix bool) (nCVEs int, err error) {
if red.DBDriver.Cnf.IsFetchViaHTTP() {
prefix, _ := util.URLPathJoin(red.DBDriver.Cnf.GetURL(), "redhat", major(r.Release), "pkgs")
responses, err := getAllUnfixedCvesViaHTTP(r, prefix)
@@ -103,7 +102,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] = []models.CveContent{*cveCont}
v.CveContents[models.RedHatAPI] = *cveCont
}
} else {
v = models.VulnInfo{
@@ -123,7 +122,7 @@ func (red RedHat) setUnfixedCveToScanResult(cve *gostmodels.RedhatCVE, r *models
if v.CveContents == nil {
v.CveContents = models.NewCveContents(*cveCont)
} else {
v.CveContents[models.RedHatAPI] = []models.CveContent{*cveCont}
v.CveContents[models.RedHatAPI] = *cveCont
}
} else {
v = models.VulnInfo{

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package gost

View File

@@ -1,191 +0,0 @@
//go:build !scanner
// +build !scanner
package gost
import (
"encoding/json"
"strings"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
gostmodels "github.com/vulsio/gost/models"
)
// Ubuntu is Gost client for Ubuntu
type Ubuntu struct {
Base
}
func (ubu Ubuntu) supported(version string) bool {
_, ok := map[string]string{
"1404": "trusty",
"1604": "xenial",
"1804": "bionic",
"2004": "focal",
"2010": "groovy",
"2104": "hirsute",
}[version]
return ok
}
// DetectCVEs fills cve information that has in Gost
func (ubu Ubuntu) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err error) {
ubuReleaseVer := strings.Replace(r.Release, ".", "", 1)
if !ubu.supported(ubuReleaseVer) {
logging.Log.Warnf("Ubuntu %s is not supported yet", r.Release)
return 0, nil
}
linuxImage := "linux-image-" + r.RunningKernel.Release
// Add linux and set the version of running kernel to search Gost.
if r.Container.ContainerID == "" {
newVer := ""
if p, ok := r.Packages[linuxImage]; ok {
newVer = p.NewVersion
}
r.Packages["linux"] = models.Package{
Name: "linux",
Version: r.RunningKernel.Version,
NewVersion: newVer,
}
}
packCvesList := []packCves{}
if ubu.DBDriver.Cnf.IsFetchViaHTTP() {
url, _ := util.URLPathJoin(ubu.DBDriver.Cnf.GetURL(), "ubuntu", ubuReleaseVer, "pkgs")
responses, err := getAllUnfixedCvesViaHTTP(r, url)
if err != nil {
return 0, err
}
for _, res := range responses {
ubuCves := map[string]gostmodels.UbuntuCVE{}
if err := json.Unmarshal([]byte(res.json), &ubuCves); err != nil {
return 0, err
}
cves := []models.CveContent{}
for _, ubucve := range ubuCves {
cves = append(cves, *ubu.ConvertToModel(&ubucve))
}
packCvesList = append(packCvesList, packCves{
packName: res.request.packName,
isSrcPack: res.request.isSrcPack,
cves: cves,
})
}
} else {
if ubu.DBDriver.DB == nil {
return 0, nil
}
for _, pack := range r.Packages {
ubuCves := ubu.DBDriver.DB.GetUnfixedCvesUbuntu(ubuReleaseVer, pack.Name)
cves := []models.CveContent{}
for _, ubucve := range ubuCves {
cves = append(cves, *ubu.ConvertToModel(&ubucve))
}
packCvesList = append(packCvesList, packCves{
packName: pack.Name,
isSrcPack: false,
cves: cves,
})
}
// SrcPack
for _, pack := range r.SrcPackages {
ubuCves := ubu.DBDriver.DB.GetUnfixedCvesUbuntu(ubuReleaseVer, pack.Name)
cves := []models.CveContent{}
for _, ubucve := range ubuCves {
cves = append(cves, *ubu.ConvertToModel(&ubucve))
}
packCvesList = append(packCvesList, packCves{
packName: pack.Name,
isSrcPack: true,
cves: cves,
})
}
}
delete(r.Packages, "linux")
for _, p := range packCvesList {
for _, cve := range p.cves {
v, ok := r.ScannedCves[cve.CveID]
if ok {
if v.CveContents == nil {
v.CveContents = models.NewCveContents(cve)
} else {
v.CveContents[models.UbuntuAPI] = []models.CveContent{cve}
}
} else {
v = models.VulnInfo{
CveID: cve.CveID,
CveContents: models.NewCveContents(cve),
Confidences: models.Confidences{models.UbuntuAPIMatch},
}
nCVEs++
}
names := []string{}
if p.isSrcPack {
if srcPack, ok := r.SrcPackages[p.packName]; ok {
for _, binName := range srcPack.BinaryNames {
if _, ok := r.Packages[binName]; ok {
names = append(names, binName)
}
}
}
} else {
if p.packName == "linux" {
names = append(names, linuxImage)
} else {
names = append(names, p.packName)
}
}
for _, name := range names {
v.AffectedPackages = v.AffectedPackages.Store(models.PackageFixStatus{
Name: name,
FixState: "open",
NotFixedYet: true,
})
}
r.ScannedCves[cve.CveID] = v
}
}
return nCVEs, nil
}
// ConvertToModel converts gost model to vuls model
func (ubu Ubuntu) ConvertToModel(cve *gostmodels.UbuntuCVE) *models.CveContent {
references := []models.Reference{}
for _, r := range cve.References {
if strings.Contains(r.Reference, "https://cve.mitre.org/cgi-bin/cvename.cgi?name=") {
references = append(references, models.Reference{Source: "CVE", Link: r.Reference})
} else {
references = append(references, models.Reference{Link: r.Reference})
}
}
for _, b := range cve.Bugs {
references = append(references, models.Reference{Source: "Bug", Link: b.Bug})
}
for _, u := range cve.Upstreams {
for _, upstreamLink := range u.UpstreamLinks {
references = append(references, models.Reference{Source: "UPSTREAM", Link: upstreamLink.Link})
}
}
return &models.CveContent{
Type: models.UbuntuAPI,
CveID: cve.Candidate,
Summary: cve.Description,
Cvss2Severity: cve.Priority,
Cvss3Severity: cve.Priority,
SourceLink: "https://ubuntu.com/security/" + cve.Candidate,
References: references,
Published: cve.PublicDate,
}
}

View File

@@ -1,137 +0,0 @@
package gost
import (
"reflect"
"testing"
"time"
"github.com/future-architect/vuls/models"
gostmodels "github.com/vulsio/gost/models"
)
func TestUbuntu_Supported(t *testing.T) {
type args struct {
ubuReleaseVer string
}
tests := []struct {
name string
args args
want bool
}{
{
name: "14.04 is supported",
args: args{
ubuReleaseVer: "1404",
},
want: true,
},
{
name: "16.04 is supported",
args: args{
ubuReleaseVer: "1604",
},
want: true,
},
{
name: "18.04 is supported",
args: args{
ubuReleaseVer: "1804",
},
want: true,
},
{
name: "20.04 is supported",
args: args{
ubuReleaseVer: "2004",
},
want: true,
},
{
name: "20.10 is supported",
args: args{
ubuReleaseVer: "2010",
},
want: true,
},
{
name: "21.04 is supported",
args: args{
ubuReleaseVer: "2104",
},
want: true,
},
{
name: "empty string is not supported yet",
args: args{
ubuReleaseVer: "",
},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ubu := Ubuntu{}
if got := ubu.supported(tt.args.ubuReleaseVer); got != tt.want {
t.Errorf("Ubuntu.Supported() = %v, want %v", got, tt.want)
}
})
}
}
func TestUbuntuConvertToModel(t *testing.T) {
tests := []struct {
name string
input gostmodels.UbuntuCVE
expected models.CveContent
}{
{
name: "gost Ubuntu.ConvertToModel",
input: gostmodels.UbuntuCVE{
Candidate: "CVE-2021-3517",
PublicDate: time.Date(2021, 5, 19, 14, 15, 0, 0, time.UTC),
References: []gostmodels.UbuntuReference{
{Reference: "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3517"},
{Reference: "https://gitlab.gnome.org/GNOME/libxml2/-/issues/235"},
{Reference: "https://gitlab.gnome.org/GNOME/libxml2/-/commit/bf22713507fe1fc3a2c4b525cf0a88c2dc87a3a2"}},
Description: "description.",
Notes: []gostmodels.UbuntuNote{},
Bugs: []gostmodels.UbuntuBug{{Bug: "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=987738"}},
Priority: "medium",
Patches: []gostmodels.UbuntuPatch{
{PackageName: "libxml2", ReleasePatches: []gostmodels.UbuntuReleasePatch{
{ReleaseName: "focal", Status: "needed", Note: ""},
}},
},
Upstreams: []gostmodels.UbuntuUpstream{{
PackageName: "libxml2", UpstreamLinks: []gostmodels.UbuntuUpstreamLink{
{Link: "https://gitlab.gnome.org/GNOME/libxml2/-/commit/50f06b3efb638efb0abd95dc62dca05ae67882c2"},
},
}},
},
expected: models.CveContent{
Type: models.UbuntuAPI,
CveID: "CVE-2021-3517",
Summary: "description.",
Cvss2Severity: "medium",
Cvss3Severity: "medium",
SourceLink: "https://ubuntu.com/security/CVE-2021-3517",
References: []models.Reference{
{Source: "CVE", Link: "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3517"},
{Link: "https://gitlab.gnome.org/GNOME/libxml2/-/issues/235"},
{Link: "https://gitlab.gnome.org/GNOME/libxml2/-/commit/bf22713507fe1fc3a2c4b525cf0a88c2dc87a3a2"},
{Source: "Bug", Link: "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=987738"},
{Source: "UPSTREAM", Link: "https://gitlab.gnome.org/GNOME/libxml2/-/commit/50f06b3efb638efb0abd95dc62dca05ae67882c2"}},
Published: time.Date(2021, 5, 19, 14, 15, 0, 0, time.UTC),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ubu := Ubuntu{}
got := ubu.ConvertToModel(&tt.input)
if !reflect.DeepEqual(got, &tt.expected) {
t.Errorf("Ubuntu.ConvertToModel() = %#v, want %#v", got, &tt.expected)
}
})
}
}

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package gost
@@ -86,10 +85,7 @@ type request struct {
func getAllUnfixedCvesViaHTTP(r *models.ScanResult, urlPrefix string) (
responses []response, err error) {
return getCvesWithFixStateViaHTTP(r, urlPrefix, "unfixed-cves")
}
func getCvesWithFixStateViaHTTP(r *models.ScanResult, urlPrefix, fixState string) (responses []response, err error) {
nReq := len(r.Packages) + len(r.SrcPackages)
reqChan := make(chan request, nReq)
resChan := make(chan response, nReq)
@@ -124,7 +120,7 @@ func getCvesWithFixStateViaHTTP(r *models.ScanResult, urlPrefix, fixState string
url, err := util.URLPathJoin(
urlPrefix,
req.packName,
fixState,
"unfixed-cves",
)
if err != nil {
errChan <- err

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,50 +1,30 @@
[cveDict]
Type = "sqlite3"
SQLite3Path = "/data/vulsctl/docker/cve.sqlite3"
SQLite3Path = "/home/ubuntu/vulsctl/docker/cve.sqlite3"
[ovalDict]
Type = "sqlite3"
SQLite3Path = "/data/vulsctl/docker/oval.sqlite3"
SQLite3Path = "/home/ubuntu/vulsctl/docker/oval.sqlite3"
[gost]
Type = "sqlite3"
SQLite3Path = "/data/vulsctl/docker/gost.sqlite3"
SQLite3Path = "/home/ubuntu/vulsctl/docker/gost.sqlite3"
[exploit]
Type = "sqlite3"
SQLite3Path = "/data/vulsctl/docker/go-exploitdb.sqlite3"
SQLite3Path = "/home/ubuntu/vulsctl/docker/go-exploitdb.sqlite3"
[metasploit]
type = "sqlite3"
SQLite3Path = "/data/vulsctl/docker/go-msfdb.sqlite3"
SQLite3Path = "/home/ubuntu/vulsctl/docker/go-msfdb.sqlite3"
[default]
[servers]
[servers.nvd_exact]
[servers.rails]
type = "pseudo"
cpeNames = [ "cpe:/a:rubyonrails:rails:3.0.1" ]
[servers.nvd_rough]
type = "pseudo"
cpeNames = [ "cpe:/a:openssl:openssl:1.1.1" ]
[servers.nvd_vendor_product]
type = "pseudo"
cpeNames = [ "cpe:/a:djangoproject:django" ]
[servers.nvd_match_no_jvn]
type = "pseudo"
cpeNames = [ "cpe:/a:apache:tomcat:7.0.27" ]
[servers.jvn_vendor_product]
type = "pseudo"
cpeNames = [ "cpe:/a:hitachi_abb_power_grids:afs660:1.0.0" ]
[servers.jvn_vendor_product_nover]
type = "pseudo"
cpeNames = [ "cpe:/o:nec:aterm_wg2600hp2_firmware"]
cpeNames = [ "cpe:/a:rubyonrails:ruby_on_rails:3.0.1" ]
[servers.gemfile]
type = "pseudo"

View File

@@ -22,30 +22,9 @@ Url = "redis://127.0.0.1/3"
[servers]
[servers.nvd_exact]
[servers.rails]
type = "pseudo"
cpeNames = [ "cpe:/a:rubyonrails:rails:3.0.1" ]
#cpeNames = [ "cpe:/a:rubyonrails:rails:4.0.0" ]
[servers.nvd_rough]
type = "pseudo"
cpeNames = [ "cpe:/a:openssl:openssl:1.1.1" ]
[servers.nvd_vendor_product]
type = "pseudo"
cpeNames = [ "cpe:/a:djangoproject:django" ]
[servers.nvd_match_no_jvn]
type = "pseudo"
cpeNames = [ "cpe:/a:apache:tomcat:7.0.27" ]
[servers.jvn_vendor_product]
type = "pseudo"
cpeNames = [ "cpe:/a:hitachi_abb_power_grids:afs660:1.0.0" ]
[servers.jvn_vendor_product_nover]
type = "pseudo"
cpeNames = [ "cpe:/o:nec:aterm_wg2600hp2_firmware"]
cpeNames = [ "cpe:/a:rubyonrails:ruby_on_rails:3.0.1" ]
[servers.gemfile]
type = "pseudo"

View File

@@ -100,7 +100,7 @@ func NewCustomLogger(debug, quiet, logToFile bool, logDir, logMsgAnsiColor, serv
}
}
} else if quiet {
log.Out = ioutil.Discard
log.Out = io.Discard
} else {
log.Out = os.Stderr
}

View File

@@ -1,7 +1,6 @@
package models
import (
"sort"
"strings"
"time"
@@ -9,26 +8,13 @@ import (
)
// CveContents has CveContent
type CveContents map[CveContentType][]CveContent
type CveContents map[CveContentType]CveContent
// NewCveContents create CveContents
func NewCveContents(conts ...CveContent) CveContents {
m := CveContents{}
for _, cont := range conts {
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}
}
m[cont.Type] = cont
}
return m
}
@@ -58,18 +44,16 @@ func (v CveContents) Except(exceptCtypes ...CveContentType) (values CveContents)
}
// PrimarySrcURLs returns link of source
func (v CveContents) PrimarySrcURLs(lang, myFamily, cveID string, confidences Confidences) (values []CveContentStr) {
func (v CveContents) PrimarySrcURLs(lang, myFamily, cveID string) (values []CveContentStr) {
if cveID == "" {
return
}
if conts, found := v[Nvd]; found {
for _, cont := range conts {
for _, r := range cont.References {
for _, t := range r.Tags {
if t == "Vendor Advisory" {
values = append(values, CveContentStr{Nvd, r.Link})
}
if cont, found := v[Nvd]; found {
for _, r := range cont.References {
for _, t := range r.Tags {
if t == "Vendor Advisory" {
values = append(values, CveContentStr{Nvd, r.Link})
}
}
}
@@ -77,31 +61,17 @@ func (v CveContents) PrimarySrcURLs(lang, myFamily, cveID string, confidences Co
order := CveContentTypes{Nvd, NewCveContentType(myFamily), GitHub}
for _, ctype := range order {
if conts, found := v[ctype]; found {
for _, cont := range conts {
if cont.SourceLink == "" {
continue
}
values = append(values, CveContentStr{ctype, cont.SourceLink})
if cont, found := v[ctype]; found {
if cont.SourceLink == "" {
continue
}
values = append(values, CveContentStr{ctype, cont.SourceLink})
}
}
jvnMatch := false
for _, confidence := range confidences {
if confidence.DetectionMethod == JvnVendorProductMatchStr {
jvnMatch = true
break
}
}
if lang == "ja" || jvnMatch {
if conts, found := v[Jvn]; found {
for _, cont := range conts {
if 0 < len(cont.SourceLink) {
values = append(values, CveContentStr{Jvn, cont.SourceLink})
}
}
if lang == "ja" {
if cont, found := v[Jvn]; found && 0 < len(cont.SourceLink) {
values = append(values, CveContentStr{Jvn, cont.SourceLink})
}
}
@@ -116,17 +86,14 @@ func (v CveContents) PrimarySrcURLs(lang, myFamily, cveID string, confidences Co
// PatchURLs returns link of patch
func (v CveContents) PatchURLs() (urls []string) {
conts, found := v[Nvd]
cont, found := v[Nvd]
if !found {
return
}
for _, cont := range conts {
for _, r := range cont.References {
for _, t := range r.Tags {
if t == "Patch" {
urls = append(urls, r.Link)
}
for _, r := range cont.References {
for _, t := range r.Tags {
if t == "Patch" {
urls = append(urls, r.Link)
}
}
}
@@ -163,15 +130,11 @@ func (v CveContents) Cpes(myFamily string) (values []CveContentCpes) {
order = append(order, AllCveContetTypes.Except(order...)...)
for _, ctype := range order {
if conts, found := v[ctype]; found {
for _, cont := range conts {
if 0 < len(cont.Cpes) {
values = append(values, CveContentCpes{
Type: ctype,
Value: cont.Cpes,
})
}
}
if cont, found := v[ctype]; found && 0 < len(cont.Cpes) {
values = append(values, CveContentCpes{
Type: ctype,
Value: cont.Cpes,
})
}
}
return
@@ -189,15 +152,11 @@ func (v CveContents) References(myFamily string) (values []CveContentRefs) {
order = append(order, AllCveContetTypes.Except(order...)...)
for _, ctype := range order {
if conts, found := v[ctype]; found {
for _, cont := range conts {
if 0 < len(cont.References) {
values = append(values, CveContentRefs{
Type: ctype,
Value: cont.References,
})
}
}
if cont, found := v[ctype]; found && 0 < len(cont.References) {
values = append(values, CveContentRefs{
Type: ctype,
Value: cont.References,
})
}
}
@@ -209,21 +168,17 @@ func (v CveContents) CweIDs(myFamily string) (values []CveContentStr) {
order := CveContentTypes{NewCveContentType(myFamily)}
order = append(order, AllCveContetTypes.Except(order...)...)
for _, ctype := range order {
if conts, found := v[ctype]; found {
for _, cont := range conts {
if 0 < len(cont.CweIDs) {
for _, cweID := range cont.CweIDs {
for _, val := range values {
if val.Value == cweID {
continue
}
}
values = append(values, CveContentStr{
Type: ctype,
Value: cweID,
})
if cont, found := v[ctype]; found && 0 < len(cont.CweIDs) {
for _, cweID := range cont.CweIDs {
for _, val := range values {
if val.Value == cweID {
continue
}
}
values = append(values, CveContentStr{
Type: ctype,
Value: cweID,
})
}
}
}
@@ -242,47 +197,6 @@ 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
sort.Slice(contents, func(i, j int) bool {
if contents[i].Cvss3Score > contents[j].Cvss3Score {
return true
} else if contents[i].Cvss3Score == contents[i].Cvss3Score {
if contents[i].Cvss2Score > contents[j].Cvss2Score {
return true
} else if contents[i].Cvss2Score == contents[i].Cvss2Score {
if contents[i].SourceLink < contents[j].SourceLink {
return true
}
}
}
return false
})
v[contType] = contents
}
for contType, contents := range v {
for cveID, cont := range contents {
sort.Slice(cont.References, func(i, j int) bool {
return cont.References[i].Link < cont.References[j].Link
})
sort.Slice(cont.CweIDs, func(i, j int) bool {
return cont.CweIDs[i] < cont.CweIDs[j]
})
for i, ref := range cont.References {
// sort v.CveContents[].References[].Tags
sort.Slice(ref.Tags, func(j, k int) bool {
return ref.Tags[j] < ref.Tags[k]
})
cont.References[i] = ref
}
contents[cveID] = cont
}
v[contType] = contents
}
}
// CveContent has abstraction of various vulnerability information
type CveContent struct {
Type CveContentType `json:"type"`
@@ -319,7 +233,7 @@ func NewCveContentType(name string) CveContentType {
return Nvd
case "jvn":
return Jvn
case "redhat", "centos", "alma", "rocky":
case "redhat", "centos":
return RedHat
case "oracle":
return Oracle
@@ -331,8 +245,6 @@ func NewCveContentType(name string) CveContentType {
return RedHatAPI
case "debian_security_tracker":
return DebianSecurityTracker
case "ubuntu_api":
return UbuntuAPI
case "microsoft":
return Microsoft
case "wordpress":
@@ -370,9 +282,6 @@ const (
// Ubuntu is Ubuntu
Ubuntu CveContentType = "ubuntu"
// UbuntuAPI is Ubuntu
UbuntuAPI CveContentType = "ubuntu_api"
// Oracle is Oracle Linux
Oracle CveContentType = "oracle"
@@ -408,11 +317,10 @@ var AllCveContetTypes = CveContentTypes{
RedHat,
RedHatAPI,
Debian,
DebianSecurityTracker,
Ubuntu,
UbuntuAPI,
Amazon,
SUSE,
DebianSecurityTracker,
WpScan,
Trivy,
GitHub,

View File

@@ -11,12 +11,12 @@ func TestExcept(t *testing.T) {
out CveContents
}{{
in: CveContents{
RedHat: []CveContent{{Type: RedHat}},
Ubuntu: []CveContent{{Type: Ubuntu}},
Debian: []CveContent{{Type: Debian}},
RedHat: {Type: RedHat},
Ubuntu: {Type: Ubuntu},
Debian: {Type: Debian},
},
out: CveContents{
RedHat: []CveContent{{Type: RedHat}},
RedHat: {Type: RedHat},
},
},
}
@@ -30,10 +30,9 @@ func TestExcept(t *testing.T) {
func TestSourceLinks(t *testing.T) {
type in struct {
lang string
cveID string
cont CveContents
confidences Confidences
lang string
cveID string
cont CveContents
}
var tests = []struct {
in in
@@ -45,15 +44,15 @@ func TestSourceLinks(t *testing.T) {
lang: "ja",
cveID: "CVE-2017-6074",
cont: CveContents{
Jvn: []CveContent{{
Jvn: {
Type: Jvn,
SourceLink: "https://jvn.jp/vu/JVNVU93610402/",
}},
RedHat: []CveContent{{
},
RedHat: {
Type: RedHat,
SourceLink: "https://access.redhat.com/security/cve/CVE-2017-6074",
}},
Nvd: []CveContent{{
},
Nvd: {
Type: Nvd,
References: []Reference{
{
@@ -70,7 +69,7 @@ func TestSourceLinks(t *testing.T) {
},
},
SourceLink: "https://nvd.nist.gov/vuln/detail/CVE-2017-6074",
}},
},
},
},
out: []CveContentStr{
@@ -98,14 +97,14 @@ func TestSourceLinks(t *testing.T) {
lang: "en",
cveID: "CVE-2017-6074",
cont: CveContents{
Jvn: []CveContent{{
Jvn: {
Type: Jvn,
SourceLink: "https://jvn.jp/vu/JVNVU93610402/",
}},
RedHat: []CveContent{{
},
RedHat: {
Type: RedHat,
SourceLink: "https://access.redhat.com/security/cve/CVE-2017-6074",
}},
},
},
},
out: []CveContentStr{
@@ -129,123 +128,11 @@ func TestSourceLinks(t *testing.T) {
},
},
},
// Confidence: JvnVendorProductMatch
{
in: in{
lang: "en",
cveID: "CVE-2017-6074",
cont: CveContents{
Jvn: []CveContent{{
Type: Jvn,
SourceLink: "https://jvn.jp/vu/JVNVU93610402/",
}},
},
confidences: Confidences{
Confidence{DetectionMethod: JvnVendorProductMatchStr},
},
},
out: []CveContentStr{
{
Type: Jvn,
Value: "https://jvn.jp/vu/JVNVU93610402/",
},
},
},
}
for i, tt := range tests {
actual := tt.in.cont.PrimarySrcURLs(tt.in.lang, "redhat", tt.in.cveID, tt.in.confidences)
actual := tt.in.cont.PrimarySrcURLs(tt.in.lang, "redhat", tt.in.cveID)
if !reflect.DeepEqual(tt.out, actual) {
t.Errorf("\n[%d] expected: %v\n actual: %v\n", i, tt.out, actual)
}
}
}
func TestCveContents_Sort(t *testing.T) {
tests := []struct {
name string
v CveContents
want CveContents
}{
{
name: "sorted",
v: map[CveContentType][]CveContent{
"jvn": {
{Cvss3Score: 3},
{Cvss3Score: 10},
},
},
want: map[CveContentType][]CveContent{
"jvn": {
{Cvss3Score: 10},
{Cvss3Score: 3},
},
},
},
{
name: "sort JVN by cvss3, cvss2, sourceLink",
v: map[CveContentType][]CveContent{
"jvn": {
{
Cvss3Score: 3,
Cvss2Score: 3,
SourceLink: "https://jvndb.jvn.jp/ja/contents/2023/JVNDB-2023-001210.html",
},
{
Cvss3Score: 3,
Cvss2Score: 3,
SourceLink: "https://jvndb.jvn.jp/ja/contents/2021/JVNDB-2021-001210.html",
},
},
},
want: map[CveContentType][]CveContent{
"jvn": {
{
Cvss3Score: 3,
Cvss2Score: 3,
SourceLink: "https://jvndb.jvn.jp/ja/contents/2021/JVNDB-2021-001210.html",
},
{
Cvss3Score: 3,
Cvss2Score: 3,
SourceLink: "https://jvndb.jvn.jp/ja/contents/2023/JVNDB-2023-001210.html",
},
},
},
},
{
name: "sort JVN by cvss3, cvss2",
v: map[CveContentType][]CveContent{
"jvn": {
{
Cvss3Score: 3,
Cvss2Score: 1,
},
{
Cvss3Score: 3,
Cvss2Score: 10,
},
},
},
want: map[CveContentType][]CveContent{
"jvn": {
{
Cvss3Score: 3,
Cvss2Score: 10,
},
{
Cvss3Score: 3,
Cvss2Score: 1,
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.v.Sort()
if !reflect.DeepEqual(tt.v, tt.want) {
t.Errorf("\n[%s] expected: %v\n actual: %v\n", tt.name, tt.want, tt.v)
}
})
}
}

View File

@@ -88,34 +88,35 @@ func (s LibraryScanner) getVulnDetail(tvuln types.DetectedVulnerability) (vinfo
vinfo.CveID = tvuln.VulnerabilityID
vinfo.CveContents = getCveContents(tvuln.VulnerabilityID, vul)
vinfo.LibraryFixedIns = []LibraryFixedIn{
{
Key: s.GetLibraryKey(),
Name: tvuln.PkgName,
FixedIn: tvuln.FixedVersion,
Path: s.Path,
},
if tvuln.FixedVersion != "" {
vinfo.LibraryFixedIns = []LibraryFixedIn{
{
Key: s.GetLibraryKey(),
Name: tvuln.PkgName,
FixedIn: tvuln.FixedVersion,
Path: s.Path,
},
}
}
return vinfo, nil
}
func getCveContents(cveID string, vul trivyDBTypes.Vulnerability) (contents map[CveContentType][]CveContent) {
contents = map[CveContentType][]CveContent{}
func getCveContents(cveID string, vul trivyDBTypes.Vulnerability) (contents map[CveContentType]CveContent) {
contents = map[CveContentType]CveContent{}
refs := []Reference{}
for _, refURL := range vul.References {
refs = append(refs, Reference{Source: "trivy", Link: refURL})
}
contents[Trivy] = []CveContent{
{
Type: Trivy,
CveID: cveID,
Title: vul.Title,
Summary: vul.Description,
Cvss3Severity: string(vul.Severity),
References: refs,
},
content := CveContent{
Type: Trivy,
CveID: cveID,
Title: vul.Title,
Summary: vul.Description,
Cvss3Severity: string(vul.Severity),
References: refs,
}
contents[Trivy] = content
return contents
}

View File

@@ -291,11 +291,12 @@ func (r ScanResult) IsContainer() bool {
}
// RemoveRaspbianPackFromResult is for Raspberry Pi and removes the Raspberry Pi dedicated package from ScanResult.
func (r ScanResult) RemoveRaspbianPackFromResult() *ScanResult {
func (r ScanResult) RemoveRaspbianPackFromResult() ScanResult {
if r.Family != constant.Raspbian {
return &r
return r
}
result := r
packs := make(Packages)
for _, pack := range r.Packages {
if !IsRaspbianPackage(pack.Name, pack.Version) {
@@ -310,10 +311,10 @@ func (r ScanResult) RemoveRaspbianPackFromResult() *ScanResult {
}
}
r.Packages = packs
r.SrcPackages = srcPacks
result.Packages = packs
result.SrcPackages = srcPacks
return &r
return result
}
// ClearFields clears a given fields of ScanResult
@@ -415,9 +416,22 @@ func (r *ScanResult) SortForJSONOutput() {
sort.Slice(v.Mitigations, func(i, j int) bool {
return v.Mitigations[i].URL < v.Mitigations[j].URL
})
v.CveContents.Sort()
for kk, vv := range v.CveContents {
sort.Slice(vv.References, func(i, j int) bool {
return vv.References[i].Link < vv.References[j].Link
})
sort.Slice(vv.CweIDs, func(i, j int) bool {
return vv.CweIDs[i] < vv.CweIDs[j]
})
for kkk, vvv := range vv.References {
// sort v.CveContents[].References[].Tags
sort.Slice(vvv.Tags, func(i, j int) bool {
return vvv.Tags[i] < vvv.Tags[j]
})
vv.References[kkk] = vvv
}
v.CveContents[kk] = vv
}
sort.Slice(v.AlertDict.En, func(i, j int) bool {
return v.AlertDict.En[i].Title < v.AlertDict.En[j].Title
})

View File

@@ -56,16 +56,6 @@ func TestIsDisplayUpdatableNum(t *testing.T) {
family: constant.CentOS,
expected: true,
},
{
mode: []byte{config.Fast},
family: constant.Alma,
expected: true,
},
{
mode: []byte{config.Fast},
family: constant.Rocky,
expected: true,
},
{
mode: []byte{config.Fast},
family: constant.Amazon,
@@ -104,55 +94,6 @@ func TestIsDisplayUpdatableNum(t *testing.T) {
}
}
func TestRemoveRaspbianPackFromResult(t *testing.T) {
var tests = []struct {
in ScanResult
expected ScanResult
}{
{
in: ScanResult{
Family: constant.Raspbian,
Packages: Packages{
"apt": Package{Name: "apt", Version: "1.8.2.1"},
"libraspberrypi-dev": Package{Name: "libraspberrypi-dev", Version: "1.20200811-1"},
},
SrcPackages: SrcPackages{},
},
expected: ScanResult{
Family: constant.Raspbian,
Packages: Packages{
"apt": Package{Name: "apt", Version: "1.8.2.1"},
},
SrcPackages: SrcPackages{},
},
},
{
in: ScanResult{
Family: constant.Debian,
Packages: Packages{
"apt": Package{Name: "apt", Version: "1.8.2.1"},
},
SrcPackages: SrcPackages{},
},
expected: ScanResult{
Family: constant.Debian,
Packages: Packages{
"apt": Package{Name: "apt", Version: "1.8.2.1"},
},
SrcPackages: SrcPackages{},
},
},
}
for i, tt := range tests {
r := tt.in
r = *r.RemoveRaspbianPackFromResult()
if !reflect.DeepEqual(r, tt.expected) {
t.Errorf("[%d] expected %+v, actual %+v", i, tt.expected, r)
}
}
}
func TestScanResult_Sort(t *testing.T) {
type fields struct {
Packages Packages
@@ -198,17 +139,17 @@ func TestScanResult_Sort(t *testing.T) {
{Name: "b"},
},
CveContents: CveContents{
"nvd": []CveContent{{
"nvd": CveContent{
References: References{
Reference{Link: "a"},
Reference{Link: "b"},
}},
},
},
"jvn": []CveContent{{
"jvn": CveContent{
References: References{
Reference{Link: "a"},
Reference{Link: "b"},
}},
},
},
},
AlertDict: AlertDict{
@@ -257,17 +198,17 @@ func TestScanResult_Sort(t *testing.T) {
{Name: "b"},
},
CveContents: CveContents{
"nvd": []CveContent{{
"nvd": CveContent{
References: References{
Reference{Link: "a"},
Reference{Link: "b"},
}},
},
},
"jvn": []CveContent{{
"jvn": CveContent{
References: References{
Reference{Link: "a"},
Reference{Link: "b"},
}},
},
},
},
AlertDict: AlertDict{
@@ -319,17 +260,17 @@ func TestScanResult_Sort(t *testing.T) {
{Name: "a"},
},
CveContents: CveContents{
"nvd": []CveContent{{
"nvd": CveContent{
References: References{
Reference{Link: "b"},
Reference{Link: "a"},
}},
},
},
"jvn": []CveContent{{
"jvn": CveContent{
References: References{
Reference{Link: "b"},
Reference{Link: "a"},
}},
},
},
},
AlertDict: AlertDict{
@@ -378,17 +319,17 @@ func TestScanResult_Sort(t *testing.T) {
{Name: "b"},
},
CveContents: CveContents{
"nvd": []CveContent{{
"nvd": CveContent{
References: References{
Reference{Link: "a"},
Reference{Link: "b"},
}},
},
},
"jvn": []CveContent{{
"jvn": CveContent{
References: References{
Reference{Link: "a"},
Reference{Link: "b"},
}},
},
},
},
AlertDict: AlertDict{
@@ -405,115 +346,6 @@ func TestScanResult_Sort(t *testing.T) {
},
},
},
{
name: "sort JVN by cvss v3",
fields: fields{
ScannedCves: VulnInfos{
"CVE-2014-3591": VulnInfo{
CveContents: CveContents{
"jvn": []CveContent{
{Cvss3Score: 3},
{Cvss3Score: 10},
},
},
},
},
},
expected: fields{
ScannedCves: VulnInfos{
"CVE-2014-3591": VulnInfo{
CveContents: CveContents{
"jvn": []CveContent{
{Cvss3Score: 10},
{Cvss3Score: 3},
},
},
},
},
},
},
{
name: "sort JVN by cvss3, cvss2, sourceLink",
fields: fields{
ScannedCves: VulnInfos{
"CVE-2014-3591": VulnInfo{
CveContents: CveContents{
"jvn": []CveContent{
{
Cvss3Score: 3,
Cvss2Score: 3,
SourceLink: "https://jvndb.jvn.jp/ja/contents/2023/JVNDB-2023-001210.html",
},
{
Cvss3Score: 3,
Cvss2Score: 3,
SourceLink: "https://jvndb.jvn.jp/ja/contents/2021/JVNDB-2021-001210.html",
},
},
},
},
},
},
expected: fields{
ScannedCves: VulnInfos{
"CVE-2014-3591": VulnInfo{
CveContents: CveContents{
"jvn": []CveContent{
{
Cvss3Score: 3,
Cvss2Score: 3,
SourceLink: "https://jvndb.jvn.jp/ja/contents/2021/JVNDB-2021-001210.html",
},
{
Cvss3Score: 3,
Cvss2Score: 3,
SourceLink: "https://jvndb.jvn.jp/ja/contents/2023/JVNDB-2023-001210.html",
},
},
},
},
},
},
},
{
name: "sort JVN by cvss3, cvss2",
fields: fields{
ScannedCves: VulnInfos{
"CVE-2014-3591": VulnInfo{
CveContents: CveContents{
"jvn": []CveContent{
{
Cvss3Score: 3,
Cvss2Score: 1,
},
{
Cvss3Score: 3,
Cvss2Score: 10,
},
},
},
},
},
},
expected: fields{
ScannedCves: VulnInfos{
"CVE-2014-3591": VulnInfo{
CveContents: CveContents{
"jvn": []CveContent{
{
Cvss3Score: 3,
Cvss2Score: 10,
},
{
Cvss3Score: 3,
Cvss2Score: 1,
},
},
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package models
@@ -6,120 +5,116 @@ package models
import (
"strings"
cvedict "github.com/vulsio/go-cve-dictionary/models"
cvedict "github.com/kotakanbe/go-cve-dictionary/models"
)
// ConvertJvnToModel convert JVN to CveContent
func ConvertJvnToModel(cveID string, jvns []cvedict.Jvn) []CveContent {
cves := []CveContent{}
for _, jvn := range jvns {
// cpes := []Cpe{}
// for _, c := range jvn.Cpes {
// cpes = append(cpes, Cpe{
// FormattedString: c.FormattedString,
// URI: c.URI,
// })
// }
refs := []Reference{}
for _, r := range jvn.References {
refs = append(refs, Reference{
Link: r.Link,
Source: r.Source,
})
}
cve := CveContent{
Type: Jvn,
CveID: cveID,
Title: jvn.Title,
Summary: jvn.Summary,
Cvss2Score: jvn.Cvss2.BaseScore,
Cvss2Vector: jvn.Cvss2.VectorString,
Cvss2Severity: jvn.Cvss2.Severity,
Cvss3Score: jvn.Cvss3.BaseScore,
Cvss3Vector: jvn.Cvss3.VectorString,
Cvss3Severity: jvn.Cvss3.BaseSeverity,
SourceLink: jvn.JvnLink,
// Cpes: cpes,
References: refs,
Published: jvn.PublishedDate,
LastModified: jvn.LastModifiedDate,
}
cves = append(cves, cve)
func ConvertJvnToModel(cveID string, jvn *cvedict.Jvn) *CveContent {
if jvn == nil {
return nil
}
// var cpes = []Cpe{}
// for _, c := range jvn.Cpes {
// cpes = append(cpes, Cpe{
// FormattedString: c.FormattedString,
// URI: c.URI,
// })
// }
refs := []Reference{}
for _, r := range jvn.References {
refs = append(refs, Reference{
Link: r.Link,
Source: r.Source,
})
}
return &CveContent{
Type: Jvn,
CveID: cveID,
Title: jvn.Title,
Summary: jvn.Summary,
Cvss2Score: jvn.Cvss2.BaseScore,
Cvss2Vector: jvn.Cvss2.VectorString,
Cvss2Severity: jvn.Cvss2.Severity,
Cvss3Score: jvn.Cvss3.BaseScore,
Cvss3Vector: jvn.Cvss3.VectorString,
Cvss3Severity: jvn.Cvss3.BaseSeverity,
SourceLink: jvn.JvnLink,
// Cpes: cpes,
References: refs,
Published: jvn.PublishedDate,
LastModified: jvn.LastModifiedDate,
}
return cves
}
// ConvertNvdToModel convert NVD to CveContent
func ConvertNvdToModel(cveID string, nvds []cvedict.Nvd) ([]CveContent, []Exploit, []Mitigation) {
cves := []CveContent{}
// ConvertNvdJSONToModel convert NVD to CveContent
func ConvertNvdJSONToModel(cveID string, nvd *cvedict.NvdJSON) (*CveContent, []Exploit, []Mitigation) {
if nvd == nil {
return nil, nil, nil
}
// var cpes = []Cpe{}
// for _, c := range nvd.Cpes {
// cpes = append(cpes, Cpe{
// FormattedString: c.FormattedString,
// URI: c.URI,
// })
// }
refs := []Reference{}
exploits := []Exploit{}
mitigations := []Mitigation{}
for _, nvd := range nvds {
// cpes := []Cpe{}
// for _, c := range nvd.Cpes {
// cpes = append(cpes, Cpe{
// FormattedString: c.FormattedString,
// URI: c.URI,
// })
// }
for _, r := range nvd.References {
var tags []string
if 0 < len(r.Tags) {
tags = strings.Split(r.Tags, ",")
}
refs = append(refs, Reference{
Link: r.Link,
Source: r.Source,
Tags: tags,
for _, r := range nvd.References {
var tags []string
if 0 < len(r.Tags) {
tags = strings.Split(r.Tags, ",")
}
refs = append(refs, Reference{
Link: r.Link,
Source: r.Source,
Tags: tags,
})
if strings.Contains(r.Tags, "Exploit") {
exploits = append(exploits, Exploit{
//TODO Add const to here
// https://github.com/vulsio/go-exploitdb/blob/master/models/exploit.go#L13-L18
ExploitType: "nvd",
URL: r.Link,
})
if strings.Contains(r.Tags, "Exploit") {
exploits = append(exploits, Exploit{
//TODO Add const to here
// https://github.com/vulsio/go-exploitdb/blob/master/models/exploit.go#L13-L18
ExploitType: "nvd",
URL: r.Link,
})
}
if strings.Contains(r.Tags, "Mitigation") {
mitigations = append(mitigations, Mitigation{
CveContentType: Nvd,
URL: r.Link,
})
}
}
cweIDs := []string{}
for _, cid := range nvd.Cwes {
cweIDs = append(cweIDs, cid.CweID)
if strings.Contains(r.Tags, "Mitigation") {
mitigations = append(mitigations, Mitigation{
CveContentType: Nvd,
URL: r.Link,
})
}
desc := []string{}
for _, d := range nvd.Descriptions {
desc = append(desc, d.Value)
}
cve := CveContent{
Type: Nvd,
CveID: cveID,
Summary: strings.Join(desc, "\n"),
Cvss2Score: nvd.Cvss2.BaseScore,
Cvss2Vector: nvd.Cvss2.VectorString,
Cvss2Severity: nvd.Cvss2.Severity,
Cvss3Score: nvd.Cvss3.BaseScore,
Cvss3Vector: nvd.Cvss3.VectorString,
Cvss3Severity: nvd.Cvss3.BaseSeverity,
SourceLink: "https://nvd.nist.gov/vuln/detail/" + cveID,
// Cpes: cpes,
CweIDs: cweIDs,
References: refs,
Published: nvd.PublishedDate,
LastModified: nvd.LastModifiedDate,
}
cves = append(cves, cve)
}
return cves, exploits, mitigations
cweIDs := []string{}
for _, cid := range nvd.Cwes {
cweIDs = append(cweIDs, cid.CweID)
}
desc := []string{}
for _, d := range nvd.Descriptions {
desc = append(desc, d.Value)
}
return &CveContent{
Type: Nvd,
CveID: cveID,
Summary: strings.Join(desc, "\n"),
Cvss2Score: nvd.Cvss2.BaseScore,
Cvss2Vector: nvd.Cvss2.VectorString,
Cvss2Severity: nvd.Cvss2.Severity,
Cvss3Score: nvd.Cvss3.BaseScore,
Cvss3Vector: nvd.Cvss3.VectorString,
Cvss3Severity: nvd.Cvss3.BaseSeverity,
SourceLink: "https://nvd.nist.gov/vuln/detail/" + cveID,
// Cpes: cpes,
CweIDs: cweIDs,
References: refs,
Published: nvd.PublishedDate,
LastModified: nvd.LastModifiedDate,
}, exploits, mitigations
}

View File

@@ -37,18 +37,6 @@ func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {
})
}
// FilterByConfidenceOver scored vulnerabilities
func (v VulnInfos) FilterByConfidenceOver(over int) VulnInfos {
return v.Find(func(v VulnInfo) bool {
for _, c := range v.Confidences {
if over <= c.Score {
return true
}
}
return false
})
}
// FilterIgnoreCves filter function.
func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {
return v.Find(func(v VulnInfo) bool {
@@ -87,8 +75,9 @@ func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {
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
@@ -358,46 +347,30 @@ func (v VulnInfo) CveIDDiffFormat() string {
// Titles returns title (TUI)
func (v VulnInfo) Titles(lang, myFamily string) (values []CveContentStr) {
if lang == "ja" {
if conts, found := v.CveContents[Jvn]; found {
for _, cont := range conts {
if cont.Title != "" {
values = append(values, CveContentStr{Jvn, cont.Title})
}
}
if cont, found := v.CveContents[Jvn]; found && cont.Title != "" {
values = append(values, CveContentStr{Jvn, cont.Title})
}
}
// RedHat API has one line title.
if conts, found := v.CveContents[RedHatAPI]; found {
for _, cont := range conts {
if cont.Title != "" {
values = append(values, CveContentStr{RedHatAPI, cont.Title})
}
}
if cont, found := v.CveContents[RedHatAPI]; found && cont.Title != "" {
values = append(values, CveContentStr{RedHatAPI, cont.Title})
}
// GitHub security alerts has a title.
if conts, found := v.CveContents[GitHub]; found {
for _, cont := range conts {
if cont.Title != "" {
values = append(values, CveContentStr{GitHub, cont.Title})
}
}
if cont, found := v.CveContents[GitHub]; found && cont.Title != "" {
values = append(values, CveContentStr{GitHub, cont.Title})
}
order := CveContentTypes{Trivy, Nvd, NewCveContentType(myFamily)}
order = append(order, AllCveContetTypes.Except(append(order, Jvn)...)...)
for _, ctype := range order {
if conts, found := v.CveContents[ctype]; found {
for _, cont := range conts {
if cont.Summary != "" {
summary := strings.Replace(cont.Summary, "\n", " ", -1)
values = append(values, CveContentStr{
Type: ctype,
Value: summary,
})
}
}
if cont, found := v.CveContents[ctype]; found && cont.Summary != "" {
summary := strings.Replace(cont.Summary, "\n", " ", -1)
values = append(values, CveContentStr{
Type: ctype,
Value: summary,
})
}
}
@@ -420,31 +393,23 @@ func (v VulnInfo) Titles(lang, myFamily string) (values []CveContentStr) {
// Summaries returns summaries
func (v VulnInfo) Summaries(lang, myFamily string) (values []CveContentStr) {
if lang == "ja" {
if conts, found := v.CveContents[Jvn]; found {
for _, cont := range conts {
if cont.Summary != "" {
summary := cont.Title
summary += "\n" + strings.Replace(
strings.Replace(cont.Summary, "\n", " ", -1), "\r", " ", -1)
values = append(values, CveContentStr{Jvn, summary})
}
}
if cont, found := v.CveContents[Jvn]; found && cont.Summary != "" {
summary := cont.Title
summary += "\n" + strings.Replace(
strings.Replace(cont.Summary, "\n", " ", -1), "\r", " ", -1)
values = append(values, CveContentStr{Jvn, summary})
}
}
order := CveContentTypes{Trivy, NewCveContentType(myFamily), Nvd, GitHub}
order = append(order, AllCveContetTypes.Except(append(order, Jvn)...)...)
for _, ctype := range order {
if conts, found := v.CveContents[ctype]; found {
for _, cont := range conts {
if cont.Summary != "" {
summary := strings.Replace(cont.Summary, "\n", " ", -1)
values = append(values, CveContentStr{
Type: ctype,
Value: summary,
})
}
}
if cont, found := v.CveContents[ctype]; found && cont.Summary != "" {
summary := strings.Replace(cont.Summary, "\n", " ", -1)
values = append(values, CveContentStr{
Type: ctype,
Value: summary,
})
}
}
@@ -455,15 +420,11 @@ func (v VulnInfo) Summaries(lang, myFamily string) (values []CveContentStr) {
})
}
if conts, ok := v.CveContents[WpScan]; ok {
for _, cont := range conts {
if cont.Title != "" {
values = append(values, CveContentStr{
Type: WpScan,
Value: cont.Title,
})
}
}
if v, ok := v.CveContents[WpScan]; ok {
values = append(values, CveContentStr{
Type: WpScan,
Value: v.Title,
})
}
if len(values) == 0 {
@@ -480,22 +441,20 @@ func (v VulnInfo) Summaries(lang, myFamily string) (values []CveContentStr) {
func (v VulnInfo) Cvss2Scores() (values []CveContentCvss) {
order := []CveContentType{RedHatAPI, RedHat, Nvd, Jvn}
for _, ctype := range order {
if conts, found := v.CveContents[ctype]; found {
for _, cont := range conts {
if cont.Cvss2Score == 0 && cont.Cvss2Severity == "" {
continue
}
// https://nvd.nist.gov/vuln-metrics/cvss
values = append(values, CveContentCvss{
Type: ctype,
Value: Cvss{
Type: CVSS2,
Score: cont.Cvss2Score,
Vector: cont.Cvss2Vector,
Severity: strings.ToUpper(cont.Cvss2Severity),
},
})
if cont, found := v.CveContents[ctype]; found {
if cont.Cvss2Score == 0 && cont.Cvss2Severity == "" {
continue
}
// https://nvd.nist.gov/vuln-metrics/cvss
values = append(values, CveContentCvss{
Type: ctype,
Value: Cvss{
Type: CVSS2,
Score: cont.Cvss2Score,
Vector: cont.Cvss2Vector,
Severity: strings.ToUpper(cont.Cvss2Severity),
},
})
}
}
return
@@ -505,40 +464,34 @@ func (v VulnInfo) Cvss2Scores() (values []CveContentCvss) {
func (v VulnInfo) Cvss3Scores() (values []CveContentCvss) {
order := []CveContentType{RedHatAPI, RedHat, Nvd, Jvn}
for _, ctype := range order {
if conts, found := v.CveContents[ctype]; found {
for _, cont := range conts {
if cont.Cvss3Score == 0 && cont.Cvss3Severity == "" {
continue
}
// https://nvd.nist.gov/vuln-metrics/cvss
values = append(values, CveContentCvss{
Type: ctype,
Value: Cvss{
Type: CVSS3,
Score: cont.Cvss3Score,
Vector: cont.Cvss3Vector,
Severity: strings.ToUpper(cont.Cvss3Severity),
},
})
if cont, found := v.CveContents[ctype]; found {
if cont.Cvss3Score == 0 && cont.Cvss3Severity == "" {
continue
}
// https://nvd.nist.gov/vuln-metrics/cvss
values = append(values, CveContentCvss{
Type: ctype,
Value: Cvss{
Type: CVSS3,
Score: cont.Cvss3Score,
Vector: cont.Cvss3Vector,
Severity: strings.ToUpper(cont.Cvss3Severity),
},
})
}
}
for _, ctype := range []CveContentType{Debian, DebianSecurityTracker, Ubuntu, Amazon, Trivy, GitHub, WpScan} {
if conts, found := v.CveContents[ctype]; found {
for _, cont := range conts {
if cont.Cvss3Severity != "" {
values = append(values, CveContentCvss{
Type: ctype,
Value: Cvss{
Type: CVSS3,
Score: severityToCvssScoreRoughly(cont.Cvss3Severity),
CalculatedBySeverity: true,
Severity: strings.ToUpper(cont.Cvss3Severity),
},
})
}
}
if cont, found := v.CveContents[ctype]; found && cont.Cvss3Severity != "" {
values = append(values, CveContentCvss{
Type: ctype,
Value: Cvss{
Type: CVSS3,
Score: severityToCvssScoreRoughly(cont.Cvss3Severity),
CalculatedBySeverity: true,
Severity: strings.ToUpper(cont.Cvss3Severity),
},
})
}
}
@@ -600,28 +553,24 @@ func (v VulnInfo) MaxCvss2Score() CveContentCvss {
// AttackVector returns attack vector string
func (v VulnInfo) AttackVector() string {
for _, conts := range v.CveContents {
for _, cont := range conts {
if strings.HasPrefix(cont.Cvss2Vector, "AV:N") ||
strings.Contains(cont.Cvss3Vector, "AV:N") {
return "AV:N"
} else if strings.HasPrefix(cont.Cvss2Vector, "AV:A") ||
strings.Contains(cont.Cvss3Vector, "AV:A") {
return "AV:A"
} else if strings.HasPrefix(cont.Cvss2Vector, "AV:L") ||
strings.Contains(cont.Cvss3Vector, "AV:L") {
return "AV:L"
} else if strings.Contains(cont.Cvss3Vector, "AV:P") {
// no AV:P in CVSS v2
return "AV:P"
}
for _, cnt := range v.CveContents {
if strings.HasPrefix(cnt.Cvss2Vector, "AV:N") ||
strings.Contains(cnt.Cvss3Vector, "AV:N") {
return "AV:N"
} else if strings.HasPrefix(cnt.Cvss2Vector, "AV:A") ||
strings.Contains(cnt.Cvss3Vector, "AV:A") {
return "AV:A"
} else if strings.HasPrefix(cnt.Cvss2Vector, "AV:L") ||
strings.Contains(cnt.Cvss3Vector, "AV:L") {
return "AV:L"
} else if strings.Contains(cnt.Cvss3Vector, "AV:P") {
// no AV:P in CVSS v2
return "AV:P"
}
}
if conts, found := v.CveContents[DebianSecurityTracker]; found {
for _, cont := range conts {
if attackRange, found := cont.Optional["attack range"]; found {
return attackRange
}
if cont, found := v.CveContents[DebianSecurityTracker]; found {
if attackRange, found := cont.Optional["attack range"]; found {
return attackRange
}
}
return ""
@@ -859,56 +808,53 @@ func (c Confidence) String() string {
type DetectionMethod string
const (
// NvdExactVersionMatchStr :
NvdExactVersionMatchStr = "NvdExactVersionMatch"
// CpeNameMatchStr is a String representation of CpeNameMatch
CpeNameMatchStr = "CpeNameMatch"
// NvdRoughVersionMatchStr :
NvdRoughVersionMatchStr = "NvdRoughVersionMatch"
// YumUpdateSecurityMatchStr is a String representation of YumUpdateSecurityMatch
YumUpdateSecurityMatchStr = "YumUpdateSecurityMatch"
// NvdVendorProductMatchStr :
NvdVendorProductMatchStr = "NvdVendorProductMatch"
// JvnVendorProductMatchStr :
JvnVendorProductMatchStr = "JvnVendorProductMatch"
// PkgAuditMatchStr :
// PkgAuditMatchStr is a String representation of PkgAuditMatch
PkgAuditMatchStr = "PkgAuditMatch"
// OvalMatchStr :
// OvalMatchStr is a String representation of OvalMatch
OvalMatchStr = "OvalMatch"
// RedHatAPIStr is :
// RedHatAPIStr is a String representation of RedHatAPIMatch
RedHatAPIStr = "RedHatAPIMatch"
// DebianSecurityTrackerMatchStr :
// DebianSecurityTrackerMatchStr is a String representation of DebianSecurityTrackerMatch
DebianSecurityTrackerMatchStr = "DebianSecurityTrackerMatch"
// UbuntuAPIMatchStr :
UbuntuAPIMatchStr = "UbuntuAPIMatch"
// TrivyMatchStr :
// TrivyMatchStr is a String representation of Trivy
TrivyMatchStr = "TrivyMatch"
// ChangelogExactMatchStr :
// ChangelogExactMatchStr is a String representation of ChangelogExactMatch
ChangelogExactMatchStr = "ChangelogExactMatch"
// ChangelogRoughMatchStr :
ChangelogRoughMatchStr = "ChangelogRoughMatch"
// ChangelogLenientMatchStr is a String representation of ChangelogLenientMatch
ChangelogLenientMatchStr = "ChangelogLenientMatch"
// GitHubMatchStr :
// GitHubMatchStr is a String representation of GitHubMatch
GitHubMatchStr = "GitHubMatch"
// WpScanMatchStr :
// WpScanMatchStr is a String representation of WordPress VulnDB scanning
WpScanMatchStr = "WpScanMatch"
// FailedToGetChangelog :
// FailedToGetChangelog is a String representation of FailedToGetChangelog
FailedToGetChangelog = "FailedToGetChangelog"
// FailedToFindVersionInChangelog :
// FailedToFindVersionInChangelog is a String representation of FailedToFindVersionInChangelog
FailedToFindVersionInChangelog = "FailedToFindVersionInChangelog"
)
var (
// CpeNameMatch is a ranking how confident the CVE-ID was detected correctly
CpeNameMatch = Confidence{100, CpeNameMatchStr, 1}
// YumUpdateSecurityMatch is a ranking how confident the CVE-ID was detected correctly
YumUpdateSecurityMatch = Confidence{100, YumUpdateSecurityMatchStr, 2}
// PkgAuditMatch is a ranking how confident the CVE-ID was detected correctly
PkgAuditMatch = Confidence{100, PkgAuditMatchStr, 2}
@@ -921,33 +867,18 @@ var (
// DebianSecurityTrackerMatch ranking how confident the CVE-ID was detected correctly
DebianSecurityTrackerMatch = Confidence{100, DebianSecurityTrackerMatchStr, 0}
// UbuntuAPIMatch ranking how confident the CVE-ID was detected correctly
UbuntuAPIMatch = Confidence{100, UbuntuAPIMatchStr, 0}
// TrivyMatch ranking how confident the CVE-ID was detected correctly
TrivyMatch = Confidence{100, TrivyMatchStr, 0}
// ChangelogExactMatch is a ranking how confident the CVE-ID was detected correctly
ChangelogExactMatch = Confidence{95, ChangelogExactMatchStr, 3}
// ChangelogRoughMatch is a ranking how confident the CVE-ID was detected correctly
ChangelogRoughMatch = Confidence{50, ChangelogRoughMatchStr, 4}
// ChangelogLenientMatch is a ranking how confident the CVE-ID was detected correctly
ChangelogLenientMatch = Confidence{50, ChangelogLenientMatchStr, 4}
// GitHubMatch is a ranking how confident the CVE-ID was detected correctly
GitHubMatch = Confidence{100, GitHubMatchStr, 2}
GitHubMatch = Confidence{97, GitHubMatchStr, 2}
// WpScanMatch is a ranking how confident the CVE-ID was detected correctly
WpScanMatch = Confidence{100, WpScanMatchStr, 0}
// NvdExactVersionMatch is a ranking how confident the CVE-ID was detected correctly
NvdExactVersionMatch = Confidence{100, NvdExactVersionMatchStr, 1}
// NvdRoughVersionMatch NvdExactVersionMatch is a ranking how confident the CVE-ID was detected correctly
NvdRoughVersionMatch = Confidence{80, NvdRoughVersionMatchStr, 1}
// NvdVendorProductMatch is a ranking how confident the CVE-ID was detected correctly
NvdVendorProductMatch = Confidence{10, NvdVendorProductMatchStr, 9}
// JvnVendorProductMatch is a ranking how confident the CVE-ID was detected correctly
JvnVendorProductMatch = Confidence{10, JvnVendorProductMatchStr, 10}
)

View File

@@ -21,19 +21,19 @@ func TestTitles(t *testing.T) {
lang: "ja",
cont: VulnInfo{
CveContents: CveContents{
Jvn: []CveContent{{
Jvn: {
Type: Jvn,
Title: "Title1",
}},
RedHat: []CveContent{{
},
RedHat: {
Type: RedHat,
Summary: "Summary RedHat",
}},
Nvd: []CveContent{{
},
Nvd: {
Type: Nvd,
Summary: "Summary NVD",
// Severity is NOT included in NVD
}},
},
},
},
},
@@ -58,19 +58,19 @@ func TestTitles(t *testing.T) {
lang: "en",
cont: VulnInfo{
CveContents: CveContents{
Jvn: []CveContent{{
Jvn: {
Type: Jvn,
Title: "Title1",
}},
RedHat: []CveContent{{
},
RedHat: {
Type: RedHat,
Summary: "Summary RedHat",
}},
Nvd: []CveContent{{
},
Nvd: {
Type: Nvd,
Summary: "Summary NVD",
// Severity is NOT included in NVD
}},
},
},
},
},
@@ -122,20 +122,20 @@ func TestSummaries(t *testing.T) {
lang: "ja",
cont: VulnInfo{
CveContents: CveContents{
Jvn: []CveContent{{
Jvn: {
Type: Jvn,
Title: "Title JVN",
Summary: "Summary JVN",
}},
RedHat: []CveContent{{
},
RedHat: {
Type: RedHat,
Summary: "Summary RedHat",
}},
Nvd: []CveContent{{
},
Nvd: {
Type: Nvd,
Summary: "Summary NVD",
// Severity is NOT included in NVD
}},
},
},
},
},
@@ -160,20 +160,20 @@ func TestSummaries(t *testing.T) {
lang: "en",
cont: VulnInfo{
CveContents: CveContents{
Jvn: []CveContent{{
Jvn: {
Type: Jvn,
Title: "Title JVN",
Summary: "Summary JVN",
}},
RedHat: []CveContent{{
},
RedHat: {
Type: RedHat,
Summary: "Summary RedHat",
}},
Nvd: []CveContent{{
},
Nvd: {
Type: Nvd,
Summary: "Summary NVD",
// Severity is NOT included in NVD
}},
},
},
},
},
@@ -220,32 +220,32 @@ func TestCountGroupBySeverity(t *testing.T) {
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
CveContents: CveContents{
Nvd: []CveContent{{
Nvd: {
Type: Nvd,
Cvss3Score: 6.0,
}},
RedHat: []CveContent{{
},
RedHat: {
Type: RedHat,
Cvss3Score: 7.0,
}},
},
},
},
"CVE-2017-0003": {
CveID: "CVE-2017-0003",
CveContents: CveContents{
Nvd: []CveContent{{
Nvd: {
Type: Nvd,
Cvss3Score: 2.0,
}},
},
},
},
"CVE-2017-0004": {
CveID: "CVE-2017-0004",
CveContents: CveContents{
Nvd: []CveContent{{
Nvd: {
Type: Nvd,
Cvss3Score: 5.0,
}},
},
},
},
"CVE-2017-0005": {
@@ -254,10 +254,10 @@ func TestCountGroupBySeverity(t *testing.T) {
"CVE-2017-0006": {
CveID: "CVE-2017-0005",
CveContents: CveContents{
Nvd: []CveContent{{
Nvd: {
Type: Nvd,
Cvss3Score: 10.0,
}},
},
},
},
},
@@ -274,32 +274,32 @@ func TestCountGroupBySeverity(t *testing.T) {
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
CveContents: CveContents{
Nvd: []CveContent{{
Nvd: {
Type: Nvd,
Cvss2Score: 1.0,
}},
RedHat: []CveContent{{
},
RedHat: {
Type: RedHat,
Cvss3Score: 7.0,
}},
},
},
},
"CVE-2017-0003": {
CveID: "CVE-2017-0003",
CveContents: CveContents{
Nvd: []CveContent{{
Nvd: {
Type: Nvd,
Cvss2Score: 2.0,
}},
},
},
},
"CVE-2017-0004": {
CveID: "CVE-2017-0004",
CveContents: CveContents{
Nvd: []CveContent{{
Nvd: {
Type: Nvd,
Cvss2Score: 5.0,
}},
},
},
},
"CVE-2017-0005": {
@@ -308,10 +308,10 @@ func TestCountGroupBySeverity(t *testing.T) {
"CVE-2017-0006": {
CveID: "CVE-2017-0005",
CveContents: CveContents{
Nvd: []CveContent{{
Nvd: {
Type: Nvd,
Cvss2Score: 10.0,
}},
},
},
},
},
@@ -346,27 +346,27 @@ func TestToSortedSlice(t *testing.T) {
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
CveContents: CveContents{
Nvd: []CveContent{{
Nvd: {
Type: Nvd,
Cvss2Score: 6.0,
}},
RedHat: []CveContent{{
},
RedHat: {
Type: RedHat,
Cvss3Score: 7.0,
}},
},
},
},
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
CveContents: CveContents{
Nvd: []CveContent{{
Nvd: {
Type: Nvd,
Cvss2Score: 7.0,
}},
RedHat: []CveContent{{
},
RedHat: {
Type: RedHat,
Cvss3Score: 8.0,
}},
},
},
},
},
@@ -374,27 +374,27 @@ func TestToSortedSlice(t *testing.T) {
{
CveID: "CVE-2017-0001",
CveContents: CveContents{
Nvd: []CveContent{{
Nvd: {
Type: Nvd,
Cvss2Score: 7.0,
}},
RedHat: []CveContent{{
},
RedHat: {
Type: RedHat,
Cvss3Score: 8.0,
}},
},
},
},
{
CveID: "CVE-2017-0002",
CveContents: CveContents{
Nvd: []CveContent{{
Nvd: {
Type: Nvd,
Cvss2Score: 6.0,
}},
RedHat: []CveContent{{
},
RedHat: {
Type: RedHat,
Cvss3Score: 7.0,
}},
},
},
},
},
@@ -405,23 +405,23 @@ func TestToSortedSlice(t *testing.T) {
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
CveContents: CveContents{
Nvd: []CveContent{{
Nvd: {
Type: Nvd,
Cvss2Score: 6.0,
}},
RedHat: []CveContent{{
},
RedHat: {
Type: RedHat,
Cvss3Score: 7.0,
}},
},
},
},
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
CveContents: CveContents{
RedHat: []CveContent{{
RedHat: {
Type: RedHat,
Cvss3Score: 7.0,
}},
},
},
},
},
@@ -429,23 +429,23 @@ func TestToSortedSlice(t *testing.T) {
{
CveID: "CVE-2017-0001",
CveContents: CveContents{
RedHat: []CveContent{{
RedHat: {
Type: RedHat,
Cvss3Score: 7.0,
}},
},
},
},
{
CveID: "CVE-2017-0002",
CveContents: CveContents{
Nvd: []CveContent{{
Nvd: {
Type: Nvd,
Cvss2Score: 6.0,
}},
RedHat: []CveContent{{
},
RedHat: {
Type: RedHat,
Cvss3Score: 7.0,
}},
},
},
},
},
@@ -456,19 +456,19 @@ func TestToSortedSlice(t *testing.T) {
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
CveContents: CveContents{
Ubuntu: []CveContent{{
Ubuntu: {
Type: Ubuntu,
Cvss3Severity: "High",
}},
},
},
},
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
CveContents: CveContents{
Ubuntu: []CveContent{{
Ubuntu: {
Type: Ubuntu,
Cvss3Severity: "Low",
}},
},
},
},
},
@@ -476,19 +476,19 @@ func TestToSortedSlice(t *testing.T) {
{
CveID: "CVE-2017-0002",
CveContents: CveContents{
Ubuntu: []CveContent{{
Ubuntu: {
Type: Ubuntu,
Cvss3Severity: "High",
}},
},
},
},
{
CveID: "CVE-2017-0001",
CveContents: CveContents{
Ubuntu: []CveContent{{
Ubuntu: {
Type: Ubuntu,
Cvss3Severity: "Low",
}},
},
},
},
},
@@ -510,31 +510,31 @@ func TestCvss2Scores(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
Jvn: []CveContent{{
Jvn: {
Type: Jvn,
Cvss2Severity: "HIGH",
Cvss2Score: 8.2,
Cvss2Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
}},
RedHat: []CveContent{{
},
RedHat: {
Type: RedHat,
Cvss2Severity: "HIGH",
Cvss2Score: 8.0,
Cvss2Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
}},
Nvd: []CveContent{{
},
Nvd: {
Type: Nvd,
Cvss2Score: 8.1,
Cvss2Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
Cvss2Severity: "HIGH",
}},
},
//v3
RedHatAPI: []CveContent{{
RedHatAPI: {
Type: RedHatAPI,
Cvss3Score: 8.1,
Cvss3Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
Cvss3Severity: "HIGH",
}},
},
},
},
out: []CveContentCvss{
@@ -590,24 +590,24 @@ func TestMaxCvss2Scores(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
Jvn: []CveContent{{
Jvn: {
Type: Jvn,
Cvss2Severity: "HIGH",
Cvss2Score: 8.2,
Cvss2Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
}},
RedHat: []CveContent{{
},
RedHat: {
Type: RedHat,
Cvss2Severity: "HIGH",
Cvss2Score: 8.0,
Cvss2Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
}},
Nvd: []CveContent{{
},
Nvd: {
Type: Nvd,
Cvss2Score: 8.1,
Cvss2Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
// Severity is NOT included in NVD
}},
},
},
},
out: CveContentCvss{
@@ -650,18 +650,18 @@ func TestCvss3Scores(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
RedHat: []CveContent{{
RedHat: {
Type: RedHat,
Cvss3Severity: "HIGH",
Cvss3Score: 8.0,
Cvss3Vector: "AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
}},
Nvd: []CveContent{{
},
Nvd: {
Type: Nvd,
Cvss2Score: 8.1,
Cvss2Vector: "AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
Cvss2Severity: "HIGH",
}},
},
},
},
out: []CveContentCvss{
@@ -680,10 +680,10 @@ func TestCvss3Scores(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
Ubuntu: []CveContent{{
Ubuntu: {
Type: Ubuntu,
Cvss3Severity: "HIGH",
}},
},
},
},
out: []CveContentCvss{
@@ -720,12 +720,12 @@ func TestMaxCvss3Scores(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
RedHat: []CveContent{{
RedHat: {
Type: RedHat,
Cvss3Severity: "HIGH",
Cvss3Score: 8.0,
Cvss3Vector: "AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
}},
},
},
},
out: CveContentCvss{
@@ -768,14 +768,14 @@ func TestMaxCvssScores(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
Nvd: []CveContent{{
Nvd: {
Type: Nvd,
Cvss3Score: 7.0,
}},
RedHat: []CveContent{{
},
RedHat: {
Type: RedHat,
Cvss2Score: 8.0,
}},
},
},
},
out: CveContentCvss{
@@ -789,10 +789,10 @@ func TestMaxCvssScores(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
RedHat: []CveContent{{
RedHat: {
Type: RedHat,
Cvss3Score: 8.0,
}},
},
},
},
out: CveContentCvss{
@@ -807,10 +807,10 @@ func TestMaxCvssScores(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
Ubuntu: []CveContent{{
Ubuntu: {
Type: Ubuntu,
Cvss3Severity: "HIGH",
}},
},
},
},
out: CveContentCvss{
@@ -827,15 +827,15 @@ func TestMaxCvssScores(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
Ubuntu: []CveContent{{
Ubuntu: {
Type: Ubuntu,
Cvss3Severity: "MEDIUM",
}},
Nvd: []CveContent{{
},
Nvd: {
Type: Nvd,
Cvss2Score: 7.0,
Cvss2Severity: "HIGH",
}},
},
},
},
out: CveContentCvss{
@@ -871,15 +871,15 @@ func TestMaxCvssScores(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
Ubuntu: []CveContent{{
Ubuntu: {
Type: Ubuntu,
Cvss3Severity: "MEDIUM",
}},
Nvd: []CveContent{{
},
Nvd: {
Type: Nvd,
Cvss2Score: 4.0,
Cvss2Severity: "MEDIUM",
}},
},
},
DistroAdvisories: []DistroAdvisory{
{
@@ -925,21 +925,21 @@ func TestFormatMaxCvssScore(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
Jvn: []CveContent{{
Jvn: {
Type: Jvn,
Cvss2Severity: "HIGH",
Cvss2Score: 8.3,
}},
RedHat: []CveContent{{
},
RedHat: {
Type: RedHat,
Cvss3Severity: "HIGH",
Cvss3Score: 8.0,
}},
Nvd: []CveContent{{
},
Nvd: {
Type: Nvd,
Cvss2Score: 8.1,
// Severity is NOT included in NVD
}},
},
},
},
out: "8.0 HIGH (redhat)",
@@ -947,22 +947,22 @@ func TestFormatMaxCvssScore(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
Jvn: []CveContent{{
Jvn: {
Type: Jvn,
Cvss2Severity: "HIGH",
Cvss2Score: 8.3,
}},
RedHat: []CveContent{{
},
RedHat: {
Type: RedHat,
Cvss2Severity: "HIGH",
Cvss2Score: 8.0,
Cvss3Severity: "HIGH",
Cvss3Score: 9.9,
}},
Nvd: []CveContent{{
},
Nvd: {
Type: Nvd,
Cvss2Score: 8.1,
}},
},
},
},
out: "9.9 HIGH (redhat)",
@@ -1037,20 +1037,20 @@ func TestAppendIfMissing(t *testing.T) {
}{
{
in: Confidences{
NvdExactVersionMatch,
CpeNameMatch,
},
arg: NvdExactVersionMatch,
arg: CpeNameMatch,
out: Confidences{
NvdExactVersionMatch,
CpeNameMatch,
},
},
{
in: Confidences{
NvdExactVersionMatch,
CpeNameMatch,
},
arg: ChangelogExactMatch,
out: Confidences{
NvdExactVersionMatch,
CpeNameMatch,
ChangelogExactMatch,
},
},
@@ -1071,21 +1071,21 @@ func TestSortByConfident(t *testing.T) {
{
in: Confidences{
OvalMatch,
NvdExactVersionMatch,
CpeNameMatch,
},
out: Confidences{
OvalMatch,
NvdExactVersionMatch,
CpeNameMatch,
},
},
{
in: Confidences{
NvdExactVersionMatch,
CpeNameMatch,
OvalMatch,
},
out: Confidences{
OvalMatch,
NvdExactVersionMatch,
CpeNameMatch,
},
},
}
@@ -1610,78 +1610,3 @@ func TestVulnInfos_FilterIgnorePkgs(t *testing.T) {
})
}
}
func TestVulnInfos_FilterByConfidenceOver(t *testing.T) {
type args struct {
over int
}
tests := []struct {
name string
v VulnInfos
args args
want VulnInfos
}{
{
name: "over 0",
v: map[string]VulnInfo{
"CVE-2021-1111": {
CveID: "CVE-2021-1111",
Confidences: Confidences{JvnVendorProductMatch},
},
},
args: args{
over: 0,
},
want: map[string]VulnInfo{
"CVE-2021-1111": {
CveID: "CVE-2021-1111",
Confidences: Confidences{JvnVendorProductMatch},
},
},
},
{
name: "over 20",
v: map[string]VulnInfo{
"CVE-2021-1111": {
CveID: "CVE-2021-1111",
Confidences: Confidences{JvnVendorProductMatch},
},
},
args: args{
over: 20,
},
want: map[string]VulnInfo{},
},
{
name: "over 100",
v: map[string]VulnInfo{
"CVE-2021-1111": {
CveID: "CVE-2021-1111",
Confidences: Confidences{
NvdExactVersionMatch,
JvnVendorProductMatch,
},
},
},
args: args{
over: 20,
},
want: map[string]VulnInfo{
"CVE-2021-1111": {
CveID: "CVE-2021-1111",
Confidences: Confidences{
NvdExactVersionMatch,
JvnVendorProductMatch,
},
},
},
},
}
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) {
t.Errorf("VulnInfos.FilterByConfidenceOver() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package oval
@@ -54,8 +53,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 +64,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

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package oval
@@ -12,7 +11,7 @@ import (
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
ovalmodels "github.com/vulsio/goval-dictionary/models"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
)
// DebianBase is the base struct of Debian and Ubuntu
@@ -20,75 +19,73 @@ type DebianBase struct {
Base
}
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
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),
}
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 {
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)
} else {
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{}
}
logging.Log.Debugf("%s is also detected by OVAL",
defPacks.def.Debian.CveID)
cveContents = models.CveContents{}
}
if r.Family != constant.Raspbian {
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,
} else {
if len(vinfo.Confidences) == 0 {
vinfo.Confidences.AppendIfMissing(models.OvalMatch)
}
}
cveContents[ctype] = ovalContent
vinfo.CveContents = cveContents
}
// 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,
}
// 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,
}
}
}
}
vinfo.AffectedPackages = collectBinpkgFixstat.toPackStatuses()
vinfo.AffectedPackages.Sort()
r.ScannedCves[cve.CveID] = vinfo
}
vinfo.AffectedPackages = defPacks.toPackStatuses()
vinfo.AffectedPackages.Sort()
r.ScannedCves[defPacks.def.Debian.CveID] = vinfo
}
func (o DebianBase) convertToModel(cveID string, def *ovalmodels.Definition) *models.CveContent {
refs := make([]models.Reference, 0, len(def.References))
func (o DebianBase) convertToModel(def *ovalmodels.Definition) *models.CveContent {
refs := []models.Reference{}
for _, r := range def.References {
refs = append(refs, models.Reference{
Link: r.RefURL,
@@ -97,23 +94,14 @@ func (o DebianBase) convertToModel(cveID string, def *ovalmodels.Definition) *mo
})
}
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 &models.CveContent{
CveID: def.Debian.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
@@ -154,8 +142,16 @@ func (o Debian) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
var relatedDefs ovalResult
if o.Cnf.IsFetchViaHTTP() {
if relatedDefs, err = getDefsByPackNameViaHTTP(r, o.Cnf.GetURL()); err != nil {
return 0, err
if r.Family != constant.Raspbian {
if relatedDefs, err = getDefsByPackNameViaHTTP(r, o.Cnf.GetURL()); err != nil {
return 0, err
}
} else {
// OVAL does not support Package for Raspbian, so skip it.
result := r.RemoveRaspbianPackFromResult()
if relatedDefs, err = getDefsByPackNameViaHTTP(&result, o.Cnf.GetURL()); err != nil {
return 0, err
}
}
} else {
driver, err := newOvalDB(o.Cnf, r.Family)
@@ -168,8 +164,16 @@ func (o Debian) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
}
}()
if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, r); err != nil {
return 0, err
if r.Family != constant.Raspbian {
if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, r); err != nil {
return 0, err
}
} else {
// OVAL does not support Package for Raspbian, so skip it.
result := r.RemoveRaspbianPackFromResult()
if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, &result); err != nil {
return 0, err
}
}
}
@@ -193,11 +197,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 i, cont := range conts {
cont.SourceLink = "https://security-tracker.debian.org/tracker/" + cont.CveID
vuln.CveContents[models.Debian][i] = cont
}
if cont, ok := vuln.CveContents[models.Debian]; ok {
cont.SourceLink = "https://security-tracker.debian.org/tracker/" + cont.CveID
vuln.CveContents[models.Debian] = cont
}
}
return len(relatedDefs.entries), nil
@@ -356,47 +358,6 @@ func (o Ubuntu) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
"linux",
}
return o.fillWithOval(r, kernelNamesInOval)
case "21":
kernelNamesInOval := []string{
"linux-aws",
"linux-base-sgx",
"linux-base",
"linux-cloud-tools-common",
"linux-cloud-tools-generic",
"linux-cloud-tools-lowlatency",
"linux-cloud-tools-virtual",
"linux-gcp",
"linux-generic",
"linux-gke",
"linux-headers-aws",
"linux-headers-gcp",
"linux-headers-gke",
"linux-headers-oracle",
"linux-image-aws",
"linux-image-extra-virtual",
"linux-image-gcp",
"linux-image-generic",
"linux-image-gke",
"linux-image-lowlatency",
"linux-image-oracle",
"linux-image-virtual",
"linux-lowlatency",
"linux-modules-extra-aws",
"linux-modules-extra-gcp",
"linux-modules-extra-gke",
"linux-oracle",
"linux-tools-aws",
"linux-tools-common",
"linux-tools-gcp",
"linux-tools-generic",
"linux-tools-gke",
"linux-tools-host",
"linux-tools-lowlatency",
"linux-tools-oracle",
"linux-tools-virtual",
"linux-virtual",
}
return o.fillWithOval(r, kernelNamesInOval)
}
return 0, fmt.Errorf("Ubuntu %s is not support for now", r.Release)
}
@@ -512,11 +473,9 @@ func (o Ubuntu) fillWithOval(r *models.ScanResult, kernelNamesInOval []string) (
}
for _, vuln := range r.ScannedCves {
if conts, ok := vuln.CveContents[models.Ubuntu]; ok {
for i, cont := range conts {
cont.SourceLink = "http://people.ubuntu.com/~ubuntu-security/cve/" + cont.CveID
vuln.CveContents[models.Ubuntu][i] = cont
}
if cont, ok := vuln.CveContents[models.Ubuntu]; ok {
cont.SourceLink = "http://people.ubuntu.com/~ubuntu-security/cve/" + cont.CveID
vuln.CveContents[models.Ubuntu] = cont
}
}
return len(relatedDefs.entries), nil

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package oval
@@ -8,7 +7,7 @@ import (
"testing"
"github.com/future-architect/vuls/models"
ovalmodels "github.com/vulsio/goval-dictionary/models"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
)
func TestPackNamesOfUpdateDebian(t *testing.T) {
@@ -30,8 +29,8 @@ func TestPackNamesOfUpdateDebian(t *testing.T) {
},
defPacks: defPacks{
def: ovalmodels.Definition{
Advisory: ovalmodels.Advisory{
Cves: []ovalmodels.Cve{{CveID: "CVE-2000-1000"}},
Debian: ovalmodels.Debian{
CveID: "CVE-2000-1000",
},
},
binpkgFixstat: map[string]fixStat{
@@ -53,68 +52,15 @@ 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)
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)
}
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)
}
}
}

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package oval
@@ -11,8 +10,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"
)
@@ -84,10 +83,7 @@ func (b Base) CheckIfOvalFresh(osFamily, release string) (ok bool, err error) {
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
}()
lastModified, err = driver.GetLastModified(ovalFamily, release)
if err != nil {
return false, xerrors.Errorf("Failed to GetLastModified: %w", err)
}
lastModified = driver.GetLastModified(ovalFamily, release)
} else {
url, _ := util.URLPathJoin(config.Conf.OvalDict.URL, "lastmodified", ovalFamily, release)
resp, body, errs := gorequest.New().Timeout(10 * time.Second).Get(url).End()
@@ -103,7 +99,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/vulsio/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/kotakanbe/goval-dictionary#usage",
osFamily, release, lastModified)
return false, nil
}

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package oval
@@ -12,10 +11,10 @@ import (
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
ovalmodels "github.com/vulsio/goval-dictionary/models"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
)
// RedHatBase is the base struct for RedHat, CentOS, Alma and Rocky
// RedHatBase is the base struct for RedHat and CentOS
type RedHatBase struct {
Base
}
@@ -51,18 +50,14 @@ func (o RedHatBase) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
for _, vuln := range r.ScannedCves {
switch models.NewCveContentType(o.family) {
case models.RedHat:
if conts, ok := vuln.CveContents[models.RedHat]; ok {
for i, cont := range conts {
cont.SourceLink = "https://access.redhat.com/security/cve/" + cont.CveID
vuln.CveContents[models.RedHat][i] = cont
}
if cont, ok := vuln.CveContents[models.RedHat]; ok {
cont.SourceLink = "https://access.redhat.com/security/cve/" + cont.CveID
vuln.CveContents[models.RedHat] = cont
}
case models.Oracle:
if conts, ok := vuln.CveContents[models.Oracle]; ok {
for i, cont := range conts {
cont.SourceLink = fmt.Sprintf("https://linux.oracle.com/cve/%s.html", cont.CveID)
vuln.CveContents[models.Oracle][i] = cont
}
if cont, ok := vuln.CveContents[models.Oracle]; ok {
cont.SourceLink = fmt.Sprintf("https://linux.oracle.com/cve/%s.html", cont.CveID)
vuln.CveContents[models.Oracle] = cont
}
}
}
@@ -102,66 +97,55 @@ var kernelRelatedPackNames = map[string]bool{
"python-perf": true,
}
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
}
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)
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[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)
} else {
logging.Log.Debugf("%s OVAL will be overwritten. DefID: %s", cve.CveID, defpacks.def.DefinitionID)
}
if v, ok := vinfo.CveContents[ctype]; ok {
if v.LastModified.After(ovalContent.LastModified) {
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)
}
} 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[ovalContent.Type] = []models.CveContent{*ovalContent}
cveContents[ctype] = ovalContent
vinfo.CveContents = cveContents
}
vinfo.DistroAdvisories.AppendIfMissing(
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
}
o.convertToDistroAdvisory(&defPacks.def))
// uniq(vinfo.PackNames + defPacks.actuallyAffectedPackNames)
for _, pack := range vinfo.AffectedPackages {
if stat, ok := collectBinpkgFixstat.binpkgFixstat[pack.Name]; !ok {
collectBinpkgFixstat.binpkgFixstat[pack.Name] = fixStat{
if stat, ok := defPacks.binpkgFixstat[pack.Name]; !ok {
defPacks.binpkgFixstat[pack.Name] = fixStat{
notFixedYet: pack.NotFixedYet,
fixedIn: pack.FixedIn,
}
} else if stat.notFixedYet {
collectBinpkgFixstat.binpkgFixstat[pack.Name] = fixStat{
defPacks.binpkgFixstat[pack.Name] = fixStat{
notFixedYet: true,
fixedIn: pack.FixedIn,
}
}
}
vinfo.AffectedPackages = collectBinpkgFixstat.toPackStatuses()
vinfo.AffectedPackages = defPacks.toPackStatuses()
vinfo.AffectedPackages.Sort()
r.ScannedCves[cve.CveID] = vinfo
}
@@ -171,7 +155,7 @@ func (o RedHatBase) update(r *models.ScanResult, defpacks defPacks) (nCVEs int)
func (o RedHatBase) convertToDistroAdvisory(def *ovalmodels.Definition) *models.DistroAdvisory {
advisoryID := def.Title
switch o.family {
case constant.RedHat, constant.CentOS, constant.Alma, constant.Rocky, constant.Oracle:
case constant.RedHat, constant.CentOS, constant.Oracle:
if def.Title != "" {
ss := strings.Fields(def.Title)
advisoryID = strings.TrimSuffix(ss[0], ":")
@@ -187,19 +171,18 @@ 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)
@@ -339,39 +322,3 @@ func NewAmazon(cnf config.VulnDictInterface) Amazon {
},
}
}
// Alma is the interface for RedhatBase OVAL
type Alma struct {
// Base
RedHatBase
}
// NewAlma creates OVAL client for Alma Linux
func NewAlma(cnf config.VulnDictInterface) Alma {
return Alma{
RedHatBase{
Base{
family: constant.Alma,
Cnf: cnf,
},
},
}
}
// Rocky is the interface for RedhatBase OVAL
type Rocky struct {
// Base
RedHatBase
}
// NewRocky creates OVAL client for Rocky Linux
func NewRocky(cnf config.VulnDictInterface) Rocky {
return Rocky{
RedHatBase{
Base{
family: constant.Rocky,
Cnf: cnf,
},
},
}
}

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package oval
@@ -8,7 +7,7 @@ import (
"testing"
"github.com/future-architect/vuls/models"
ovalmodels "github.com/vulsio/goval-dictionary/models"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
)
func TestParseCvss2(t *testing.T) {
@@ -129,68 +128,15 @@ 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)
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)
}
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)
}
}
}

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package oval
@@ -8,7 +7,7 @@ import (
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
ovalmodels "github.com/vulsio/goval-dictionary/models"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
)
// SUSE is the struct of SUSE Linux
@@ -54,24 +53,22 @@ 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 i, cont := range conts {
cont.SourceLink = "https://security-tracker.debian.org/tracker/" + cont.CveID
vuln.CveContents[models.SUSE][i] = cont
}
if cont, ok := vuln.CveContents[models.SUSE]; ok {
cont.SourceLink = "https://security-tracker.debian.org/tracker/" + cont.CveID
vuln.CveContents[models.SUSE] = 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,33 +76,26 @@ 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] = []models.CveContent{ovalContent}
cveContents[ctype] = 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
}
// uniq(vinfo.PackNames + defPacks.actuallyAffectedPackNames)
for _, pack := range vinfo.AffectedPackages {
collectBinpkgFixstat.binpkgFixstat[pack.Name] = fixStat{
defPacks.binpkgFixstat[pack.Name] = fixStat{
notFixedYet: pack.NotFixedYet,
fixedIn: pack.FixedIn,
}
}
vinfo.AffectedPackages = collectBinpkgFixstat.toPackStatuses()
vinfo.AffectedPackages = defPacks.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

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package oval
@@ -20,9 +19,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"
)
@@ -307,7 +306,7 @@ func isOvalDefAffected(def ovalmodels.Definition, req request, family string, ru
switch family {
case constant.Oracle, constant.Amazon:
if ovalPack.Arch == "" {
logging.Log.Infof("Arch is needed to detect Vulns for Amazon and Oracle Linux, but empty. You need refresh OVAL maybe. oval: %#v, defID: %s", ovalPack, def.DefinitionID)
logging.Log.Infof("Arch is needed to detect Vulns for Amazon and Oracle Linux, but empty. You need refresh OVAL maybe. oval: %s, defID: %s", ovalPack, def.DefinitionID)
continue
}
}
@@ -338,7 +337,7 @@ func isOvalDefAffected(def ovalmodels.Definition, req request, family string, ru
if running.Release != "" {
switch family {
case constant.RedHat, constant.CentOS, constant.Alma, constant.Rocky, constant.Oracle:
case constant.RedHat, constant.CentOS, constant.Oracle:
// For kernel related packages, ignore OVAL information with different major versions
if _, ok := kernelRelatedPackNames[ovalPack.Name]; ok {
if util.Major(ovalPack.Version) != util.Major(running.Release) {
@@ -378,7 +377,7 @@ func isOvalDefAffected(def ovalmodels.Definition, req request, family string, ru
return true, false, ovalPack.Version, nil
}
// But CentOS/Alma/Rocky can't judge whether fixed or unfixed.
// But CentOS can't judge whether fixed or unfixed.
// Because fixed state in RHEL OVAL is different.
// So, it have to be judged version comparison.
@@ -436,11 +435,9 @@ func lessThan(family, newVer string, packInOVAL ovalmodels.Package) (bool, error
return vera.LessThan(verb), nil
case constant.RedHat,
constant.CentOS,
constant.Alma,
constant.Rocky:
vera := rpmver.NewVersion(rhelDownStreamOSVersionToRHEL(newVer))
verb := rpmver.NewVersion(rhelDownStreamOSVersionToRHEL(packInOVAL.Version))
constant.CentOS:
vera := rpmver.NewVersion(centOSVersionToRHEL(newVer))
verb := rpmver.NewVersion(centOSVersionToRHEL(packInOVAL.Version))
return vera.LessThan(verb), nil
default:
@@ -448,10 +445,10 @@ func lessThan(family, newVer string, packInOVAL ovalmodels.Package) (bool, error
}
}
var rhelDownStreamOSVerPattern = regexp.MustCompile(`\.[es]l(\d+)(?:_\d+)?(?:\.(centos|rocky|alma))?`)
var centosVerPattern = regexp.MustCompile(`\.[es]l(\d+)(?:_\d+)?(?:\.centos)?`)
func rhelDownStreamOSVersionToRHEL(ver string) string {
return rhelDownStreamOSVerPattern.ReplaceAllString(ver, ".el$1")
func centOSVersionToRHEL(ver string) string {
return centosVerPattern.ReplaceAllString(ver, ".el$1")
}
// NewOVALClient returns a client for OVAL database
@@ -464,11 +461,8 @@ func NewOVALClient(family string, cnf config.GovalDictConf) (Client, error) {
case constant.RedHat:
return NewRedhat(&cnf), nil
case constant.CentOS:
//use RedHat's OVAL
return NewCentOS(&cnf), nil
case constant.Alma:
return NewAlma(&cnf), nil
case constant.Rocky:
return NewRocky(&cnf), nil
case constant.Oracle:
return NewOracle(&cnf), nil
case constant.SUSEEnterpriseServer:
@@ -491,14 +485,17 @@ func NewOVALClient(family string, cnf config.GovalDictConf) (Client, error) {
}
// GetFamilyInOval returns the OS family name in OVAL
// For example, CentOS/Alma/Rocky uses Red Hat's OVAL, so return 'redhat'
// For example, CentOS uses Red Hat's OVAL, so return 'redhat'
func GetFamilyInOval(familyInScanResult string) (string, error) {
switch familyInScanResult {
case constant.Debian, constant.Raspbian:
return constant.Debian, nil
case constant.Ubuntu:
return constant.Ubuntu, nil
case constant.RedHat, constant.CentOS, constant.Alma, constant.Rocky:
case constant.RedHat:
return constant.RedHat, nil
case constant.CentOS:
//use RedHat's OVAL
return constant.RedHat, nil
case constant.Oracle:
return constant.Oracle, nil

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package oval
@@ -10,7 +9,7 @@ import (
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/models"
ovalmodels "github.com/vulsio/goval-dictionary/models"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
)
func TestUpsert(t *testing.T) {
@@ -1079,472 +1078,6 @@ func TestIsOvalDefAffected(t *testing.T) {
notFixedYet: false,
fixedIn: "3.1.0",
},
// Rocky Linux
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.el6.rocky.7",
newVersionRelease: "",
},
},
affected: true,
notFixedYet: false,
fixedIn: "0:1.2.3-45.el6_7.8",
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.el6.rocky.8",
},
},
affected: false,
notFixedYet: false,
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.el6.rocky.9",
},
},
affected: false,
notFixedYet: false,
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.el6.rocky.6",
newVersionRelease: "0:1.2.3-45.el6.rocky.7",
},
},
affected: true,
notFixedYet: true,
fixedIn: "0:1.2.3-45.el6_7.8",
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.el6.rocky.6",
newVersionRelease: "0:1.2.3-45.el6.rocky.8",
},
},
affected: true,
notFixedYet: false,
fixedIn: "0:1.2.3-45.el6_7.8",
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.el6.rocky.6",
newVersionRelease: "0:1.2.3-45.el6.rocky.9",
},
},
affected: true,
notFixedYet: false,
fixedIn: "0:1.2.3-45.el6_7.8",
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.el6.8",
},
},
affected: false,
notFixedYet: false,
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.el6_7.8",
},
},
affected: false,
notFixedYet: false,
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.sl6.7",
},
},
affected: true,
notFixedYet: false,
fixedIn: "0:1.2.3-45.el6_7.8",
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.sl6.8",
},
},
affected: false,
notFixedYet: false,
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.sl6.9",
},
},
affected: false,
notFixedYet: false,
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.sl6.6",
newVersionRelease: "0:1.2.3-45.sl6.7",
},
},
affected: true,
notFixedYet: true,
fixedIn: "0:1.2.3-45.el6_7.8",
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.sl6.6",
newVersionRelease: "0:1.2.3-45.sl6.8",
},
},
affected: true,
notFixedYet: false,
fixedIn: "0:1.2.3-45.el6_7.8",
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.sl6.6",
newVersionRelease: "0:1.2.3-45.sl6.9",
},
},
affected: true,
notFixedYet: false,
fixedIn: "0:1.2.3-45.el6_7.8",
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.el6.8",
},
},
affected: false,
notFixedYet: false,
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.el6_7.8",
},
},
affected: false,
notFixedYet: false,
},
// For kernel related packages, ignore OVAL with different major versions
{
in: in{
family: constant.Rocky,
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "kernel",
Version: "4.1.0",
NotFixedYet: false,
},
},
},
req: request{
packName: "kernel",
versionRelease: "3.0.0",
newVersionRelease: "3.2.0",
},
kernel: models.Kernel{
Release: "3.0.0",
},
},
affected: false,
notFixedYet: false,
},
{
in: in{
family: constant.Rocky,
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "kernel",
Version: "3.1.0",
NotFixedYet: false,
},
},
},
req: request{
packName: "kernel",
versionRelease: "3.0.0",
newVersionRelease: "3.2.0",
},
kernel: models.Kernel{
Release: "3.0.0",
},
},
affected: true,
notFixedYet: false,
fixedIn: "3.1.0",
},
// dnf module
{
in: in{
@@ -1793,7 +1326,7 @@ func TestIsOvalDefAffected(t *testing.T) {
}
}
func Test_rhelDownStreamOSVersionToRHEL(t *testing.T) {
func Test_centOSVersionToRHEL(t *testing.T) {
type args struct {
ver string
}
@@ -1809,13 +1342,6 @@ func Test_rhelDownStreamOSVersionToRHEL(t *testing.T) {
},
want: "grub2-tools-2.02-0.80.el7.x86_64",
},
{
name: "remove rocky.",
args: args{
ver: "platform-python-3.6.8-37.el8.rocky.x86_64",
},
want: "platform-python-3.6.8-37.el8.x86_64",
},
{
name: "noop",
args: args{
@@ -1833,8 +1359,8 @@ func Test_rhelDownStreamOSVersionToRHEL(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := rhelDownStreamOSVersionToRHEL(tt.args.ver); got != tt.want {
t.Errorf("rhelDownStreamOSVersionToRHEL() = %v, want %v", got, tt.want)
if got := centOSVersionToRHEL(tt.args.ver); got != tt.want {
t.Errorf("centOSVersionToRHEL() = %v, want %v", got, tt.want)
}
})
}

View File

@@ -1,102 +0,0 @@
package reporter
import (
"bytes"
"context"
"fmt"
"net/http"
"regexp"
"strings"
"time"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
"golang.org/x/xerrors"
)
// GoogleChatWriter send report to GoogleChat
type GoogleChatWriter struct {
Cnf config.GoogleChatConf
Proxy string
}
func (w GoogleChatWriter) Write(rs ...models.ScanResult) (err error) {
re := regexp.MustCompile(w.Cnf.ServerNameRegexp)
for _, r := range rs {
if re.Match([]byte(r.FormatServerName())) {
continue
}
msgs := []string{fmt.Sprintf("*%s*\n%s\t%s\t%s",
r.ServerInfo(),
r.ScannedCves.FormatCveSummary(),
r.ScannedCves.FormatFixedStatus(r.Packages),
r.FormatUpdatablePkgsSummary())}
for _, vinfo := range r.ScannedCves.ToSortedSlice() {
max := vinfo.MaxCvssScore().Value.Score
exploits := ""
if 0 < len(vinfo.Exploits) || 0 < len(vinfo.Metasploits) {
exploits = "*PoC*"
}
link := ""
if strings.HasPrefix(vinfo.CveID, "CVE-") {
link = fmt.Sprintf("https://nvd.nist.gov/vuln/detail/%s", vinfo.CveID)
} else if strings.HasPrefix(vinfo.CveID, "WPVDBID-") {
link = fmt.Sprintf("https://wpscan.com/vulnerabilities/%s", strings.TrimPrefix(vinfo.CveID, "WPVDBID-"))
}
msgs = append(msgs, fmt.Sprintf(`%s %s %4.1f %5s %s`,
vinfo.CveIDDiffFormat(),
link,
max,
vinfo.AttackVector(),
exploits))
if len(msgs) == 50 {
msgs = append(msgs, "(The rest is omitted.)")
break
}
}
if len(msgs) == 1 && w.Cnf.SkipIfNoCve {
msgs = []string{}
}
if len(msgs) != 0 {
if err = w.postMessage(strings.Join(msgs, "\n")); err != nil {
return err
}
}
}
return nil
}
func (w GoogleChatWriter) postMessage(message string) error {
uri := fmt.Sprintf("%s", w.Cnf.WebHookURL)
payload := `{"text": "` + message + `" }`
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri, bytes.NewBuffer([]byte(payload)))
defer cancel()
if err != nil {
return err
}
req.Header.Add("Content-Type", "application/json; charset=utf-8")
client, err := util.GetHTTPClient(w.Proxy)
if err != nil {
return err
}
resp, err := client.Do(req)
if checkResponse(resp) != nil && err != nil {
return err
}
defer resp.Body.Close()
return nil
}
func (w GoogleChatWriter) checkResponse(r *http.Response) error {
if c := r.StatusCode; 200 <= c && c <= 299 {
return nil
}
return xerrors.Errorf("API call to %s failed: %s", r.Request.URL.String(), r.Status)
}

View File

@@ -269,20 +269,19 @@ func (w SlackWriter) attachmentText(vinfo models.VulnInfo, cweDict map[string]mo
vinfo.CveID)
}
if conts, ok := vinfo.CveContents[cvss.Type]; ok {
for _, cont := range conts {
v := fmt.Sprintf("<%s|%s> %s (<%s|%s>)",
calcURL,
fmt.Sprintf("%3.1f/%s", cvss.Value.Score, cvss.Value.Vector),
cvss.Value.Severity,
cont.SourceLink,
cvss.Type)
vectors = append(vectors, v)
}
if cont, ok := vinfo.CveContents[cvss.Type]; ok {
v := fmt.Sprintf("<%s|%s> %s (<%s|%s>)",
calcURL,
fmt.Sprintf("%3.1f/%s", cvss.Value.Score, cvss.Value.Vector),
cvss.Value.Severity,
cont.SourceLink,
cvss.Type)
vectors = append(vectors, v)
} else {
if 0 < len(vinfo.DistroAdvisories) {
links := []string{}
for _, v := range vinfo.CveContents.PrimarySrcURLs(w.lang, w.osFamily, vinfo.CveID, vinfo.Confidences) {
for _, v := range vinfo.CveContents.PrimarySrcURLs(w.lang, w.osFamily, vinfo.CveID) {
links = append(links, fmt.Sprintf("<%s|%s>", v.Value, v.Type))
}

View File

@@ -70,20 +70,16 @@ func (w SyslogWriter) encodeSyslog(result models.ScanResult) (messages []string)
kvPairs = append(kvPairs, fmt.Sprintf(`cvss_vector_%s_v3="%s"`, cvss.Type, cvss.Value.Vector))
}
if conts, ok := vinfo.CveContents[models.Nvd]; ok {
for _, cont := range conts {
cwes := strings.Join(cont.CweIDs, ",")
kvPairs = append(kvPairs, fmt.Sprintf(`cwe_ids="%s"`, cwes))
if w.Cnf.Verbose {
kvPairs = append(kvPairs, fmt.Sprintf(`source_link="%s"`, cont.SourceLink))
kvPairs = append(kvPairs, fmt.Sprintf(`summary="%s"`, cont.Summary))
}
if content, ok := vinfo.CveContents[models.Nvd]; ok {
cwes := strings.Join(content.CweIDs, ",")
kvPairs = append(kvPairs, fmt.Sprintf(`cwe_ids="%s"`, cwes))
if w.Cnf.Verbose {
kvPairs = append(kvPairs, fmt.Sprintf(`source_link="%s"`, content.SourceLink))
kvPairs = append(kvPairs, fmt.Sprintf(`summary="%s"`, content.Summary))
}
}
if conts, ok := vinfo.CveContents[models.RedHat]; ok {
for _, cont := range conts {
kvPairs = append(kvPairs, fmt.Sprintf(`title="%s"`, cont.Title))
}
if content, ok := vinfo.CveContents[models.RedHat]; ok {
kvPairs = append(kvPairs, fmt.Sprintf(`title="%s"`, content.Title))
}
// message: key1="value1" key2="value2"...

View File

@@ -33,7 +33,7 @@ func TestSyslogWriterEncodeSyslog(t *testing.T) {
models.PackageFixStatus{Name: "pkg4"},
},
CveContents: models.CveContents{
models.Nvd: []models.CveContent{{
models.Nvd: models.CveContent{
Cvss2Score: 5.0,
Cvss2Vector: "AV:L/AC:L/Au:N/C:N/I:N/A:C",
Cvss2Severity: "MEDIUM",
@@ -41,7 +41,7 @@ func TestSyslogWriterEncodeSyslog(t *testing.T) {
Cvss3Score: 9.8,
Cvss3Vector: "AV:L/AC:L/Au:N/C:N/I:N/A:C",
Cvss3Severity: "HIGH",
}},
},
},
},
},
@@ -65,13 +65,13 @@ func TestSyslogWriterEncodeSyslog(t *testing.T) {
models.PackageFixStatus{Name: "pkg5"},
},
CveContents: models.CveContents{
models.RedHat: []models.CveContent{{
models.RedHat: models.CveContent{
Cvss3Score: 5.0,
Cvss3Severity: "Medium",
Cvss3Vector: "AV:L/AC:L/Au:N/C:N/I:N/A:C",
CweIDs: []string{"CWE-284"},
Title: "RHSA-2017:0001: pkg5 security update (Important)",
}},
},
},
},
},

View File

@@ -8,7 +8,6 @@ import (
"io/ioutil"
"os"
"path/filepath"
"reflect"
"regexp"
"sort"
"strings"
@@ -348,7 +347,7 @@ No CVE-IDs are found in updatable packages.
data = append(data, []string{"Mitigation", m.URL})
}
links := vuln.CveContents.PrimarySrcURLs(r.Lang, r.Family, vuln.CveID, vuln.Confidences)
links := vuln.CveContents.PrimarySrcURLs(r.Lang, r.Family, vuln.CveID)
for _, link := range links {
data = append(data, []string{"Primary Src", link.Value})
}
@@ -621,7 +620,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/vulsio/gost
// This logic will be uncomented after integration with gost https://github.com/knqyf263/gost
// } else if isCveFixed(v, previous) {
// updated[v.CveID] = v
// logging.Log.Debugf("fixed: %s", v.CveID)
@@ -674,36 +673,32 @@ func isCveInfoUpdated(cveID string, previous, current models.ScanResult) bool {
models.NewCveContentType(current.Family),
}
prevLastModifieds := map[models.CveContentType][]time.Time{}
prevLastModified := map[models.CveContentType]time.Time{}
preVinfo, ok := previous.ScannedCves[cveID]
if !ok {
return true
}
for _, cType := range cTypes {
if conts, ok := preVinfo.CveContents[cType]; ok {
for _, cont := range conts {
prevLastModifieds[cType] = append(prevLastModifieds[cType], cont.LastModified)
}
if content, ok := preVinfo.CveContents[cType]; ok {
prevLastModified[cType] = content.LastModified
}
}
curLastModifieds := map[models.CveContentType][]time.Time{}
curLastModified := map[models.CveContentType]time.Time{}
curVinfo, ok := current.ScannedCves[cveID]
if !ok {
return true
}
for _, cType := range cTypes {
if conts, ok := curVinfo.CveContents[cType]; ok {
for _, cont := range conts {
curLastModifieds[cType] = append(curLastModifieds[cType], cont.LastModified)
}
if content, ok := curVinfo.CveContents[cType]; ok {
curLastModified[cType] = content.LastModified
}
}
for _, t := range cTypes {
if !reflect.DeepEqual(curLastModifieds[t], prevLastModifieds[t]) {
if !curLastModified[t].Equal(prevLastModified[t]) {
logging.Log.Debugf("%s LastModified not equal: \n%s\n%s",
cveID, curLastModifieds[t], prevLastModifieds[t])
cveID, curLastModified[t], prevLastModified[t])
return true
}
}

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, scanResults, uuid.GenerateUUID)
needsOverwrite, err := ensure(servers, path, 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, scanResults models.ScanResults, generateFunc func() (string, error)) (needsOverwrite bool, err error) {
func ensure(servers map[string]config.ServerInfo, path string, 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.scanResults, tt.args.generateFunc)
gotNeedsOverwrite, err := ensure(tt.args.servers, tt.args.path, tt.args.scanResults, tt.args.generateFunc)
if (err != nil) != tt.wantErr {
t.Errorf("ensure() error = %v, wantErr %v", err, tt.wantErr)
return

View File

@@ -1,118 +0,0 @@
package scanner
import (
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
)
// inherit OsTypeInterface
type alma struct {
redhatBase
}
// NewAlma is constructor
func newAlma(c config.ServerInfo) *alma {
r := &alma{
redhatBase{
base: base{
osPackages: osPackages{
Packages: models.Packages{},
VulnInfos: models.VulnInfos{},
},
},
sudo: rootPrivAlma{},
},
}
r.log = logging.NewNormalLogger()
r.setServerInfo(c)
return r
}
func (o *alma) checkScanMode() error {
return nil
}
func (o *alma) checkDeps() error {
if o.getServerInfo().Mode.IsFast() {
return o.execCheckDeps(o.depsFast())
} else if o.getServerInfo().Mode.IsFastRoot() {
return o.execCheckDeps(o.depsFastRoot())
} else {
return o.execCheckDeps(o.depsDeep())
}
}
func (o *alma) depsFast() []string {
if o.getServerInfo().Mode.IsOffline() {
return []string{}
}
// repoquery
// `rpm -qa` shows dnf-utils as yum-utils on RHEL8, CentOS8, Alma8, Rocky8
return []string{"yum-utils"}
}
func (o *alma) depsFastRoot() []string {
if o.getServerInfo().Mode.IsOffline() {
return []string{}
}
// repoquery
// `rpm -qa` shows dnf-utils as yum-utils on RHEL8, CentOS8, Alma8, Rocky8
return []string{"yum-utils"}
}
func (o *alma) depsDeep() []string {
return o.depsFastRoot()
}
func (o *alma) checkIfSudoNoPasswd() error {
if o.getServerInfo().Mode.IsFast() {
return o.execCheckIfSudoNoPasswd(o.sudoNoPasswdCmdsFast())
} else if o.getServerInfo().Mode.IsFastRoot() {
return o.execCheckIfSudoNoPasswd(o.sudoNoPasswdCmdsFastRoot())
} else {
return o.execCheckIfSudoNoPasswd(o.sudoNoPasswdCmdsDeep())
}
}
func (o *alma) sudoNoPasswdCmdsFast() []cmd {
return []cmd{}
}
func (o *alma) sudoNoPasswdCmdsFastRoot() []cmd {
if !o.ServerInfo.IsContainer() {
return []cmd{
{"repoquery -h", exitStatusZero},
{"needs-restarting", exitStatusZero},
{"which which", exitStatusZero},
{"stat /proc/1/exe", exitStatusZero},
{"ls -l /proc/1/exe", exitStatusZero},
{"cat /proc/1/maps", exitStatusZero},
{"lsof -i -P", exitStatusZero},
}
}
return []cmd{
{"repoquery -h", exitStatusZero},
{"needs-restarting", exitStatusZero},
}
}
func (o *alma) sudoNoPasswdCmdsDeep() []cmd {
return o.sudoNoPasswdCmdsFastRoot()
}
type rootPrivAlma struct{}
func (o rootPrivAlma) repoquery() bool {
return false
}
func (o rootPrivAlma) yumMakeCache() bool {
return false
}
func (o rootPrivAlma) yumPS() bool {
return false
}

View File

@@ -26,22 +26,14 @@ import (
"golang.org/x/xerrors"
// Import library scanner
_ "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"
_ "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"
nmap "github.com/Ullaakut/nmap/v2"
)
@@ -70,7 +62,7 @@ type osPackages struct {
// enabled dnf modules or packages
EnabledDnfModules []string
// Detected Vulnerabilities Key: CVE-ID
// unsecure packages
VulnInfos models.VulnInfos
// kernel information
@@ -664,7 +656,6 @@ func AnalyzeLibraries(ctx context.Context, libFilemap map[string][]byte) (librar
&wg,
semaphore.NewWeighted(1),
result,
"",
path,
&DummyFileInfo{},
func() ([]byte, error) { return b, nil }); err != nil {

View File

@@ -4,18 +4,13 @@ import (
"reflect"
"testing"
_ "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/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/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
)

View File

@@ -11,7 +11,7 @@ type centos struct {
redhatBase
}
// NewCentOS is constructor
// NewAmazon is constructor
func newCentOS(c config.ServerInfo) *centos {
r := &centos{
redhatBase{
@@ -49,7 +49,7 @@ func (o *centos) depsFast() []string {
}
// repoquery
// `rpm -qa` shows dnf-utils as yum-utils on RHEL8, CentOS8, Alma8, Rocky8
// `rpm -qa` shows dnf-utils as yum-utils on RHEL8, CentOS8
return []string{"yum-utils"}
}
@@ -59,7 +59,7 @@ func (o *centos) depsFastRoot() []string {
}
// repoquery
// `rpm -qa` shows dnf-utils as yum-utils on RHEL8, CentOS8, Alma8, Rocky8
// `rpm -qa` shows dnf-utils as yum-utils on RHEL8, CentOS8
return []string{"yum-utils"}
}

View File

@@ -931,7 +931,7 @@ func (o *debian) getCveIDsFromChangelog(
if 1 < len(splittedByColon) {
verAfterColon = splittedByColon[1]
if cveIDs, pack, err := o.parseChangelog(
changelog, name, verAfterColon, models.ChangelogRoughMatch); err == nil {
changelog, name, verAfterColon, models.ChangelogLenientMatch); err == nil {
return cveIDs, pack
}
}
@@ -948,7 +948,7 @@ func (o *debian) getCveIDsFromChangelog(
ss := strings.Split(ver, d)
if 1 < len(ss) {
if cveIDs, pack, err := o.parseChangelog(
changelog, name, ss[0], models.ChangelogRoughMatch); err == nil {
changelog, name, ss[0], models.ChangelogLenientMatch); err == nil {
return cveIDs, pack
}
}
@@ -956,7 +956,7 @@ func (o *debian) getCveIDsFromChangelog(
ss = strings.Split(verAfterColon, d)
if 1 < len(ss) {
if cveIDs, pack, err := o.parseChangelog(
changelog, name, ss[0], models.ChangelogRoughMatch); err == nil {
changelog, name, ss[0], models.ChangelogLenientMatch); err == nil {
return cveIDs, pack
}
}
@@ -1020,7 +1020,7 @@ func (o *debian) parseChangelog(changelog, name, ver string, confidence models.C
pack := o.Packages[name]
pack.Changelog = &models.Changelog{
Contents: strings.Join(buf, "\n"),
Method: models.ChangelogRoughMatchStr,
Method: models.ChangelogLenientMatchStr,
}
cves := []DetectedCveID{}

View File

@@ -144,7 +144,12 @@ systemd (228-5) unstable; urgency=medium`,
util-linux (2.27.1-1) unstable; urgency=medium
util-linux (2.27-3ubuntu1) xenial; urgency=medium`,
},
[]DetectedCveID{},
[]DetectedCveID{
// {"CVE-2015-2325", models.ChangelogLenientMatch},
// {"CVE-2015-2326", models.ChangelogLenientMatch},
// {"CVE-2015-3210", models.ChangelogLenientMatch},
// {"CVE-2016-1000000", models.ChangelogLenientMatch},
},
models.Changelog{
// Contents: `util-linux (2.27.1-3ubuntu1) xenial; urgency=medium
// util-linux (2.27.1-3) unstable; urgency=medium
@@ -175,7 +180,12 @@ systemd (228-5) unstable; urgency=medium`,
util-linux (2.27.1-1) unstable; urgency=medium
util-linux (2.27-3) xenial; urgency=medium`,
},
[]DetectedCveID{},
[]DetectedCveID{
// {"CVE-2015-2325", models.ChangelogLenientMatch},
// {"CVE-2015-2326", models.ChangelogLenientMatch},
// {"CVE-2015-3210", models.ChangelogLenientMatch},
// {"CVE-2016-1000000", models.ChangelogLenientMatch},
},
models.Changelog{
// Contents: `util-linux (2.27.1-3ubuntu1) xenial; urgency=medium
// util-linux (2.27.1-3) unstable; urgency=medium
@@ -835,7 +845,7 @@ vlc (3.0.11-0+deb10u1) buster-security; urgency=high
-- RealVNC <noreply@realvnc.com> Wed, 13 May 2020 19:51:40 +0100
`,
Method: models.ChangelogRoughMatchStr,
Method: models.ChangelogLenientMatchStr,
}},
},
},

View File

@@ -11,7 +11,7 @@ type oracle struct {
redhatBase
}
// NewOracle is constructor
// NewAmazon is constructor
func newOracle(c config.ServerInfo) *oracle {
r := &oracle{
redhatBase{

View File

@@ -58,58 +58,12 @@ func detectRedhat(c config.ServerInfo) (bool, osTypeInterface) {
cent := newCentOS(c)
cent.setDistro(constant.CentOS, release)
return true, cent
case "alma", "almalinux":
alma := newAlma(c)
alma.setDistro(constant.Alma, release)
return true, alma
default:
logging.Log.Warnf("Failed to parse CentOS: %s", r)
}
}
}
if r := exec(c, "ls /etc/almalinux-release", noSudo); r.isSuccess() {
if r := exec(c, "cat /etc/almalinux-release", noSudo); r.isSuccess() {
re := regexp.MustCompile(`(.*) release (\d[\d\.]*)`)
result := re.FindStringSubmatch(strings.TrimSpace(r.Stdout))
if len(result) != 3 {
logging.Log.Warnf("Failed to parse Alma version: %s", r)
return true, newAlma(c)
}
release := result[2]
switch strings.ToLower(result[1]) {
case "alma", "almalinux":
alma := newAlma(c)
alma.setDistro(constant.Alma, release)
return true, alma
default:
logging.Log.Warnf("Failed to parse Alma: %s", r)
}
}
}
if r := exec(c, "ls /etc/rocky-release", noSudo); r.isSuccess() {
if r := exec(c, "cat /etc/rocky-release", noSudo); r.isSuccess() {
re := regexp.MustCompile(`(.*) release (\d[\d\.]*)`)
result := re.FindStringSubmatch(strings.TrimSpace(r.Stdout))
if len(result) != 3 {
logging.Log.Warnf("Failed to parse Rocky version: %s", r)
return true, newRocky(c)
}
release := result[2]
switch strings.ToLower(result[1]) {
case "rocky", "rocky linux":
rocky := newRocky(c)
rocky.setDistro(constant.Rocky, release)
return true, rocky
default:
logging.Log.Warnf("Failed to parse Rocky: %s", r)
}
}
}
if r := exec(c, "ls /etc/redhat-release", noSudo); r.isSuccess() {
// https://www.rackaid.com/blog/how-to-determine-centos-or-red-hat-version/
// e.g.
@@ -125,18 +79,10 @@ func detectRedhat(c config.ServerInfo) (bool, osTypeInterface) {
release := result[2]
switch strings.ToLower(result[1]) {
case "centos", "centos linux", "centos stream":
case "centos", "centos linux":
cent := newCentOS(c)
cent.setDistro(constant.CentOS, release)
return true, cent
case "alma", "almalinux":
alma := newAlma(c)
alma.setDistro(constant.Alma, release)
return true, alma
case "rocky", "rocky linux":
rocky := newRocky(c)
rocky.setDistro(constant.Rocky, release)
return true, rocky
default:
// RHEL
rhel := newRHEL(c)
@@ -509,7 +455,7 @@ func (o *redhatBase) isExecNeedsRestarting() bool {
// TODO zypper ps
// https://github.com/future-architect/vuls/issues/696
return false
case constant.RedHat, constant.CentOS, constant.Rocky, constant.Oracle:
case constant.RedHat, constant.CentOS, constant.Oracle:
majorVersion, err := o.Distro.MajorVersion()
if err != nil || majorVersion < 6 {
o.log.Errorf("Not implemented yet: %s, err: %+v", o.Distro, err)
@@ -688,7 +634,7 @@ func (o *redhatBase) rpmQf() string {
func (o *redhatBase) detectEnabledDnfModules() ([]string, error) {
switch o.Distro.Family {
case constant.RedHat, constant.CentOS, constant.Alma, constant.Rocky:
case constant.RedHat, constant.CentOS:
//TODO OracleLinux
default:
return nil, nil

View File

@@ -55,7 +55,7 @@ func (o *rhel) depsFastRoot() []string {
}
// repoquery
// `rpm -qa` shows dnf-utils as yum-utils on RHEL8, CentOS8, Alma8, Rocky8
// `rpm -qa` shows dnf-utils as yum-utils on RHEL8, CentOS8
return []string{"yum-utils"}
}

View File

@@ -1,118 +0,0 @@
package scanner
import (
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
)
// inherit OsTypeInterface
type rocky struct {
redhatBase
}
// NewRocky is constructor
func newRocky(c config.ServerInfo) *rocky {
r := &rocky{
redhatBase{
base: base{
osPackages: osPackages{
Packages: models.Packages{},
VulnInfos: models.VulnInfos{},
},
},
sudo: rootPrivRocky{},
},
}
r.log = logging.NewNormalLogger()
r.setServerInfo(c)
return r
}
func (o *rocky) checkScanMode() error {
return nil
}
func (o *rocky) checkDeps() error {
if o.getServerInfo().Mode.IsFast() {
return o.execCheckDeps(o.depsFast())
} else if o.getServerInfo().Mode.IsFastRoot() {
return o.execCheckDeps(o.depsFastRoot())
} else {
return o.execCheckDeps(o.depsDeep())
}
}
func (o *rocky) depsFast() []string {
if o.getServerInfo().Mode.IsOffline() {
return []string{}
}
// repoquery
// `rpm -qa` shows dnf-utils as yum-utils on RHEL8, CentOS8, Alma8, Rocky8
return []string{"yum-utils"}
}
func (o *rocky) depsFastRoot() []string {
if o.getServerInfo().Mode.IsOffline() {
return []string{}
}
// repoquery
// `rpm -qa` shows dnf-utils as yum-utils on RHEL8, CentOS8, Alma8, Rocky8
return []string{"yum-utils"}
}
func (o *rocky) depsDeep() []string {
return o.depsFastRoot()
}
func (o *rocky) checkIfSudoNoPasswd() error {
if o.getServerInfo().Mode.IsFast() {
return o.execCheckIfSudoNoPasswd(o.sudoNoPasswdCmdsFast())
} else if o.getServerInfo().Mode.IsFastRoot() {
return o.execCheckIfSudoNoPasswd(o.sudoNoPasswdCmdsFastRoot())
} else {
return o.execCheckIfSudoNoPasswd(o.sudoNoPasswdCmdsDeep())
}
}
func (o *rocky) sudoNoPasswdCmdsFast() []cmd {
return []cmd{}
}
func (o *rocky) sudoNoPasswdCmdsFastRoot() []cmd {
if !o.ServerInfo.IsContainer() {
return []cmd{
{"repoquery -h", exitStatusZero},
{"needs-restarting", exitStatusZero},
{"which which", exitStatusZero},
{"stat /proc/1/exe", exitStatusZero},
{"ls -l /proc/1/exe", exitStatusZero},
{"cat /proc/1/maps", exitStatusZero},
{"lsof -i -P", exitStatusZero},
}
}
return []cmd{
{"repoquery -h", exitStatusZero},
{"needs-restarting", exitStatusZero},
}
}
func (o *rocky) sudoNoPasswdCmdsDeep() []cmd {
return o.sudoNoPasswdCmdsFastRoot()
}
type rootPrivRocky struct{}
func (o rootPrivRocky) repoquery() bool {
return false
}
func (o rootPrivRocky) yumMakeCache() bool {
return false
}
func (o rootPrivRocky) yumPS() bool {
return false
}

View File

@@ -211,16 +211,12 @@ func ParseInstalledPkgs(distro config.Distro, kernel models.Kernel, pkgList stri
var osType osTypeInterface
switch distro.Family {
case constant.Debian, constant.Ubuntu, constant.Raspbian:
case constant.Debian, constant.Ubuntu:
osType = &debian{base: base}
case constant.RedHat:
osType = &rhel{redhatBase: redhatBase{base: base}}
case constant.CentOS:
osType = &centos{redhatBase: redhatBase{base: base}}
case constant.Alma:
osType = &alma{redhatBase: redhatBase{base: base}}
case constant.Rocky:
osType = &rocky{redhatBase: redhatBase{base: base}}
case constant.Oracle:
osType = &oracle{redhatBase: redhatBase{base: base}}
case constant.Amazon:
@@ -655,8 +651,7 @@ func (s Scanner) getScanResults(scannedAt time.Time) (results models.ScanResults
}
if o.getServerInfo().Module.IsScanPort() {
if err = o.scanPorts(); err != nil {
// continue scanning
logging.Log.Warnf("Failed to scan Ports: %+v", err)
return xerrors.Errorf("Failed to scan Ports: %w", err)
}
}
if o.getServerInfo().Module.IsScanWordPress() {

View File

@@ -26,7 +26,7 @@ func isRunningKernel(pack models.Package, family string, kernel models.Kernel) (
}
return false, false
case constant.RedHat, constant.Oracle, constant.CentOS, constant.Alma, constant.Rocky, constant.Amazon:
case constant.RedHat, constant.Oracle, constant.CentOS, constant.Amazon:
switch pack.Name {
case "kernel", "kernel-devel", "kernel-core", "kernel-modules", "kernel-uek":
ver := fmt.Sprintf("%s-%s.%s", pack.Version, pack.Release, pack.Arch)

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package server

View File

@@ -34,7 +34,7 @@ func (*DiscoverCmd) Usage() string {
}
// SetFlags set flag
func (p *DiscoverCmd) SetFlags(_ *flag.FlagSet) {
func (p *DiscoverCmd) SetFlags(f *flag.FlagSet) {
}
// Execute execute
@@ -157,13 +157,6 @@ func printConfigToml(ips []string) (err error) {
#room = "xxxxxxxxxxx"
#apiToken = "xxxxxxxxxxxxxxxxxx"
# https://vuls.io/docs/en/config.toml.html#googlechat-section
#[googlechat]
#webHookURL = "https://chat.googleapis.com/v1/spaces/xxxxxxxxxx/messages?key=yyyyyyyyyy&token=zzzzzzzzzz%3D"
#skipIfNoCve = false
#serverNameRegexp = "^(\\[Reboot Required\\] )?((spam|ham).*|.*(egg)$)" # include spamonigiri, hamburger, boiledegg
#serverNameRegexp = "^(\\[Reboot Required\\] )?(?:(spam|ham).*|.*(?:egg)$)" # exclude spamonigiri, hamburger, boiledegg
# https://vuls.io/docs/en/config.toml.html#telegram-section
#[telegram]
#chatID = "xxxxxxxxxxx"
@@ -211,7 +204,6 @@ host = "{{$ip}}"
#containerType = "docker" #or "lxd" or "lxc" default: docker
#containersIncluded = ["${running}"]
#containersExcluded = ["container_name_a"]
#confidenceScoreOver = 80
#[servers.{{index $names $i}}.containers.container_name_a]
#cpeNames = [ "cpe:/a:rubyonrails:ruby_on_rails:4.2.1" ]

View File

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

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package subcmds
@@ -31,16 +30,15 @@ type ReportCmd struct {
formatList bool
gzip bool
toSlack bool
toChatWork bool
toGoogleChat bool
toTelegram bool
toEmail bool
toSyslog bool
toLocalFile bool
toS3 bool
toAzureBlob bool
toHTTP bool
toSlack bool
toChatWork bool
toTelegram bool
toEmail bool
toSyslog bool
toLocalFile bool
toS3 bool
toAzureBlob bool
toHTTP bool
}
// Name return subcommand name
@@ -60,7 +58,6 @@ func (*ReportCmd) Usage() string {
[-log-dir=/path/to/log]
[-refresh-cve]
[-cvss-over=7]
[-confidence-over=80]
[-diff]
[-diff-minus]
[-diff-plus]
@@ -70,7 +67,6 @@ func (*ReportCmd) Usage() string {
[-to-http]
[-to-slack]
[-to-chatwork]
[-to-googlechat]
[-to-telegram]
[-to-localfile]
[-to-s3]
@@ -119,9 +115,6 @@ func (p *ReportCmd) SetFlags(f *flag.FlagSet) {
f.Float64Var(&config.Conf.CvssScoreOver, "cvss-over", 0,
"-cvss-over=6.5 means reporting CVSS Score 6.5 and over (default: 0 (means report all))")
f.IntVar(&config.Conf.ConfidenceScoreOver, "confidence-over", 80,
"-confidence-over=40 means reporting Confidence Score 40 and over (default: 80)")
f.BoolVar(&config.Conf.DiffMinus, "diff-minus", false,
"Minus Difference between previous result and current result")
@@ -153,7 +146,6 @@ func (p *ReportCmd) SetFlags(f *flag.FlagSet) {
f.BoolVar(&p.toSlack, "to-slack", false, "Send report via Slack")
f.BoolVar(&p.toChatWork, "to-chatwork", false, "Send report via chatwork")
f.BoolVar(&p.toGoogleChat, "to-googlechat", false, "Send report via Google Chat")
f.BoolVar(&p.toTelegram, "to-telegram", false, "Send report via Telegram")
f.BoolVar(&p.toEmail, "to-email", false, "Send report via Email")
f.BoolVar(&p.toSyslog, "to-syslog", false, "Send report via Syslog")
@@ -181,7 +173,6 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
}
config.Conf.Slack.Enabled = p.toSlack
config.Conf.ChatWork.Enabled = p.toChatWork
config.Conf.GoogleChat.Enabled = p.toGoogleChat
config.Conf.Telegram.Enabled = p.toTelegram
config.Conf.EMail.Enabled = p.toEmail
config.Conf.Syslog.Enabled = p.toSyslog
@@ -270,10 +261,6 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
reports = append(reports, reporter.ChatWorkWriter{Cnf: config.Conf.ChatWork, Proxy: config.Conf.HTTPProxy})
}
if p.toGoogleChat {
reports = append(reports, reporter.GoogleChatWriter{Cnf: config.Conf.GoogleChat, Proxy: config.Conf.HTTPProxy})
}
if p.toTelegram {
reports = append(reports, reporter.TelegramWriter{Cnf: config.Conf.Telegram})
}

View File

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package subcmds
@@ -39,7 +38,6 @@ func (*ServerCmd) Usage() string {
[-log-to-file]
[-log-dir=/path/to/log]
[-cvss-over=7]
[-confidence-over=80]
[-ignore-unscored-cves]
[-ignore-unfixed]
[-to-localfile]
@@ -72,9 +70,6 @@ func (p *ServerCmd) SetFlags(f *flag.FlagSet) {
f.Float64Var(&config.Conf.CvssScoreOver, "cvss-over", 0,
"-cvss-over=6.5 means Servering CVSS Score 6.5 and over (default: 0 (means Server all))")
f.IntVar(&config.Conf.ConfidenceScoreOver, "confidence-over", 80,
"-confidence-over=40 means reporting Confidence Score 40 and over (default: 80)")
f.BoolVar(&config.Conf.IgnoreUnscoredCves, "ignore-unscored-cves", false,
"Don't Server the unscored CVEs")
@@ -90,7 +85,7 @@ func (p *ServerCmd) SetFlags(f *flag.FlagSet) {
}
// Execute execute
func (p *ServerCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
func (p *ServerCmd) Execute(_ context.Context, f *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

@@ -1,4 +1,3 @@
//go:build !scanner
// +build !scanner
package subcmds
@@ -37,7 +36,6 @@ func (*TuiCmd) Usage() string {
[-refresh-cve]
[-config=/path/to/config.toml]
[-cvss-over=7]
[-confidence-over=80]
[-diff]
[-diff-minus]
[-diff-plus]
@@ -81,9 +79,6 @@ func (p *TuiCmd) SetFlags(f *flag.FlagSet) {
f.Float64Var(&config.Conf.CvssScoreOver, "cvss-over", 0,
"-cvss-over=6.5 means reporting CVSS Score 6.5 and over (default: 0 (means report all))")
f.IntVar(&config.Conf.ConfidenceScoreOver, "confidence-over", 80,
"-confidence-over=40 means reporting Confidence Score 40 and over (default: 80)")
f.BoolVar(&config.Conf.Diff, "diff", false,
"Plus Difference between previous result and current result")

View File

@@ -301,7 +301,10 @@ func cursorMoveMiddle(g *gocui.Gui, v *gocui.View) error {
return err
}
}
return onMovingCursorRedrawView(g, v)
if err := onMovingCursorRedrawView(g, v); err != nil {
return err
}
return nil
}
func cursorPageDown(g *gocui.Gui, v *gocui.View) error {
@@ -502,7 +505,7 @@ func showMsg(g *gocui.Gui, v *gocui.View) error {
return nil
}
func delMsg(g *gocui.Gui, _ *gocui.View) error {
func delMsg(g *gocui.Gui, v *gocui.View) error {
if err := g.DeleteView("msg"); err != nil {
return err
}
@@ -510,7 +513,7 @@ func delMsg(g *gocui.Gui, _ *gocui.View) error {
return err
}
func quit(_ *gocui.Gui, _ *gocui.View) error {
func quit(g *gocui.Gui, v *gocui.View) error {
return gocui.ErrQuit
}
@@ -892,7 +895,7 @@ func detailLines() (string, error) {
vinfo := vinfos[currentVinfo]
links := []string{}
for _, r := range vinfo.CveContents.PrimarySrcURLs(r.Lang, r.Family, vinfo.CveID, vinfo.Confidences) {
for _, r := range vinfo.CveContents.PrimarySrcURLs(r.Lang, r.Family, vinfo.CveID) {
links = append(links, r.Value)
}
@@ -905,11 +908,9 @@ func detailLines() (string, error) {
refsMap[ref.Link] = ref
}
}
if conts, found := vinfo.CveContents[models.Trivy]; found {
for _, cont := range conts {
for _, ref := range cont.References {
refsMap[ref.Link] = ref
}
if cont, found := vinfo.CveContents[models.Trivy]; found {
for _, ref := range cont.References {
refsMap[ref.Link] = ref
}
}
refs := []models.Reference{}
@@ -1013,7 +1014,7 @@ CWE
Confidence
-----------
{{range $confidence := .Confidences -}}
* {{$confidence.Score}} / {{$confidence.DetectionMethod}}
* {{$confidence.DetectionMethod}}
{{end}}
References
-----------