Compare commits
10 Commits
v0.23.0-be
...
v0.23.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abdb081af7 | ||
|
|
e506125017 | ||
|
|
8ccaa8c3ef | ||
|
|
de1ed8ecaa | ||
|
|
947d668452 | ||
|
|
db21149f00 | ||
|
|
7f35f4e661 | ||
|
|
6682232b5c | ||
|
|
984debe929 | ||
|
|
a528362663 |
20
.github/workflows/goreleaser.yml
vendored
20
.github/workflows/goreleaser.yml
vendored
@@ -12,9 +12,6 @@ jobs:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: install package for cross compile
|
||||
run: sudo apt update && sudo apt install -y gcc-aarch64-linux-gnu
|
||||
-
|
||||
name: Unshallow
|
||||
run: git fetch --prune --unshallow
|
||||
@@ -22,13 +19,16 @@ jobs:
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.18
|
||||
go-version-file: go.mod
|
||||
-
|
||||
name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v2
|
||||
with:
|
||||
version: latest
|
||||
args: release --rm-dist
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
docker run --rm \
|
||||
-e CGO_ENABLED=1 \
|
||||
-e GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v `pwd`:/go/src/github.com/future-architect/vuls \
|
||||
-w /go/src/github.com/future-architect/vuls \
|
||||
ghcr.io/goreleaser/goreleaser-cross:v1.20 \
|
||||
release --clean
|
||||
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -20,3 +20,5 @@ vuls
|
||||
!cmd/vuls
|
||||
future-vuls
|
||||
trivy-to-vuls
|
||||
snmp2cpe
|
||||
!snmp2cpe/
|
||||
@@ -6,7 +6,7 @@ release:
|
||||
owner: future-architect
|
||||
name: vuls
|
||||
builds:
|
||||
- id: vuls-amd64
|
||||
- id: vuls-linux-amd64
|
||||
goos:
|
||||
- linux
|
||||
goarch:
|
||||
@@ -21,7 +21,7 @@ builds:
|
||||
- -s -w -X github.com/future-architect/vuls/config.Version={{.Version}} -X github.com/future-architect/vuls/config.Revision={{.Commit}}-{{ .CommitDate }}
|
||||
binary: vuls
|
||||
|
||||
- id: vuls-arm64
|
||||
- id: vuls-linux-arm64
|
||||
goos:
|
||||
- linux
|
||||
goarch:
|
||||
@@ -36,11 +36,42 @@ builds:
|
||||
- -s -w -X github.com/future-architect/vuls/config.Version={{.Version}} -X github.com/future-architect/vuls/config.Revision={{.Commit}}-{{ .CommitDate }}
|
||||
binary: vuls
|
||||
|
||||
- id: vuls-windows-amd64
|
||||
goos:
|
||||
- windows
|
||||
goarch:
|
||||
- amd64
|
||||
env:
|
||||
- CGO_ENABLED=1
|
||||
- CC=x86_64-w64-mingw32-gcc
|
||||
main: ./cmd/vuls/main.go
|
||||
flags:
|
||||
- -a
|
||||
ldflags:
|
||||
- -s -w -X github.com/future-architect/vuls/config.Version={{.Version}} -X github.com/future-architect/vuls/config.Revision={{.Commit}}-{{ .CommitDate }}
|
||||
binary: vuls
|
||||
|
||||
- id: vuls-windows-arm64
|
||||
goos:
|
||||
- windows
|
||||
goarch:
|
||||
- arm64
|
||||
env:
|
||||
- CGO_ENABLED=1
|
||||
- CC=/llvm-mingw/bin/aarch64-w64-mingw32-gcc
|
||||
main: ./cmd/vuls/main.go
|
||||
flags:
|
||||
- -a
|
||||
ldflags:
|
||||
- -s -w -X github.com/future-architect/vuls/config.Version={{.Version}} -X github.com/future-architect/vuls/config.Revision={{.Commit}}-{{ .CommitDate }}
|
||||
binary: vuls
|
||||
|
||||
- id: vuls-scanner
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- linux
|
||||
- windows
|
||||
goarch:
|
||||
- 386
|
||||
- amd64
|
||||
@@ -60,6 +91,7 @@ builds:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- linux
|
||||
- windows
|
||||
goarch:
|
||||
- 386
|
||||
- amd64
|
||||
@@ -68,6 +100,8 @@ builds:
|
||||
tags:
|
||||
- scanner
|
||||
main: ./contrib/trivy/cmd/main.go
|
||||
ldflags:
|
||||
- -s -w -X github.com/future-architect/vuls/config.Version={{.Version}} -X github.com/future-architect/vuls/config.Revision={{.Commit}}-{{ .CommitDate }}
|
||||
binary: trivy-to-vuls
|
||||
|
||||
- id: future-vuls
|
||||
@@ -75,6 +109,7 @@ builds:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- linux
|
||||
- windows
|
||||
goarch:
|
||||
- 386
|
||||
- amd64
|
||||
@@ -84,16 +119,40 @@ builds:
|
||||
- -a
|
||||
tags:
|
||||
- scanner
|
||||
ldflags:
|
||||
- -s -w -X github.com/future-architect/vuls/config.Version={{.Version}} -X github.com/future-architect/vuls/config.Revision={{.Commit}}-{{ .CommitDate }}
|
||||
main: ./contrib/future-vuls/cmd/main.go
|
||||
binary: future-vuls
|
||||
|
||||
- id: snmp2cpe
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- linux
|
||||
- windows
|
||||
goarch:
|
||||
- 386
|
||||
- amd64
|
||||
- arm
|
||||
- arm64
|
||||
flags:
|
||||
- -a
|
||||
tags:
|
||||
- scanner
|
||||
ldflags:
|
||||
- -s -w -X github.com/future-architect/vuls/config.Version={{.Version}} -X github.com/future-architect/vuls/config.Revision={{.Commit}}-{{ .CommitDate }}
|
||||
main: ./contrib/snmp2cpe/cmd/main.go
|
||||
binary: snmp2cpe
|
||||
|
||||
archives:
|
||||
|
||||
- id: vuls
|
||||
name_template: '{{ .Binary }}_{{.Version}}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
|
||||
builds:
|
||||
- vuls-amd64
|
||||
- vuls-arm64
|
||||
- vuls-linux-amd64
|
||||
- vuls-linux-arm64
|
||||
- vuls-windows-amd64
|
||||
- vuls-windows-arm64
|
||||
format: tar.gz
|
||||
files:
|
||||
- LICENSE
|
||||
@@ -129,5 +188,16 @@ archives:
|
||||
- LICENSE
|
||||
- README*
|
||||
- CHANGELOG.md
|
||||
|
||||
- id: snmp2cpe
|
||||
name_template: '{{ .Binary }}_{{.Version}}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
|
||||
builds:
|
||||
- snmp2cpe
|
||||
format: tar.gz
|
||||
files:
|
||||
- LICENSE
|
||||
- README*
|
||||
- CHANGELOG.md
|
||||
|
||||
snapshot:
|
||||
name_template: SNAPSHOT-{{ .Commit }}
|
||||
|
||||
22
GNUmakefile
22
GNUmakefile
@@ -81,12 +81,16 @@ build-trivy-to-vuls: ./contrib/trivy/cmd/main.go
|
||||
build-future-vuls: ./contrib/future-vuls/cmd/main.go
|
||||
$(GO) build -a -ldflags "$(LDFLAGS)" -o future-vuls ./contrib/future-vuls/cmd
|
||||
|
||||
# snmp2cpe
|
||||
build-snmp2cpe: ./contrib/snmp2cpe/cmd/main.go
|
||||
$(GO) build -a -ldflags "$(LDFLAGS)" -o snmp2cpe ./contrib/snmp2cpe/cmd
|
||||
|
||||
# integration-test
|
||||
BASE_DIR := '${PWD}/integration/results'
|
||||
# $(shell mkdir -p ${BASE_DIR})
|
||||
NOW=$(shell date --iso-8601=seconds)
|
||||
CURRENT := `find ${BASE_DIR} -type d -exec basename {} \; | sort -nr | head -n 1`
|
||||
NOW=$(shell date '+%Y-%m-%dT%H-%M-%S%z')
|
||||
NOW_JSON_DIR := '${BASE_DIR}/$(NOW)'
|
||||
ONE_SEC_AFTER=$(shell date -d '+1 second' --iso-8601=seconds)
|
||||
ONE_SEC_AFTER=$(shell date -d '+1 second' '+%Y-%m-%dT%H-%M-%S%z')
|
||||
ONE_SEC_AFTER_JSON_DIR := '${BASE_DIR}/$(ONE_SEC_AFTER)'
|
||||
LIBS := 'bundler' 'pip' 'pipenv' 'poetry' 'composer' 'npm' 'yarn' 'pnpm' 'cargo' 'gomod' 'gosum' 'gobinary' 'jar' 'pom' 'gradle' 'nuget-lock' 'nuget-config' 'dotnet-deps' 'conan' 'nvd_exact' 'nvd_rough' 'nvd_vendor_product' 'nvd_match_no_jvn' 'jvn_vendor_product' 'jvn_vendor_product_nover'
|
||||
|
||||
@@ -106,14 +110,14 @@ endif
|
||||
mkdir -p ${NOW_JSON_DIR}
|
||||
sleep 1
|
||||
./vuls.old scan -config=./integration/int-config.toml --results-dir=${BASE_DIR} ${LIBS}
|
||||
cp ${BASE_DIR}/current/*.json ${NOW_JSON_DIR}
|
||||
cp ${BASE_DIR}/$(CURRENT)/*.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 ${BASE_DIR}/$(CURRENT)/*.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}
|
||||
|
||||
@@ -139,14 +143,14 @@ endif
|
||||
mkdir -p ${NOW_JSON_DIR}
|
||||
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 -f ${BASE_DIR}/$(CURRENT)/*.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 -f ${BASE_DIR}/$(CURRENT)/*.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}
|
||||
|
||||
@@ -163,14 +167,14 @@ endif
|
||||
sleep 1
|
||||
# new vs new
|
||||
./vuls.new scan -config=./integration/int-config.toml --results-dir=${BASE_DIR} ${LIBS}
|
||||
cp -f ${BASE_DIR}/current/*.json ${NOW_JSON_DIR}
|
||||
cp -f ${BASE_DIR}/$(CURRENT)/*.json ${NOW_JSON_DIR}
|
||||
cp integration/data/results/*.json ${NOW_JSON_DIR}
|
||||
./vuls.new 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 -f ${BASE_DIR}/current/*.json ${ONE_SEC_AFTER_JSON_DIR}
|
||||
cp -f ${BASE_DIR}/$(CURRENT)/*.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}
|
||||
|
||||
|
||||
@@ -48,10 +48,11 @@ Vuls is a tool created to solve the problems listed above. It has the following
|
||||
|
||||
### Scan for any vulnerabilities in Linux/FreeBSD Server
|
||||
|
||||
[Supports major Linux/FreeBSD](https://vuls.io/docs/en/supported-os.html)
|
||||
[Supports major Linux/FreeBSD/Windows](https://vuls.io/docs/en/supported-os.html)
|
||||
|
||||
- Alpine, Amazon Linux, CentOS, AlmaLinux, Rocky Linux, Debian, Oracle Linux, Raspbian, RHEL, openSUSE, openSUSE Leap, SUSE Enterprise Linux, Fedora, and Ubuntu
|
||||
- FreeBSD
|
||||
- Windows
|
||||
- Cloud, on-premise, Running Docker Container
|
||||
|
||||
### High-quality scan
|
||||
@@ -72,6 +73,7 @@ Vuls is a tool created to solve the problems listed above. It has the following
|
||||
- [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/)
|
||||
- [Microsoft CVRF](https://api.msrc.microsoft.com/cvrf/v2.0/swagger/index)
|
||||
|
||||
- Commands(yum, zypper, pkg-audit)
|
||||
- RHSA / ALAS / ELSA / FreeBSD-SA
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build !windows
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
@@ -7,9 +9,10 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/asaskevich/govalidator"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/future-architect/vuls/constant"
|
||||
"github.com/future-architect/vuls/logging"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// Version of Vuls
|
||||
@@ -117,6 +120,9 @@ func (c Config) ValidateOnScan() bool {
|
||||
if es := server.PortScan.Validate(); 0 < len(es) {
|
||||
errs = append(errs, es...)
|
||||
}
|
||||
if es := server.Windows.Validate(); 0 < len(es) {
|
||||
errs = append(errs, es...)
|
||||
}
|
||||
}
|
||||
|
||||
for _, err := range errs {
|
||||
@@ -245,6 +251,7 @@ type ServerInfo struct {
|
||||
IgnoredJSONKeys []string `toml:"ignoredJSONKeys,omitempty" json:"ignoredJSONKeys,omitempty"`
|
||||
WordPress *WordPressConf `toml:"wordpress,omitempty" json:"wordpress,omitempty"`
|
||||
PortScan *PortScanConf `toml:"portscan,omitempty" json:"portscan,omitempty"`
|
||||
Windows *WindowsConf `toml:"windows,omitempty" json:"windows,omitempty"`
|
||||
|
||||
IPv4Addrs []string `toml:"-" json:"ipv4Addrs,omitempty"`
|
||||
IPv6Addrs []string `toml:"-" json:"ipv6Addrs,omitempty"`
|
||||
@@ -271,6 +278,7 @@ type WordPressConf struct {
|
||||
OSUser string `toml:"osUser,omitempty" json:"osUser,omitempty"`
|
||||
DocRoot string `toml:"docRoot,omitempty" json:"docRoot,omitempty"`
|
||||
CmdPath string `toml:"cmdPath,omitempty" json:"cmdPath,omitempty"`
|
||||
NoSudo bool `toml:"noSudo,omitempty" json:"noSudo,omitempty"`
|
||||
}
|
||||
|
||||
// IsZero return whether this struct is not specified in config.toml
|
||||
|
||||
351
config/config_windows.go
Normal file
351
config/config_windows.go
Normal file
@@ -0,0 +1,351 @@
|
||||
//go:build windows
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/asaskevich/govalidator"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/future-architect/vuls/constant"
|
||||
"github.com/future-architect/vuls/logging"
|
||||
)
|
||||
|
||||
// Version of Vuls
|
||||
var Version = "`make build` or `make install` will show the version"
|
||||
|
||||
// Revision of Git
|
||||
var Revision string
|
||||
|
||||
// Conf has Configuration
|
||||
var Conf Config
|
||||
|
||||
// Config is struct of Configuration
|
||||
type Config struct {
|
||||
logging.LogOpts
|
||||
|
||||
// scan, report
|
||||
HTTPProxy string `valid:"url" json:"httpProxy,omitempty"`
|
||||
ResultsDir string `json:"resultsDir,omitempty"`
|
||||
Pipe bool `json:"pipe,omitempty"`
|
||||
|
||||
Default ServerInfo `json:"default,omitempty"`
|
||||
Servers map[string]ServerInfo `json:"servers,omitempty"`
|
||||
|
||||
ScanOpts
|
||||
|
||||
// report
|
||||
CveDict GoCveDictConf `json:"cveDict,omitempty"`
|
||||
OvalDict GovalDictConf `json:"ovalDict,omitempty"`
|
||||
Gost GostConf `json:"gost,omitempty"`
|
||||
Exploit ExploitConf `json:"exploit,omitempty"`
|
||||
Metasploit MetasploitConf `json:"metasploit,omitempty"`
|
||||
KEVuln KEVulnConf `json:"kevuln,omitempty"`
|
||||
Cti CtiConf `json:"cti,omitempty"`
|
||||
|
||||
Slack SlackConf `json:"-"`
|
||||
EMail SMTPConf `json:"-"`
|
||||
HTTP HTTPConf `json:"-"`
|
||||
AWS AWSConf `json:"-"`
|
||||
Azure AzureConf `json:"-"`
|
||||
ChatWork ChatWorkConf `json:"-"`
|
||||
GoogleChat GoogleChatConf `json:"-"`
|
||||
Telegram TelegramConf `json:"-"`
|
||||
WpScan WpScanConf `json:"-"`
|
||||
Saas SaasConf `json:"-"`
|
||||
|
||||
ReportOpts
|
||||
}
|
||||
|
||||
// ReportConf is an interface to Validate Report Config
|
||||
type ReportConf interface {
|
||||
Validate() []error
|
||||
}
|
||||
|
||||
// ScanOpts is options for scan
|
||||
type ScanOpts struct {
|
||||
Vvv bool `json:"vvv,omitempty"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// ValidateOnConfigtest validates
|
||||
func (c Config) ValidateOnConfigtest() bool {
|
||||
errs := c.checkSSHKeyExist()
|
||||
if _, err := govalidator.ValidateStruct(c); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
for _, err := range errs {
|
||||
logging.Log.Error(err)
|
||||
}
|
||||
return len(errs) == 0
|
||||
}
|
||||
|
||||
// ValidateOnScan validates configuration
|
||||
func (c Config) ValidateOnScan() bool {
|
||||
errs := c.checkSSHKeyExist()
|
||||
if len(c.ResultsDir) != 0 {
|
||||
if ok, _ := govalidator.IsFilePath(c.ResultsDir); !ok {
|
||||
errs = append(errs, xerrors.Errorf(
|
||||
"JSON base directory must be a *Absolute* file path. -results-dir: %s", c.ResultsDir))
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := govalidator.ValidateStruct(c); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
for _, server := range c.Servers {
|
||||
if !server.Module.IsScanPort() {
|
||||
continue
|
||||
}
|
||||
if es := server.PortScan.Validate(); 0 < len(es) {
|
||||
errs = append(errs, es...)
|
||||
}
|
||||
if es := server.Windows.Validate(); 0 < len(es) {
|
||||
errs = append(errs, es...)
|
||||
}
|
||||
}
|
||||
|
||||
for _, err := range errs {
|
||||
logging.Log.Error(err)
|
||||
}
|
||||
return len(errs) == 0
|
||||
}
|
||||
|
||||
func (c Config) checkSSHKeyExist() (errs []error) {
|
||||
for serverName, v := range c.Servers {
|
||||
if v.Type == constant.ServerTypePseudo {
|
||||
continue
|
||||
}
|
||||
if v.KeyPath != "" {
|
||||
if _, err := os.Stat(v.KeyPath); err != nil {
|
||||
errs = append(errs, xerrors.Errorf(
|
||||
"%s is invalid. keypath: %s not exists", serverName, v.KeyPath))
|
||||
}
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
// ValidateOnReport validates configuration
|
||||
func (c *Config) ValidateOnReport() bool {
|
||||
errs := []error{}
|
||||
|
||||
if len(c.ResultsDir) != 0 {
|
||||
if ok, _ := govalidator.IsFilePath(c.ResultsDir); !ok {
|
||||
errs = append(errs, xerrors.Errorf(
|
||||
"JSON base directory must be a *Absolute* file path. -results-dir: %s", c.ResultsDir))
|
||||
}
|
||||
}
|
||||
|
||||
_, err := govalidator.ValidateStruct(c)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
for _, rc := range []ReportConf{
|
||||
&c.EMail,
|
||||
&c.Slack,
|
||||
&c.ChatWork,
|
||||
&c.GoogleChat,
|
||||
&c.Telegram,
|
||||
&c.HTTP,
|
||||
&c.AWS,
|
||||
&c.Azure,
|
||||
} {
|
||||
if es := rc.Validate(); 0 < len(es) {
|
||||
errs = append(errs, es...)
|
||||
}
|
||||
}
|
||||
|
||||
for _, cnf := range []VulnDictInterface{
|
||||
&Conf.CveDict,
|
||||
&Conf.OvalDict,
|
||||
&Conf.Gost,
|
||||
&Conf.Exploit,
|
||||
&Conf.Metasploit,
|
||||
&Conf.KEVuln,
|
||||
&Conf.Cti,
|
||||
} {
|
||||
if err := cnf.Validate(); err != nil {
|
||||
errs = append(errs, xerrors.Errorf("Failed to validate %s: %+v", cnf.GetName(), err))
|
||||
}
|
||||
if err := cnf.CheckHTTPHealth(); err != nil {
|
||||
errs = append(errs, xerrors.Errorf("Run %s as server mode before reporting: %+v", cnf.GetName(), err))
|
||||
}
|
||||
}
|
||||
|
||||
for _, err := range errs {
|
||||
logging.Log.Error(err)
|
||||
}
|
||||
|
||||
return len(errs) == 0
|
||||
}
|
||||
|
||||
// ValidateOnSaaS validates configuration
|
||||
func (c Config) ValidateOnSaaS() bool {
|
||||
saaserrs := c.Saas.Validate()
|
||||
for _, err := range saaserrs {
|
||||
logging.Log.Error("Failed to validate SaaS conf: %+w", err)
|
||||
}
|
||||
return len(saaserrs) == 0
|
||||
}
|
||||
|
||||
// WpScanConf is wpscan.com config
|
||||
type WpScanConf struct {
|
||||
Token string `toml:"token,omitempty" json:"-"`
|
||||
DetectInactive bool `toml:"detectInactive,omitempty" json:"detectInactive,omitempty"`
|
||||
}
|
||||
|
||||
// ServerInfo has SSH Info, additional CPE packages to scan.
|
||||
type ServerInfo struct {
|
||||
BaseName string `toml:"-" json:"-"`
|
||||
ServerName string `toml:"-" json:"serverName,omitempty"`
|
||||
User string `toml:"user,omitempty" json:"user,omitempty"`
|
||||
Host string `toml:"host,omitempty" json:"host,omitempty"`
|
||||
IgnoreIPAddresses []string `toml:"ignoreIPAddresses,omitempty" json:"ignoreIPAddresses,omitempty"`
|
||||
JumpServer []string `toml:"jumpServer,omitempty" json:"jumpServer,omitempty"`
|
||||
Port string `toml:"port,omitempty" json:"port,omitempty"`
|
||||
SSHConfigPath string `toml:"sshConfigPath,omitempty" json:"sshConfigPath,omitempty"`
|
||||
KeyPath string `toml:"keyPath,omitempty" json:"keyPath,omitempty"`
|
||||
CpeNames []string `toml:"cpeNames,omitempty" json:"cpeNames,omitempty"`
|
||||
ScanMode []string `toml:"scanMode,omitempty" json:"scanMode,omitempty"`
|
||||
ScanModules []string `toml:"scanModules,omitempty" json:"scanModules,omitempty"`
|
||||
OwaspDCXMLPath string `toml:"owaspDCXMLPath,omitempty" json:"owaspDCXMLPath,omitempty"`
|
||||
ContainersOnly bool `toml:"containersOnly,omitempty" json:"containersOnly,omitempty"`
|
||||
ContainersIncluded []string `toml:"containersIncluded,omitempty" json:"containersIncluded,omitempty"`
|
||||
ContainersExcluded []string `toml:"containersExcluded,omitempty" json:"containersExcluded,omitempty"`
|
||||
ContainerType string `toml:"containerType,omitempty" json:"containerType,omitempty"`
|
||||
Containers map[string]ContainerSetting `toml:"containers,omitempty" json:"containers,omitempty"`
|
||||
IgnoreCves []string `toml:"ignoreCves,omitempty" json:"ignoreCves,omitempty"`
|
||||
IgnorePkgsRegexp []string `toml:"ignorePkgsRegexp,omitempty" json:"ignorePkgsRegexp,omitempty"`
|
||||
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
|
||||
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"`
|
||||
FindLockDirs []string `toml:"findLockDirs,omitempty" json:"findLockDirs,omitempty"`
|
||||
Type string `toml:"type,omitempty" json:"type,omitempty"` // "pseudo" or ""
|
||||
IgnoredJSONKeys []string `toml:"ignoredJSONKeys,omitempty" json:"ignoredJSONKeys,omitempty"`
|
||||
WordPress *WordPressConf `toml:"wordpress,omitempty" json:"wordpress,omitempty"`
|
||||
PortScan *PortScanConf `toml:"portscan,omitempty" json:"portscan,omitempty"`
|
||||
Windows *WindowsConf `toml:"windows,omitempty" json:"windows,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:"-"`
|
||||
Distro Distro `toml:"-" json:"-"`
|
||||
Mode ScanMode `toml:"-" json:"-"`
|
||||
Module ScanModule `toml:"-" json:"-"`
|
||||
}
|
||||
|
||||
// ContainerSetting is used for loading container setting in config.toml
|
||||
type ContainerSetting struct {
|
||||
Cpes []string `json:"cpes,omitempty"`
|
||||
OwaspDCXMLPath string `json:"owaspDCXMLPath,omitempty"`
|
||||
IgnorePkgsRegexp []string `json:"ignorePkgsRegexp,omitempty"`
|
||||
IgnoreCves []string `json:"ignoreCves,omitempty"`
|
||||
}
|
||||
|
||||
// WordPressConf used for WordPress Scanning
|
||||
type WordPressConf struct {
|
||||
OSUser string `toml:"osUser,omitempty" json:"osUser,omitempty"`
|
||||
DocRoot string `toml:"docRoot,omitempty" json:"docRoot,omitempty"`
|
||||
CmdPath string `toml:"cmdPath,omitempty" json:"cmdPath,omitempty"`
|
||||
NoSudo bool `toml:"noSudo,omitempty" json:"noSudo,omitempty"`
|
||||
}
|
||||
|
||||
// IsZero return whether this struct is not specified in config.toml
|
||||
func (cnf WordPressConf) IsZero() bool {
|
||||
return cnf.OSUser == "" && cnf.DocRoot == "" && cnf.CmdPath == ""
|
||||
}
|
||||
|
||||
// GitHubConf is used for GitHub Security Alerts
|
||||
type GitHubConf struct {
|
||||
Token string `json:"-"`
|
||||
IgnoreGitHubDismissed bool `json:"ignoreGitHubDismissed,omitempty"`
|
||||
}
|
||||
|
||||
// GetServerName returns ServerName if this serverInfo is about host.
|
||||
// If this serverInfo is about a container, returns containerID@ServerName
|
||||
func (s ServerInfo) GetServerName() string {
|
||||
if len(s.Container.ContainerID) == 0 {
|
||||
return s.ServerName
|
||||
}
|
||||
return fmt.Sprintf("%s@%s", s.Container.Name, s.ServerName)
|
||||
}
|
||||
|
||||
// Distro has distribution info
|
||||
type Distro struct {
|
||||
Family string
|
||||
Release string
|
||||
}
|
||||
|
||||
func (l Distro) String() string {
|
||||
return fmt.Sprintf("%s %s", l.Family, l.Release)
|
||||
}
|
||||
|
||||
// MajorVersion returns Major version
|
||||
func (l Distro) MajorVersion() (int, error) {
|
||||
switch l.Family {
|
||||
case constant.Amazon:
|
||||
return strconv.Atoi(getAmazonLinuxVersion(l.Release))
|
||||
case constant.CentOS:
|
||||
if 0 < len(l.Release) {
|
||||
return strconv.Atoi(strings.Split(strings.TrimPrefix(l.Release, "stream"), ".")[0])
|
||||
}
|
||||
case constant.OpenSUSE:
|
||||
if l.Release != "" {
|
||||
if l.Release == "tumbleweed" {
|
||||
return 0, nil
|
||||
}
|
||||
return strconv.Atoi(strings.Split(l.Release, ".")[0])
|
||||
}
|
||||
default:
|
||||
if 0 < len(l.Release) {
|
||||
return strconv.Atoi(strings.Split(l.Release, ".")[0])
|
||||
}
|
||||
}
|
||||
return 0, xerrors.New("Release is empty")
|
||||
}
|
||||
|
||||
// IsContainer returns whether this ServerInfo is about container
|
||||
func (s ServerInfo) IsContainer() bool {
|
||||
return 0 < len(s.Container.ContainerID)
|
||||
}
|
||||
|
||||
// SetContainer set container
|
||||
func (s *ServerInfo) SetContainer(d Container) {
|
||||
s.Container = d
|
||||
}
|
||||
|
||||
// Container has Container information.
|
||||
type Container struct {
|
||||
ContainerID string
|
||||
Name string
|
||||
Image string
|
||||
}
|
||||
110
config/os.go
110
config/os.go
@@ -41,8 +41,12 @@ func GetEOL(family, release string) (eol EOL, found bool) {
|
||||
case constant.Amazon:
|
||||
eol, found = map[string]EOL{
|
||||
"1": {StandardSupportUntil: time.Date(2023, 6, 30, 23, 59, 59, 0, time.UTC)},
|
||||
"2": {StandardSupportUntil: time.Date(2024, 6, 30, 23, 59, 59, 0, time.UTC)},
|
||||
"2": {StandardSupportUntil: time.Date(2025, 6, 30, 23, 59, 59, 0, time.UTC)},
|
||||
"2022": {StandardSupportUntil: time.Date(2026, 6, 30, 23, 59, 59, 0, time.UTC)},
|
||||
"2023": {StandardSupportUntil: time.Date(2027, 6, 30, 23, 59, 59, 0, time.UTC)},
|
||||
"2025": {StandardSupportUntil: time.Date(2029, 6, 30, 23, 59, 59, 0, time.UTC)},
|
||||
"2027": {StandardSupportUntil: time.Date(2031, 6, 30, 23, 59, 59, 0, time.UTC)},
|
||||
"2029": {StandardSupportUntil: time.Date(2033, 6, 30, 23, 59, 59, 0, time.UTC)},
|
||||
}[getAmazonLinuxVersion(release)]
|
||||
case constant.RedHat:
|
||||
// https://access.redhat.com/support/policy/updates/errata
|
||||
@@ -311,6 +315,88 @@ func GetEOL(family, release string) (eol EOL, found bool) {
|
||||
"36": {StandardSupportUntil: time.Date(2023, 5, 16, 23, 59, 59, 0, time.UTC)},
|
||||
"37": {StandardSupportUntil: time.Date(2023, 12, 15, 23, 59, 59, 0, time.UTC)},
|
||||
}[major(release)]
|
||||
case constant.Windows:
|
||||
// https://learn.microsoft.com/ja-jp/lifecycle/products/?products=windows
|
||||
|
||||
lhs, rhs, _ := strings.Cut(strings.TrimSuffix(release, "(Server Core installation)"), "for")
|
||||
switch strings.TrimSpace(lhs) {
|
||||
case "Windows 7":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2013, 4, 9, 23, 59, 59, 0, time.UTC)}, true
|
||||
if strings.Contains(rhs, "Service Pack 1") {
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2020, 1, 14, 23, 59, 59, 0, time.UTC)}, true
|
||||
}
|
||||
case "Windows 8":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2016, 1, 12, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows 8.1":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2023, 1, 10, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows 10":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2017, 5, 9, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows 10 Version 1511":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2017, 10, 10, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows 10 Version 1607":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2018, 4, 10, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows 10 Version 1703":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2018, 10, 9, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows 10 Version 1709":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2019, 4, 9, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows 10 Version 1803":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2019, 11, 12, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows 10 Version 1809":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2020, 11, 10, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows 10 Version 1903":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2020, 12, 8, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows 10 Version 1909":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2021, 5, 11, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows 10 Version 2004":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2021, 12, 14, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows 10 Version 20H2":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2022, 5, 10, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows 10 Version 21H1":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2022, 12, 13, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows 10 Version 21H2":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2023, 6, 13, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows 10 Version 22H2":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2024, 5, 14, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows 11 Version 21H2":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2024, 10, 8, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows 11 Version 22H2":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2025, 10, 14, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows Server 2008":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2011, 7, 12, 23, 59, 59, 0, time.UTC)}, true
|
||||
if strings.Contains(rhs, "Service Pack 2") {
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2020, 1, 14, 23, 59, 59, 0, time.UTC)}, true
|
||||
}
|
||||
case "Windows Server 2008 R2":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2013, 4, 9, 23, 59, 59, 0, time.UTC)}, true
|
||||
if strings.Contains(rhs, "Service Pack 1") {
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2020, 1, 14, 23, 59, 59, 0, time.UTC)}, true
|
||||
}
|
||||
case "Windows Server 2012":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2023, 10, 10, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows Server 2012 R2":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2023, 10, 10, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows Server 2016":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2027, 1, 12, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows Server, Version 1709":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2019, 4, 9, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows Server, Version 1803":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2019, 11, 12, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows Server, Version 1809":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2020, 11, 10, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows Server 2019":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2029, 1, 9, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows Server, Version 1903":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2020, 12, 8, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows Server, Version 1909":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2021, 5, 11, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows Server, Version 2004":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2021, 12, 14, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows Server, Version 20H2":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2022, 8, 9, 23, 59, 59, 0, time.UTC)}, true
|
||||
case "Windows Server 2022":
|
||||
eol, found = EOL{StandardSupportUntil: time.Date(2031, 10, 14, 23, 59, 59, 0, time.UTC)}, true
|
||||
default:
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -328,9 +414,25 @@ func majorDotMinor(osVer string) (majorDotMinor string) {
|
||||
}
|
||||
|
||||
func getAmazonLinuxVersion(osRelease string) string {
|
||||
ss := strings.Fields(osRelease)
|
||||
if len(ss) == 1 {
|
||||
switch s := strings.Fields(osRelease)[0]; s {
|
||||
case "1":
|
||||
return "1"
|
||||
case "2":
|
||||
return "2"
|
||||
case "2022":
|
||||
return "2022"
|
||||
case "2023":
|
||||
return "2023"
|
||||
case "2025":
|
||||
return "2025"
|
||||
case "2027":
|
||||
return "2027"
|
||||
case "2029":
|
||||
return "2029"
|
||||
default:
|
||||
if _, err := time.Parse("2006.01", s); err == nil {
|
||||
return "1"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
return ss[0]
|
||||
}
|
||||
|
||||
@@ -54,8 +54,16 @@ func TestEOL_IsStandardSupportEnded(t *testing.T) {
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "amazon linux 2024 not found",
|
||||
fields: fields{family: Amazon, release: "2024 (Amazon Linux)"},
|
||||
name: "amazon linux 2023 supported",
|
||||
fields: fields{family: Amazon, release: "2023"},
|
||||
now: time.Date(2023, 7, 1, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "amazon linux 2031 not found",
|
||||
fields: fields{family: Amazon, release: "2031"},
|
||||
now: time.Date(2023, 7, 1, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
@@ -347,6 +355,14 @@ func TestEOL_IsStandardSupportEnded(t *testing.T) {
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
},
|
||||
// {
|
||||
// name: "Ubuntu 23.04 supported",
|
||||
// fields: fields{family: Ubuntu, release: "23.04"},
|
||||
// now: time.Date(2023, 3, 16, 23, 59, 59, 0, time.UTC),
|
||||
// found: true,
|
||||
// stdEnded: false,
|
||||
// extEnded: false,
|
||||
// },
|
||||
//Debian
|
||||
{
|
||||
name: "Debian 9 supported",
|
||||
@@ -607,6 +623,22 @@ func TestEOL_IsStandardSupportEnded(t *testing.T) {
|
||||
extEnded: false,
|
||||
found: false,
|
||||
},
|
||||
{
|
||||
name: "Windows 10 EOL",
|
||||
fields: fields{family: Windows, release: "Windows 10 for x64-based Systems"},
|
||||
now: time.Date(2022, 12, 8, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: true,
|
||||
extEnded: true,
|
||||
found: true,
|
||||
},
|
||||
{
|
||||
name: "Windows 10 Version 22H2 supported",
|
||||
fields: fields{family: Windows, release: "Windows 10 Version 22H2 for x64-based Systems"},
|
||||
now: time.Date(2022, 12, 8, 23, 59, 59, 0, time.UTC),
|
||||
stdEnded: false,
|
||||
extEnded: false,
|
||||
found: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
@@ -672,3 +704,58 @@ func Test_majorDotMinor(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_getAmazonLinuxVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
release string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
release: "2017.09",
|
||||
want: "1",
|
||||
},
|
||||
{
|
||||
release: "2018.03",
|
||||
want: "1",
|
||||
},
|
||||
{
|
||||
release: "1",
|
||||
want: "1",
|
||||
},
|
||||
{
|
||||
release: "2",
|
||||
want: "2",
|
||||
},
|
||||
{
|
||||
release: "2022",
|
||||
want: "2022",
|
||||
},
|
||||
{
|
||||
release: "2023",
|
||||
want: "2023",
|
||||
},
|
||||
{
|
||||
release: "2025",
|
||||
want: "2025",
|
||||
},
|
||||
{
|
||||
release: "2027",
|
||||
want: "2027",
|
||||
},
|
||||
{
|
||||
release: "2029",
|
||||
want: "2029",
|
||||
},
|
||||
{
|
||||
release: "2031",
|
||||
want: "unknown",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.release, func(t *testing.T) {
|
||||
if got := getAmazonLinuxVersion(tt.release); got != tt.want {
|
||||
t.Errorf("getAmazonLinuxVersion() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build !windows
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
|
||||
@@ -294,6 +294,13 @@ func setDefaultIfEmpty(server *ServerInfo) error {
|
||||
}
|
||||
}
|
||||
|
||||
if server.Windows == nil {
|
||||
server.Windows = Conf.Default.Windows
|
||||
if server.Windows == nil {
|
||||
server.Windows = &WindowsConf{}
|
||||
}
|
||||
}
|
||||
|
||||
if len(server.IgnoredJSONKeys) == 0 {
|
||||
server.IgnoredJSONKeys = Conf.Default.IgnoredJSONKeys
|
||||
}
|
||||
|
||||
27
config/windows.go
Normal file
27
config/windows.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// WindowsConf used for Windows Update Setting
|
||||
type WindowsConf struct {
|
||||
ServerSelection int `toml:"serverSelection,omitempty" json:"serverSelection,omitempty"`
|
||||
CabPath string `toml:"cabPath,omitempty" json:"cabPath,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates configuration
|
||||
func (c *WindowsConf) Validate() []error {
|
||||
switch c.ServerSelection {
|
||||
case 0, 1, 2:
|
||||
case 3:
|
||||
if _, err := os.Stat(c.CabPath); err != nil {
|
||||
return []error{xerrors.Errorf("%s does not exist. err: %w", c.CabPath, err)}
|
||||
}
|
||||
default:
|
||||
return []error{xerrors.Errorf("ServerSelection: %d does not support . Reference: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-uamg/07e2bfa4-6795-4189-b007-cc50b476181a", c.ServerSelection)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -11,7 +11,8 @@ COPY . $GOPATH/src/$REPOSITORY
|
||||
RUN cd $GOPATH/src/$REPOSITORY && \
|
||||
make build-scanner && mv vuls $GOPATH/bin && \
|
||||
make build-trivy-to-vuls && mv trivy-to-vuls $GOPATH/bin && \
|
||||
make build-future-vuls && mv future-vuls $GOPATH/bin
|
||||
make build-future-vuls && mv future-vuls $GOPATH/bin && \
|
||||
make build-snmp2cpe && mv snmp2cpe $GOPATH/bin
|
||||
|
||||
FROM alpine:3.15
|
||||
|
||||
@@ -25,7 +26,7 @@ RUN apk add --no-cache \
|
||||
nmap \
|
||||
&& mkdir -p $WORKDIR $LOGDIR
|
||||
|
||||
COPY --from=builder /go/bin/vuls /go/bin/trivy-to-vuls /go/bin/future-vuls /usr/local/bin/
|
||||
COPY --from=builder /go/bin/vuls /go/bin/trivy-to-vuls /go/bin/future-vuls /go/bin/snmp2cpe /usr/local/bin/
|
||||
COPY --from=aquasec/trivy:latest /usr/local/bin/trivy /usr/local/bin/trivy
|
||||
|
||||
VOLUME ["$WORKDIR", "$LOGDIR"]
|
||||
|
||||
50
contrib/snmp2cpe/README.md
Normal file
50
contrib/snmp2cpe/README.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# snmp2cpe
|
||||
|
||||
## Main Features
|
||||
|
||||
- Estimate hardware and OS CPE from SNMP reply of network devices
|
||||
|
||||
## Installation
|
||||
|
||||
```console
|
||||
$ git clone https://github.com/future-architect/vuls.git
|
||||
$ make build-snmp2cpe
|
||||
```
|
||||
|
||||
## Command Reference
|
||||
|
||||
```console
|
||||
$ snmp2cpe help
|
||||
snmp2cpe: SNMP reply To CPE
|
||||
|
||||
Usage:
|
||||
snmp2cpe [command]
|
||||
|
||||
Available Commands:
|
||||
completion Generate the autocompletion script for the specified shell
|
||||
convert snmpget reply to CPE
|
||||
help Help about any command
|
||||
v1 snmpget with SNMPv1
|
||||
v2c snmpget with SNMPv2c
|
||||
v3 snmpget with SNMPv3
|
||||
version Print the version
|
||||
|
||||
Flags:
|
||||
-h, --help help for snmp2cpe
|
||||
|
||||
Use "snmp2cpe [command] --help" for more information about a command.
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```console
|
||||
$ snmp2cpe v2c --debug 192.168.1.99 public
|
||||
2023/03/28 14:16:54 DEBUG: .1.3.6.1.2.1.1.1.0 ->
|
||||
2023/03/28 14:16:54 DEBUG: .1.3.6.1.2.1.47.1.1.1.1.12.1 -> Fortinet
|
||||
2023/03/28 14:16:54 DEBUG: .1.3.6.1.2.1.47.1.1.1.1.7.1 -> FGT_50E
|
||||
2023/03/28 14:16:54 DEBUG: .1.3.6.1.2.1.47.1.1.1.1.10.1 -> FortiGate-50E v5.4.6,build1165b1165,171018 (GA)
|
||||
{"192.168.1.99":{"entPhysicalTables":{"1":{"entPhysicalMfgName":"Fortinet","entPhysicalName":"FGT_50E","entPhysicalSoftwareRev":"FortiGate-50E v5.4.6,build1165b1165,171018 (GA)"}}}}
|
||||
|
||||
$ snmp2cpe v2c 192.168.1.99 public | snmp2cpe convert
|
||||
{"192.168.1.99":["cpe:2.3:h:fortinet:fortigate-50e:-:*:*:*:*:*:*:*","cpe:2.3:o:fortinet:fortios:5.4.6:*:*:*:*:*:*:*"]}
|
||||
```
|
||||
15
contrib/snmp2cpe/cmd/main.go
Normal file
15
contrib/snmp2cpe/cmd/main.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
rootCmd "github.com/future-architect/vuls/contrib/snmp2cpe/pkg/cmd/root"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if err := rootCmd.NewCmdRoot().Execute(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to exec snmp2cpe: %s\n", fmt.Sprintf("%+v", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
52
contrib/snmp2cpe/pkg/cmd/convert/convert.go
Normal file
52
contrib/snmp2cpe/pkg/cmd/convert/convert.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package convert
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/future-architect/vuls/contrib/snmp2cpe/pkg/cpe"
|
||||
"github.com/future-architect/vuls/contrib/snmp2cpe/pkg/snmp"
|
||||
)
|
||||
|
||||
// NewCmdConvert ...
|
||||
func NewCmdConvert() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "convert",
|
||||
Short: "snmpget reply to CPE",
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
Example: `$ snmp2cpe v2c 192.168.11.11 public | snmp2cpe convert
|
||||
$ snmp2cpe v2c 192.168.11.11 public | snmp2cpe convert -
|
||||
$ snmp2cpe v2c 192.168.11.11 public > v2c.json && snmp2cpe convert v2c.json`,
|
||||
RunE: func(_ *cobra.Command, args []string) error {
|
||||
r := os.Stdin
|
||||
if len(args) == 1 && args[0] != "-" {
|
||||
f, err := os.Open(args[0])
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to open %s", args[0])
|
||||
}
|
||||
defer f.Close()
|
||||
r = f
|
||||
}
|
||||
|
||||
var reply map[string]snmp.Result
|
||||
if err := json.NewDecoder(r).Decode(&reply); err != nil {
|
||||
return errors.Wrap(err, "failed to decode")
|
||||
}
|
||||
|
||||
converted := map[string][]string{}
|
||||
for ipaddr, res := range reply {
|
||||
converted[ipaddr] = cpe.Convert(res)
|
||||
}
|
||||
|
||||
if err := json.NewEncoder(os.Stdout).Encode(converted); err != nil {
|
||||
return errors.Wrap(err, "failed to encode")
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
30
contrib/snmp2cpe/pkg/cmd/root/root.go
Normal file
30
contrib/snmp2cpe/pkg/cmd/root/root.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package root
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
convertCmd "github.com/future-architect/vuls/contrib/snmp2cpe/pkg/cmd/convert"
|
||||
v1Cmd "github.com/future-architect/vuls/contrib/snmp2cpe/pkg/cmd/v1"
|
||||
v2cCmd "github.com/future-architect/vuls/contrib/snmp2cpe/pkg/cmd/v2c"
|
||||
v3Cmd "github.com/future-architect/vuls/contrib/snmp2cpe/pkg/cmd/v3"
|
||||
versionCmd "github.com/future-architect/vuls/contrib/snmp2cpe/pkg/cmd/version"
|
||||
)
|
||||
|
||||
// NewCmdRoot ...
|
||||
func NewCmdRoot() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "snmp2cpe <command>",
|
||||
Short: "snmp2cpe",
|
||||
Long: "snmp2cpe: SNMP reply To CPE",
|
||||
SilenceErrors: true,
|
||||
SilenceUsage: true,
|
||||
}
|
||||
|
||||
cmd.AddCommand(v1Cmd.NewCmdV1())
|
||||
cmd.AddCommand(v2cCmd.NewCmdV2c())
|
||||
cmd.AddCommand(v3Cmd.NewCmdV3())
|
||||
cmd.AddCommand(convertCmd.NewCmdConvert())
|
||||
cmd.AddCommand(versionCmd.NewCmdVersion())
|
||||
|
||||
return cmd
|
||||
}
|
||||
47
contrib/snmp2cpe/pkg/cmd/v1/v1.go
Normal file
47
contrib/snmp2cpe/pkg/cmd/v1/v1.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
"github.com/gosnmp/gosnmp"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/future-architect/vuls/contrib/snmp2cpe/pkg/snmp"
|
||||
)
|
||||
|
||||
// SNMPv1Options ...
|
||||
type SNMPv1Options struct {
|
||||
Debug bool
|
||||
}
|
||||
|
||||
// NewCmdV1 ...
|
||||
func NewCmdV1() *cobra.Command {
|
||||
opts := &SNMPv1Options{
|
||||
Debug: false,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "v1 <IP Address> <Community>",
|
||||
Short: "snmpget with SNMPv1",
|
||||
Example: "$ snmp2cpe v1 192.168.100.1 public",
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(_ *cobra.Command, args []string) error {
|
||||
r, err := snmp.Get(gosnmp.Version1, args[0], snmp.WithCommunity(args[1]), snmp.WithDebug(opts.Debug))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to snmpget")
|
||||
}
|
||||
|
||||
if err := json.NewEncoder(os.Stdout).Encode(map[string]snmp.Result{args[0]: r}); err != nil {
|
||||
return errors.Wrap(err, "failed to encode")
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().BoolVarP(&opts.Debug, "debug", "", false, "debug mode")
|
||||
|
||||
return cmd
|
||||
}
|
||||
47
contrib/snmp2cpe/pkg/cmd/v2c/v2c.go
Normal file
47
contrib/snmp2cpe/pkg/cmd/v2c/v2c.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package v2c
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
"github.com/gosnmp/gosnmp"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/future-architect/vuls/contrib/snmp2cpe/pkg/snmp"
|
||||
)
|
||||
|
||||
// SNMPv2cOptions ...
|
||||
type SNMPv2cOptions struct {
|
||||
Debug bool
|
||||
}
|
||||
|
||||
// NewCmdV2c ...
|
||||
func NewCmdV2c() *cobra.Command {
|
||||
opts := &SNMPv2cOptions{
|
||||
Debug: false,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "v2c <IP Address> <Community>",
|
||||
Short: "snmpget with SNMPv2c",
|
||||
Example: "$ snmp2cpe v2c 192.168.100.1 public",
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(_ *cobra.Command, args []string) error {
|
||||
r, err := snmp.Get(gosnmp.Version2c, args[0], snmp.WithCommunity(args[1]), snmp.WithDebug(opts.Debug))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to snmpget")
|
||||
}
|
||||
|
||||
if err := json.NewEncoder(os.Stdout).Encode(map[string]snmp.Result{args[0]: r}); err != nil {
|
||||
return errors.Wrap(err, "failed to encode")
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().BoolVarP(&opts.Debug, "debug", "", false, "debug mode")
|
||||
|
||||
return cmd
|
||||
}
|
||||
39
contrib/snmp2cpe/pkg/cmd/v3/v3.go
Normal file
39
contrib/snmp2cpe/pkg/cmd/v3/v3.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package v3
|
||||
|
||||
import (
|
||||
"github.com/gosnmp/gosnmp"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/future-architect/vuls/contrib/snmp2cpe/pkg/snmp"
|
||||
)
|
||||
|
||||
// SNMPv3Options ...
|
||||
type SNMPv3Options struct {
|
||||
Debug bool
|
||||
}
|
||||
|
||||
// NewCmdV3 ...
|
||||
func NewCmdV3() *cobra.Command {
|
||||
opts := &SNMPv3Options{
|
||||
Debug: false,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "v3 <args>",
|
||||
Short: "snmpget with SNMPv3",
|
||||
Example: "$ snmp2cpe v3",
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
_, err := snmp.Get(gosnmp.Version3, "", snmp.WithDebug(opts.Debug))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to snmpget")
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().BoolVarP(&opts.Debug, "debug", "", false, "debug mode")
|
||||
|
||||
return cmd
|
||||
}
|
||||
23
contrib/snmp2cpe/pkg/cmd/version/version.go
Normal file
23
contrib/snmp2cpe/pkg/cmd/version/version.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package version
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
)
|
||||
|
||||
// NewCmdVersion ...
|
||||
func NewCmdVersion() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Print the version",
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(_ *cobra.Command, _ []string) {
|
||||
fmt.Fprintf(os.Stdout, "snmp2cpe %s %s\n", config.Version, config.Revision)
|
||||
},
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
212
contrib/snmp2cpe/pkg/cpe/cpe.go
Normal file
212
contrib/snmp2cpe/pkg/cpe/cpe.go
Normal file
@@ -0,0 +1,212 @@
|
||||
package cpe
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
|
||||
"github.com/future-architect/vuls/contrib/snmp2cpe/pkg/snmp"
|
||||
"github.com/future-architect/vuls/contrib/snmp2cpe/pkg/util"
|
||||
)
|
||||
|
||||
// Convert ...
|
||||
func Convert(result snmp.Result) []string {
|
||||
var cpes []string
|
||||
|
||||
switch detectVendor(result) {
|
||||
case "Cisco":
|
||||
var p, v string
|
||||
lhs, _, _ := strings.Cut(result.SysDescr0, " RELEASE SOFTWARE")
|
||||
for _, s := range strings.Split(lhs, ",") {
|
||||
s = strings.TrimSpace(s)
|
||||
switch {
|
||||
case strings.Contains(s, "Cisco NX-OS"):
|
||||
p = "nx-os"
|
||||
case strings.Contains(s, "Cisco IOS Software"), strings.Contains(s, "Cisco Internetwork Operating System Software IOS"):
|
||||
p = "ios"
|
||||
if strings.Contains(lhs, "IOSXE") || strings.Contains(lhs, "IOS-XE") {
|
||||
p = "ios_xe"
|
||||
}
|
||||
case strings.HasPrefix(s, "Version "):
|
||||
v = strings.ToLower(strings.TrimPrefix(s, "Version "))
|
||||
}
|
||||
}
|
||||
if p != "" && v != "" {
|
||||
cpes = append(cpes, fmt.Sprintf("cpe:2.3:o:cisco:%s:%s:*:*:*:*:*:*:*", p, v))
|
||||
}
|
||||
|
||||
if t, ok := result.EntPhysicalTables[1]; ok {
|
||||
if t.EntPhysicalName != "" {
|
||||
cpes = append(cpes, fmt.Sprintf("cpe:2.3:h:cisco:%s:-:*:*:*:*:*:*:*", strings.ToLower(t.EntPhysicalName)))
|
||||
}
|
||||
if p != "" && t.EntPhysicalSoftwareRev != "" {
|
||||
s, _, _ := strings.Cut(t.EntPhysicalSoftwareRev, " RELEASE SOFTWARE")
|
||||
cpes = append(cpes, fmt.Sprintf("cpe:2.3:o:cisco:%s:%s:*:*:*:*:*:*:*", p, strings.ToLower(strings.TrimSuffix(s, ","))))
|
||||
}
|
||||
}
|
||||
case "Juniper Networks":
|
||||
if strings.HasPrefix(result.SysDescr0, "Juniper Networks, Inc.") {
|
||||
for _, s := range strings.Split(strings.TrimPrefix(result.SysDescr0, "Juniper Networks, Inc. "), ",") {
|
||||
s = strings.TrimSpace(s)
|
||||
switch {
|
||||
case strings.HasPrefix(s, "qfx"), strings.HasPrefix(s, "ex"), strings.HasPrefix(s, "mx"), strings.HasPrefix(s, "ptx"), strings.HasPrefix(s, "acx"), strings.HasPrefix(s, "bti"), strings.HasPrefix(s, "srx"):
|
||||
cpes = append(cpes, fmt.Sprintf("cpe:2.3:h:juniper:%s:-:*:*:*:*:*:*:*", strings.Fields(s)[0]))
|
||||
case strings.HasPrefix(s, "kernel JUNOS "):
|
||||
cpes = append(cpes, fmt.Sprintf("cpe:2.3:o:juniper:junos:%s:*:*:*:*:*:*:*", strings.ToLower(strings.Fields(strings.TrimPrefix(s, "kernel JUNOS "))[0])))
|
||||
}
|
||||
}
|
||||
|
||||
if t, ok := result.EntPhysicalTables[1]; ok {
|
||||
if t.EntPhysicalSoftwareRev != "" {
|
||||
cpes = append(cpes, fmt.Sprintf("cpe:2.3:o:juniper:junos:%s:*:*:*:*:*:*:*", strings.ToLower(t.EntPhysicalSoftwareRev)))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
h, v, ok := strings.Cut(result.SysDescr0, " version ")
|
||||
if ok {
|
||||
cpes = append(cpes,
|
||||
fmt.Sprintf("cpe:2.3:h:juniper:%s:-:*:*:*:*:*:*:*", strings.ToLower(h)),
|
||||
fmt.Sprintf("cpe:2.3:o:juniper:screenos:%s:*:*:*:*:*:*:*", strings.ToLower(strings.Fields(v)[0])),
|
||||
)
|
||||
}
|
||||
}
|
||||
case "Arista Networks":
|
||||
v, h, ok := strings.Cut(result.SysDescr0, " running on an ")
|
||||
if ok {
|
||||
if strings.HasPrefix(v, "Arista Networks EOS version ") {
|
||||
cpes = append(cpes, fmt.Sprintf("cpe:2.3:o:arista:eos:%s:*:*:*:*:*:*:*", strings.ToLower(strings.TrimPrefix(v, "Arista Networks EOS version "))))
|
||||
}
|
||||
cpes = append(cpes, fmt.Sprintf("cpe:/h:arista:%s:-:*:*:*:*:*:*:*", strings.ToLower(strings.TrimPrefix(h, "Arista Networks "))))
|
||||
}
|
||||
if t, ok := result.EntPhysicalTables[1]; ok {
|
||||
if t.EntPhysicalSoftwareRev != "" {
|
||||
cpes = append(cpes, fmt.Sprintf("cpe:2.3:o:arista:eos:%s:*:*:*:*:*:*:*", strings.ToLower(t.EntPhysicalSoftwareRev)))
|
||||
}
|
||||
}
|
||||
case "Fortinet":
|
||||
if t, ok := result.EntPhysicalTables[1]; ok {
|
||||
if strings.HasPrefix(t.EntPhysicalName, "FGT_") {
|
||||
cpes = append(cpes, fmt.Sprintf("cpe:2.3:h:fortinet:fortigate-%s:-:*:*:*:*:*:*:*", strings.ToLower(strings.TrimPrefix(t.EntPhysicalName, "FGT_"))))
|
||||
}
|
||||
for _, s := range strings.Fields(t.EntPhysicalSoftwareRev) {
|
||||
switch {
|
||||
case strings.HasPrefix(s, "FortiGate-"):
|
||||
cpes = append(cpes, fmt.Sprintf("cpe:2.3:h:fortinet:%s:-:*:*:*:*:*:*:*", strings.ToLower(s)))
|
||||
case strings.HasPrefix(s, "v") && strings.Contains(s, "build"):
|
||||
if v, _, found := strings.Cut(strings.TrimPrefix(s, "v"), ",build"); found {
|
||||
if _, err := version.NewVersion(v); err == nil {
|
||||
cpes = append(cpes, fmt.Sprintf("cpe:2.3:o:fortinet:fortios:%s:*:*:*:*:*:*:*", v))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case "YAMAHA":
|
||||
var h, v string
|
||||
for _, s := range strings.Fields(result.SysDescr0) {
|
||||
switch {
|
||||
case strings.HasPrefix(s, "RTX"), strings.HasPrefix(s, "NVR"), strings.HasPrefix(s, "RTV"), strings.HasPrefix(s, "RT"),
|
||||
strings.HasPrefix(s, "SRT"), strings.HasPrefix(s, "FWX"), strings.HasPrefix(s, "YSL-V810"):
|
||||
h = strings.ToLower(s)
|
||||
case strings.HasPrefix(s, "Rev."):
|
||||
if _, err := version.NewVersion(strings.TrimPrefix(s, "Rev.")); err == nil {
|
||||
v = strings.TrimPrefix(s, "Rev.")
|
||||
}
|
||||
}
|
||||
}
|
||||
if h != "" {
|
||||
cpes = append(cpes, fmt.Sprintf("cpe:2.3:h:yamaha:%s:-:*:*:*:*:*:*:*", h))
|
||||
if v != "" {
|
||||
cpes = append(cpes, fmt.Sprintf("cpe:2.3:o:yamaha:%s:%s:*:*:*:*:*:*:*", h, v))
|
||||
}
|
||||
}
|
||||
case "NEC":
|
||||
var h, v string
|
||||
for _, s := range strings.Split(result.SysDescr0, ",") {
|
||||
s = strings.TrimSpace(s)
|
||||
switch {
|
||||
case strings.HasPrefix(s, "IX Series "):
|
||||
h = strings.ToLower(strings.TrimSuffix(strings.TrimPrefix(s, "IX Series "), " (magellan-sec) Software"))
|
||||
case strings.HasPrefix(s, "Version "):
|
||||
if _, err := version.NewVersion(strings.TrimSpace(strings.TrimPrefix(s, "Version "))); err == nil {
|
||||
v = strings.TrimSpace(strings.TrimPrefix(s, "Version "))
|
||||
}
|
||||
}
|
||||
}
|
||||
if h != "" {
|
||||
cpes = append(cpes, fmt.Sprintf("cpe:2.3:h:nec:%s:-:*:*:*:*:*:*:*", h))
|
||||
if v != "" {
|
||||
cpes = append(cpes, fmt.Sprintf("cpe:2.3:o:nec:%s:%s:*:*:*:*:*:*:*", h, v))
|
||||
}
|
||||
}
|
||||
case "Palo Alto Networks":
|
||||
if t, ok := result.EntPhysicalTables[1]; ok {
|
||||
if t.EntPhysicalName != "" {
|
||||
cpes = append(cpes, fmt.Sprintf("cpe:2.3:h:paloaltonetworks:%s:-:*:*:*:*:*:*:*", strings.ToLower(t.EntPhysicalName)))
|
||||
}
|
||||
if t.EntPhysicalSoftwareRev != "" {
|
||||
cpes = append(cpes, fmt.Sprintf("cpe:2.3:o:paloaltonetworks:pan-os:%s:*:*:*:*:*:*:*", t.EntPhysicalSoftwareRev))
|
||||
}
|
||||
}
|
||||
default:
|
||||
return []string{}
|
||||
}
|
||||
|
||||
return util.Unique(cpes)
|
||||
}
|
||||
|
||||
func detectVendor(r snmp.Result) string {
|
||||
if t, ok := r.EntPhysicalTables[1]; ok {
|
||||
switch t.EntPhysicalMfgName {
|
||||
case "Cisco":
|
||||
return "Cisco"
|
||||
case "Juniper Networks":
|
||||
return "Juniper Networks"
|
||||
case "Arista Networks":
|
||||
return "Arista Networks"
|
||||
case "Fortinet":
|
||||
return "Fortinet"
|
||||
case "YAMAHA":
|
||||
return "YAMAHA"
|
||||
case "NEC":
|
||||
return "NEC"
|
||||
case "Palo Alto Networks":
|
||||
return "Palo Alto Networks"
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
case strings.Contains(r.SysDescr0, "Cisco"):
|
||||
return "Cisco"
|
||||
case strings.Contains(r.SysDescr0, "Juniper Networks"),
|
||||
strings.Contains(r.SysDescr0, "SSG5"), strings.Contains(r.SysDescr0, "SSG20"), strings.Contains(r.SysDescr0, "SSG140"),
|
||||
strings.Contains(r.SysDescr0, "SSG320"), strings.Contains(r.SysDescr0, "SSG350"), strings.Contains(r.SysDescr0, "SSG520"),
|
||||
strings.Contains(r.SysDescr0, "SSG550"):
|
||||
return "Juniper Networks"
|
||||
case strings.Contains(r.SysDescr0, "Arista Networks"):
|
||||
return "Arista Networks"
|
||||
case strings.Contains(r.SysDescr0, "Fortinet"), strings.Contains(r.SysDescr0, "FortiGate"):
|
||||
return "Fortinet"
|
||||
case strings.Contains(r.SysDescr0, "YAMAHA"),
|
||||
strings.Contains(r.SysDescr0, "RTX810"), strings.Contains(r.SysDescr0, "RTX830"),
|
||||
strings.Contains(r.SysDescr0, "RTX1000"), strings.Contains(r.SysDescr0, "RTX1100"),
|
||||
strings.Contains(r.SysDescr0, "RTX1200"), strings.Contains(r.SysDescr0, "RTX1210"), strings.Contains(r.SysDescr0, "RTX1220"),
|
||||
strings.Contains(r.SysDescr0, "RTX1300"), strings.Contains(r.SysDescr0, "RTX1500"), strings.Contains(r.SysDescr0, "RTX2000"),
|
||||
strings.Contains(r.SysDescr0, "RTX3000"), strings.Contains(r.SysDescr0, "RTX3500"), strings.Contains(r.SysDescr0, "RTX5000"),
|
||||
strings.Contains(r.SysDescr0, "NVR500"), strings.Contains(r.SysDescr0, "NVR510"), strings.Contains(r.SysDescr0, "NVR700W"),
|
||||
strings.Contains(r.SysDescr0, "RTV01"), strings.Contains(r.SysDescr0, "RTV700"),
|
||||
strings.Contains(r.SysDescr0, "RT105i"), strings.Contains(r.SysDescr0, "RT105p"), strings.Contains(r.SysDescr0, "RT105e"),
|
||||
strings.Contains(r.SysDescr0, "RT107e"), strings.Contains(r.SysDescr0, "RT250i"), strings.Contains(r.SysDescr0, "RT300i"),
|
||||
strings.Contains(r.SysDescr0, "SRT100"),
|
||||
strings.Contains(r.SysDescr0, "FWX100"),
|
||||
strings.Contains(r.SysDescr0, "YSL-V810"):
|
||||
return "YAMAHA"
|
||||
case strings.Contains(r.SysDescr0, "NEC"):
|
||||
return "NEC"
|
||||
case strings.Contains(r.SysDescr0, "Palo Alto Networks"):
|
||||
return "Palo Alto Networks"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
244
contrib/snmp2cpe/pkg/cpe/cpe_test.go
Normal file
244
contrib/snmp2cpe/pkg/cpe/cpe_test.go
Normal file
@@ -0,0 +1,244 @@
|
||||
package cpe_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
|
||||
"github.com/future-architect/vuls/contrib/snmp2cpe/pkg/cpe"
|
||||
"github.com/future-architect/vuls/contrib/snmp2cpe/pkg/snmp"
|
||||
)
|
||||
|
||||
func TestConvert(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args snmp.Result
|
||||
want []string
|
||||
}{
|
||||
{
|
||||
name: "Cisco NX-OS Version 7.1(4)N1(1)",
|
||||
args: snmp.Result{
|
||||
SysDescr0: "Cisco NX-OS(tm) n6000, Software (n6000-uk9), Version 7.1(4)N1(1), RELEASE SOFTWARE Copyright (c) 2002-2012 by Cisco Systems, Inc. Device Manager Version 6.0(2)N1(1),Compiled 9/2/2016 10:00:00",
|
||||
},
|
||||
want: []string{"cpe:2.3:o:cisco:nx-os:7.1(4)n1(1):*:*:*:*:*:*:*"},
|
||||
},
|
||||
{
|
||||
name: "Cisco IOS Version 15.1(4)M3",
|
||||
args: snmp.Result{
|
||||
SysDescr0: `Cisco IOS Software, 2800 Software (C2800NM-ADVENTERPRISEK9-M), Version 15.1(4)M3, RELEASE SOFTWARE (fc1)
|
||||
Technical Support: http://www.cisco.com/techsupport
|
||||
Copyright (c) 1986-2011 by Cisco Systems, Inc.
|
||||
Compiled Tue 06-Dec-11 16:21 by prod_rel_team`,
|
||||
},
|
||||
want: []string{"cpe:2.3:o:cisco:ios:15.1(4)m3:*:*:*:*:*:*:*"},
|
||||
},
|
||||
{
|
||||
name: "Cisco IOS Version 15.1(4)M4",
|
||||
args: snmp.Result{
|
||||
SysDescr0: `Cisco IOS Software, C181X Software (C181X-ADVENTERPRISEK9-M), Version 15.1(4)M4, RELEASE SOFTWARE (fc1)
|
||||
Technical Support: http://www.cisco.com/techsupport
|
||||
Copyright (c) 1986-2012 by Cisco Systems, Inc.
|
||||
Compiled Tue 20-Mar-12 23:34 by prod_rel_team`,
|
||||
},
|
||||
want: []string{"cpe:2.3:o:cisco:ios:15.1(4)m4:*:*:*:*:*:*:*"},
|
||||
},
|
||||
{
|
||||
name: "Cisco IOS Vresion 15.5(3)M on Cisco 892J-K9-V02",
|
||||
args: snmp.Result{
|
||||
SysDescr0: `Cisco IOS Software, C890 Software (C890-UNIVERSALK9-M), Version 15.5(3)M, RELEASE SOFTWARE (fc1)
|
||||
Technical Support: http://www.cisco.com/techsupport
|
||||
Copyright (c) 1986-2015 by Cisco Systems, Inc.
|
||||
Compiled Thu 23-Jul-15 03:08 by prod_rel_team`,
|
||||
EntPhysicalTables: map[int]snmp.EntPhysicalTable{1: {
|
||||
EntPhysicalMfgName: "Cisco",
|
||||
EntPhysicalName: "892",
|
||||
EntPhysicalSoftwareRev: "15.5(3)M, RELEASE SOFTWARE (fc1)",
|
||||
}},
|
||||
},
|
||||
want: []string{"cpe:2.3:h:cisco:892:-:*:*:*:*:*:*:*", "cpe:2.3:o:cisco:ios:15.5(3)m:*:*:*:*:*:*:*"},
|
||||
},
|
||||
{
|
||||
name: "Cisco IOS Version 15.4(3)M5 on Cisco C892FSP-K9-V02",
|
||||
args: snmp.Result{
|
||||
SysDescr0: `Cisco IOS Software, C800 Software (C800-UNIVERSALK9-M), Version 15.4(3)M5, RELEASE SOFTWARE (fc1)
|
||||
Technical Support: http://www.cisco.com/techsupport
|
||||
Copyright (c) 1986-2016 by Cisco Systems, Inc.
|
||||
Compiled Tue 09-Feb-16 06:15 by prod_rel_team`,
|
||||
EntPhysicalTables: map[int]snmp.EntPhysicalTable{1: {
|
||||
EntPhysicalMfgName: "Cisco",
|
||||
EntPhysicalName: "C892FSP-K9",
|
||||
EntPhysicalSoftwareRev: "15.4(3)M5, RELEASE SOFTWARE (fc1)",
|
||||
}},
|
||||
},
|
||||
want: []string{"cpe:2.3:h:cisco:c892fsp-k9:-:*:*:*:*:*:*:*", "cpe:2.3:o:cisco:ios:15.4(3)m5:*:*:*:*:*:*:*"},
|
||||
},
|
||||
{
|
||||
name: "Cisco IOS Version 12.2(17d)SXB11",
|
||||
args: snmp.Result{
|
||||
SysDescr0: `Cisco Internetwork Operating System Software IOS (tm) s72033_rp Software (s72033_rp-JK9SV-M), Version 12.2(17d)SXB11, RELEASE SOFTWARE (fc1)
|
||||
Technical Support: http://www.cisco.com/techsupport
|
||||
Copyright (c) 1986-2005 by cisco Systems, Inc.`,
|
||||
},
|
||||
want: []string{"cpe:2.3:o:cisco:ios:12.2(17d)sxb11:*:*:*:*:*:*:*"},
|
||||
},
|
||||
{
|
||||
name: "Cisco IOX-XE Version 16.12.4",
|
||||
args: snmp.Result{
|
||||
SysDescr0: `Cisco IOS Software [Gibraltar], Catalyst L3 Switch Software (CAT9K_LITE_IOSXE), Version 16.12.4, RELEASE SOFTWARE (fc5)
|
||||
Technical Support: http://www.cisco.com/techsupport
|
||||
Copyright (c) 1986-2020 by Cisco Systems, Inc.
|
||||
Compiled Thu 09-Jul-20 19:31 by m`,
|
||||
},
|
||||
want: []string{"cpe:2.3:o:cisco:ios_xe:16.12.4:*:*:*:*:*:*:*"},
|
||||
},
|
||||
{
|
||||
name: "Cisco IOX-XE Version 03.06.07.E",
|
||||
args: snmp.Result{
|
||||
SysDescr0: `Cisco IOS Software, IOS-XE Software, Catalyst 4500 L3 Switch Software (cat4500es8-UNIVERSALK9-M), Version 03.06.07.E RELEASE SOFTWARE (fc3)
|
||||
Technical Support: http://www.cisco.com/techsupport
|
||||
Copyright (c) 1986-2017 by Cisco Systems, Inc.
|
||||
Compiled Wed`,
|
||||
},
|
||||
want: []string{"cpe:2.3:o:cisco:ios_xe:03.06.07.e:*:*:*:*:*:*:*"},
|
||||
},
|
||||
{
|
||||
name: "Juniper SSG-5-SH-BT",
|
||||
args: snmp.Result{
|
||||
SysDescr0: "SSG5-ISDN version 6.3.0r14.0 (SN: 0000000000000001, Firewall+VPN)",
|
||||
},
|
||||
want: []string{"cpe:2.3:h:juniper:ssg5-isdn:-:*:*:*:*:*:*:*", "cpe:2.3:o:juniper:screenos:6.3.0r14.0:*:*:*:*:*:*:*"},
|
||||
},
|
||||
{
|
||||
name: "JUNOS 20.4R3-S4.8 on Juniper MX240",
|
||||
args: snmp.Result{
|
||||
SysDescr0: "Juniper Networks, Inc. mx240 internet router, kernel JUNOS 20.4R3-S4.8, Build date: 2022-08-16 20:42:11 UTC Copyright (c) 1996-2022 Juniper Networks, Inc.",
|
||||
EntPhysicalTables: map[int]snmp.EntPhysicalTable{1: {
|
||||
EntPhysicalMfgName: "Juniper Networks",
|
||||
EntPhysicalName: "CHAS-BP3-MX240-S",
|
||||
EntPhysicalSoftwareRev: "20.4R3-S4.8",
|
||||
}},
|
||||
},
|
||||
want: []string{"cpe:2.3:h:juniper:mx240:-:*:*:*:*:*:*:*", "cpe:2.3:o:juniper:junos:20.4r3-s4.8:*:*:*:*:*:*:*"},
|
||||
},
|
||||
{
|
||||
name: "JUNOS 12.1X46-D65.4 on Juniper SRX220H",
|
||||
args: snmp.Result{
|
||||
SysDescr0: "Juniper Networks, Inc. srx220h internet router, kernel JUNOS 12.1X46-D65.4 #0: 2016-12-30 01:34:30 UTC builder@quoarth.juniper.net:/volume/build/junos/12.1/service/12.1X46-D65.4/obj-octeon/junos/bsd/kernels/JSRXNLE/kernel Build date: 2016-12-30 02:59",
|
||||
},
|
||||
want: []string{"cpe:2.3:h:juniper:srx220h:-:*:*:*:*:*:*:*", "cpe:2.3:o:juniper:junos:12.1x46-d65.4:*:*:*:*:*:*:*"},
|
||||
},
|
||||
{
|
||||
name: "JUNOS 12.3X48-D30.7 on Juniper SRX220H2",
|
||||
args: snmp.Result{
|
||||
SysDescr0: "Juniper Networks, Inc. srx220h2 internet router, kernel JUNOS 12.3X48-D30.7, Build date: 2016-04-29 00:01:04 UTC Copyright (c) 1996-2016 Juniper Networks, Inc.",
|
||||
},
|
||||
want: []string{"cpe:2.3:h:juniper:srx220h2:-:*:*:*:*:*:*:*", "cpe:2.3:o:juniper:junos:12.3x48-d30.7:*:*:*:*:*:*:*"},
|
||||
},
|
||||
{
|
||||
name: "JUNOS 20.4R3-S4.8 on Juniper SRX4600",
|
||||
args: snmp.Result{
|
||||
SysDescr0: "Juniper Networks, Inc. srx4600 internet router, kernel JUNOS 20.4R3-S4.8, Build date: 2022-08-16 20:42:11 UTC Copyright (c) 1996-2022 Juniper Networks, Inc.",
|
||||
},
|
||||
want: []string{"cpe:2.3:h:juniper:srx4600:-:*:*:*:*:*:*:*", "cpe:2.3:o:juniper:junos:20.4r3-s4.8:*:*:*:*:*:*:*"},
|
||||
},
|
||||
{
|
||||
name: "cpe:2.3:o:juniper:junos:20.4:r2-s2.2:*:*:*:*:*:*",
|
||||
args: snmp.Result{
|
||||
SysDescr0: "Juniper Networks, Inc. ex4300-32f Ethernet Switch, kernel JUNOS 20.4R3-S4.8, Build date: 2022-08-16 21:10:45 UTC Copyright (c) 1996-2022 Juniper Networks, Inc.",
|
||||
EntPhysicalTables: map[int]snmp.EntPhysicalTable{1: {
|
||||
EntPhysicalMfgName: "Juniper Networks",
|
||||
EntPhysicalName: "",
|
||||
EntPhysicalSoftwareRev: "20.4R3-S4.8",
|
||||
}},
|
||||
},
|
||||
want: []string{"cpe:2.3:h:juniper:ex4300-32f:-:*:*:*:*:*:*:*", "cpe:2.3:o:juniper:junos:20.4r3-s4.8:*:*:*:*:*:*:*"},
|
||||
},
|
||||
{
|
||||
name: "Arista Networks EOS version 4.28.4M on DCS-7050TX-64",
|
||||
args: snmp.Result{
|
||||
SysDescr0: "Arista Networks EOS version 4.28.4M running on an Arista Networks DCS-7050TX-64",
|
||||
EntPhysicalTables: map[int]snmp.EntPhysicalTable{1: {
|
||||
EntPhysicalMfgName: "Arista Networks",
|
||||
EntPhysicalName: "",
|
||||
EntPhysicalSoftwareRev: "4.28.4M",
|
||||
}},
|
||||
},
|
||||
want: []string{"cpe:/h:arista:dcs-7050tx-64:-:*:*:*:*:*:*:*", "cpe:2.3:o:arista:eos:4.28.4m:*:*:*:*:*:*:*"},
|
||||
},
|
||||
{
|
||||
name: "FortiGate-50E",
|
||||
args: snmp.Result{
|
||||
EntPhysicalTables: map[int]snmp.EntPhysicalTable{1: {
|
||||
EntPhysicalMfgName: "Fortinet",
|
||||
EntPhysicalName: "FGT_50E",
|
||||
EntPhysicalSoftwareRev: "FortiGate-50E v5.4.6,build1165b1165,171018 (GA)",
|
||||
}},
|
||||
},
|
||||
want: []string{"cpe:2.3:h:fortinet:fortigate-50e:-:*:*:*:*:*:*:*", "cpe:2.3:o:fortinet:fortios:5.4.6:*:*:*:*:*:*:*"},
|
||||
},
|
||||
{
|
||||
name: "FortiGate-60F",
|
||||
args: snmp.Result{
|
||||
EntPhysicalTables: map[int]snmp.EntPhysicalTable{1: {
|
||||
EntPhysicalMfgName: "Fortinet",
|
||||
EntPhysicalName: "FGT_60F",
|
||||
EntPhysicalSoftwareRev: "FortiGate-60F v6.4.11,build2030,221031 (GA.M)",
|
||||
}},
|
||||
},
|
||||
want: []string{"cpe:2.3:h:fortinet:fortigate-60f:-:*:*:*:*:*:*:*", "cpe:2.3:o:fortinet:fortios:6.4.11:*:*:*:*:*:*:*"},
|
||||
},
|
||||
{
|
||||
name: "YAMAHA RTX1000",
|
||||
args: snmp.Result{
|
||||
SysDescr0: "RTX1000 Rev.8.01.29 (Fri Apr 15 11:50:44 2011)",
|
||||
},
|
||||
want: []string{"cpe:2.3:h:yamaha:rtx1000:-:*:*:*:*:*:*:*", "cpe:2.3:o:yamaha:rtx1000:8.01.29:*:*:*:*:*:*:*"},
|
||||
},
|
||||
{
|
||||
name: "YAMAHA RTX810",
|
||||
args: snmp.Result{
|
||||
SysDescr0: "RTX810 Rev.11.01.34 (Tue Nov 26 18:39:12 2019)",
|
||||
},
|
||||
want: []string{"cpe:2.3:h:yamaha:rtx810:-:*:*:*:*:*:*:*", "cpe:2.3:o:yamaha:rtx810:11.01.34:*:*:*:*:*:*:*"},
|
||||
},
|
||||
{
|
||||
name: "NEC IX2105",
|
||||
args: snmp.Result{
|
||||
SysDescr0: "NEC Portable Internetwork Core Operating System Software, IX Series IX2105 (magellan-sec) Software, Version 8.8.22, RELEASE SOFTWARE, Compiled Jul 04-Wed-2012 14:18:46 JST #2, IX2105",
|
||||
},
|
||||
want: []string{"cpe:2.3:h:nec:ix2105:-:*:*:*:*:*:*:*", "cpe:2.3:o:nec:ix2105:8.8.22:*:*:*:*:*:*:*"},
|
||||
},
|
||||
{
|
||||
name: "NEC IX2235",
|
||||
args: snmp.Result{
|
||||
SysDescr0: "NEC Portable Internetwork Core Operating System Software, IX Series IX2235 (magellan-sec) Software, Version 10.6.21, RELEASE SOFTWARE, Compiled Dec 15-Fri-YYYY HH:MM:SS JST #2, IX2235",
|
||||
},
|
||||
want: []string{"cpe:2.3:h:nec:ix2235:-:*:*:*:*:*:*:*", "cpe:2.3:o:nec:ix2235:10.6.21:*:*:*:*:*:*:*"},
|
||||
},
|
||||
{
|
||||
name: "Palo Alto Networks PAN-OS 10.0.0 on PA-220",
|
||||
args: snmp.Result{
|
||||
SysDescr0: "Palo Alto Networks PA-220 series firewall",
|
||||
EntPhysicalTables: map[int]snmp.EntPhysicalTable{1: {
|
||||
EntPhysicalMfgName: "Palo Alto Networks",
|
||||
EntPhysicalName: "PA-220",
|
||||
EntPhysicalSoftwareRev: "10.0.0",
|
||||
}},
|
||||
},
|
||||
want: []string{"cpe:2.3:h:paloaltonetworks:pa-220:-:*:*:*:*:*:*:*", "cpe:2.3:o:paloaltonetworks:pan-os:10.0.0:*:*:*:*:*:*:*"},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
opts := []cmp.Option{
|
||||
cmpopts.SortSlices(func(i, j string) bool {
|
||||
return i < j
|
||||
}),
|
||||
}
|
||||
if diff := cmp.Diff(cpe.Convert(tt.args), tt.want, opts...); diff != "" {
|
||||
t.Errorf("Convert() value is mismatch (-got +want):%s\n", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
131
contrib/snmp2cpe/pkg/snmp/snmp.go
Normal file
131
contrib/snmp2cpe/pkg/snmp/snmp.go
Normal file
@@ -0,0 +1,131 @@
|
||||
package snmp
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gosnmp/gosnmp"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type options struct {
|
||||
community string
|
||||
debug bool
|
||||
}
|
||||
|
||||
// Option ...
|
||||
type Option interface {
|
||||
apply(*options)
|
||||
}
|
||||
|
||||
type communityOption string
|
||||
|
||||
func (c communityOption) apply(opts *options) {
|
||||
opts.community = string(c)
|
||||
}
|
||||
|
||||
// WithCommunity ...
|
||||
func WithCommunity(c string) Option {
|
||||
return communityOption(c)
|
||||
}
|
||||
|
||||
type debugOption bool
|
||||
|
||||
func (d debugOption) apply(opts *options) {
|
||||
opts.debug = bool(d)
|
||||
}
|
||||
|
||||
// WithDebug ...
|
||||
func WithDebug(d bool) Option {
|
||||
return debugOption(d)
|
||||
}
|
||||
|
||||
// Get ...
|
||||
func Get(version gosnmp.SnmpVersion, ipaddr string, opts ...Option) (Result, error) {
|
||||
var options options
|
||||
for _, o := range opts {
|
||||
o.apply(&options)
|
||||
}
|
||||
|
||||
r := Result{SysDescr0: "", EntPhysicalTables: map[int]EntPhysicalTable{}}
|
||||
|
||||
params := &gosnmp.GoSNMP{
|
||||
Target: ipaddr,
|
||||
Port: 161,
|
||||
Version: version,
|
||||
Timeout: time.Duration(2) * time.Second,
|
||||
Retries: 3,
|
||||
ExponentialTimeout: true,
|
||||
MaxOids: gosnmp.MaxOids,
|
||||
}
|
||||
|
||||
switch version {
|
||||
case gosnmp.Version1, gosnmp.Version2c:
|
||||
params.Community = options.community
|
||||
case gosnmp.Version3:
|
||||
return Result{}, errors.New("not implemented")
|
||||
}
|
||||
|
||||
if err := params.Connect(); err != nil {
|
||||
return Result{}, errors.Wrap(err, "failed to connect")
|
||||
}
|
||||
defer params.Conn.Close()
|
||||
|
||||
for _, oid := range []string{"1.3.6.1.2.1.1.1.0", "1.3.6.1.2.1.47.1.1.1.1.12.1", "1.3.6.1.2.1.47.1.1.1.1.7.1", "1.3.6.1.2.1.47.1.1.1.1.10.1"} {
|
||||
resp, err := params.Get([]string{oid})
|
||||
if err != nil {
|
||||
return Result{}, errors.Wrap(err, "send SNMP GET request")
|
||||
}
|
||||
for _, v := range resp.Variables {
|
||||
if options.debug {
|
||||
switch v.Type {
|
||||
case gosnmp.OctetString:
|
||||
log.Printf("DEBUG: %s -> %s", v.Name, string(v.Value.([]byte)))
|
||||
default:
|
||||
log.Printf("DEBUG: %s -> %v", v.Name, v.Value)
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
case v.Name == ".1.3.6.1.2.1.1.1.0":
|
||||
if v.Type == gosnmp.OctetString {
|
||||
r.SysDescr0 = string(v.Value.([]byte))
|
||||
}
|
||||
case strings.HasPrefix(v.Name, ".1.3.6.1.2.1.47.1.1.1.1.12."):
|
||||
i, err := strconv.Atoi(strings.TrimPrefix(v.Name, ".1.3.6.1.2.1.47.1.1.1.1.12."))
|
||||
if err != nil {
|
||||
return Result{}, errors.Wrap(err, "failed to get index")
|
||||
}
|
||||
if v.Type == gosnmp.OctetString {
|
||||
b := r.EntPhysicalTables[i]
|
||||
b.EntPhysicalMfgName = string(v.Value.([]byte))
|
||||
r.EntPhysicalTables[i] = b
|
||||
}
|
||||
case strings.HasPrefix(v.Name, ".1.3.6.1.2.1.47.1.1.1.1.7."):
|
||||
i, err := strconv.Atoi(strings.TrimPrefix(v.Name, ".1.3.6.1.2.1.47.1.1.1.1.7."))
|
||||
if err != nil {
|
||||
return Result{}, errors.Wrap(err, "failed to get index")
|
||||
}
|
||||
if v.Type == gosnmp.OctetString {
|
||||
b := r.EntPhysicalTables[i]
|
||||
b.EntPhysicalName = string(v.Value.([]byte))
|
||||
r.EntPhysicalTables[i] = b
|
||||
}
|
||||
case strings.HasPrefix(v.Name, ".1.3.6.1.2.1.47.1.1.1.1.10."):
|
||||
i, err := strconv.Atoi(strings.TrimPrefix(v.Name, ".1.3.6.1.2.1.47.1.1.1.1.10."))
|
||||
if err != nil {
|
||||
return Result{}, errors.Wrap(err, "failed to get index")
|
||||
}
|
||||
if v.Type == gosnmp.OctetString {
|
||||
b := r.EntPhysicalTables[i]
|
||||
b.EntPhysicalSoftwareRev = string(v.Value.([]byte))
|
||||
r.EntPhysicalTables[i] = b
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
14
contrib/snmp2cpe/pkg/snmp/types.go
Normal file
14
contrib/snmp2cpe/pkg/snmp/types.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package snmp
|
||||
|
||||
// Result ...
|
||||
type Result struct {
|
||||
SysDescr0 string `json:"sysDescr0,omitempty"`
|
||||
EntPhysicalTables map[int]EntPhysicalTable `json:"entPhysicalTables,omitempty"`
|
||||
}
|
||||
|
||||
// EntPhysicalTable ...
|
||||
type EntPhysicalTable struct {
|
||||
EntPhysicalMfgName string `json:"entPhysicalMfgName,omitempty"`
|
||||
EntPhysicalName string `json:"entPhysicalName,omitempty"`
|
||||
EntPhysicalSoftwareRev string `json:"entPhysicalSoftwareRev,omitempty"`
|
||||
}
|
||||
12
contrib/snmp2cpe/pkg/util/util.go
Normal file
12
contrib/snmp2cpe/pkg/util/util.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package util
|
||||
|
||||
import "golang.org/x/exp/maps"
|
||||
|
||||
// Unique return unique elements
|
||||
func Unique[T comparable](s []T) []T {
|
||||
m := map[T]struct{}{}
|
||||
for _, v := range s {
|
||||
m[v] = struct{}{}
|
||||
}
|
||||
return maps.Keys(m)
|
||||
}
|
||||
@@ -473,7 +473,7 @@ func detectPkgsCvesWithGost(cnf config.GostConf, r *models.ScanResult, logOpts l
|
||||
nCVEs, err := client.DetectCVEs(r, true)
|
||||
if err != nil {
|
||||
switch r.Family {
|
||||
case constant.Debian, constant.Ubuntu:
|
||||
case constant.Debian, constant.Ubuntu, constant.Windows:
|
||||
return xerrors.Errorf("Failed to detect CVEs with gost: %w", err)
|
||||
default:
|
||||
return xerrors.Errorf("Failed to detect unfixed CVEs with gost: %w", err)
|
||||
@@ -481,7 +481,7 @@ func detectPkgsCvesWithGost(cnf config.GostConf, r *models.ScanResult, logOpts l
|
||||
}
|
||||
|
||||
switch r.Family {
|
||||
case constant.Debian, constant.Ubuntu:
|
||||
case constant.Debian, constant.Ubuntu, constant.Windows:
|
||||
logging.Log.Infof("%s: %d CVEs are detected with gost", r.FormatServerName(), nCVEs)
|
||||
default:
|
||||
logging.Log.Infof("%s: %d unfixed CVEs are detected with gost", r.FormatServerName(), nCVEs)
|
||||
|
||||
@@ -225,7 +225,7 @@ func fetchDependencyGraph(r *models.ScanResult, httpClient *http.Client, owner,
|
||||
"query { repository(owner:\"%s\", name:\"%s\") { url dependencyGraphManifests(first: %d, withDependencies: true%s) { pageInfo { endCursor hasNextPage } edges { node { blobPath filename repository { url } parseable exceedsMaxSize dependenciesCount dependencies%s { pageInfo { endCursor hasNextPage } edges { node { packageName packageManager repository { url } requirements hasDependencies } } } } } } } }"}`
|
||||
|
||||
queryStr := fmt.Sprintf(queryFmt, owner, repo, 100, after, dependenciesAfter)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost,
|
||||
"https://api.github.com/graphql",
|
||||
bytes.NewBuffer([]byte(queryStr)),
|
||||
|
||||
@@ -6,11 +6,9 @@ package detector
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
@@ -221,25 +219,23 @@ func isCveInfoUpdated(cveID string, previous, current models.ScanResult) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// jsonDirPattern is file name pattern of JSON directory
|
||||
// 2016-11-16T10:43:28+09:00
|
||||
// 2016-11-16T10:43:28Z
|
||||
var jsonDirPattern = regexp.MustCompile(
|
||||
`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:Z|[+-]\d{2}:\d{2})$`)
|
||||
|
||||
// ListValidJSONDirs returns valid json directory as array
|
||||
// Returned array is sorted so that recent directories are at the head
|
||||
func ListValidJSONDirs(resultsDir string) (dirs []string, err error) {
|
||||
var dirInfo []fs.DirEntry
|
||||
if dirInfo, err = os.ReadDir(resultsDir); err != nil {
|
||||
err = xerrors.Errorf("Failed to read %s: %w",
|
||||
config.Conf.ResultsDir, err)
|
||||
return
|
||||
dirInfo, err := os.ReadDir(resultsDir)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("Failed to read %s: %w", config.Conf.ResultsDir, err)
|
||||
}
|
||||
for _, d := range dirInfo {
|
||||
if d.IsDir() && jsonDirPattern.MatchString(d.Name()) {
|
||||
jsonDir := filepath.Join(resultsDir, d.Name())
|
||||
dirs = append(dirs, jsonDir)
|
||||
if !d.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, layout := range []string{"2006-01-02T15:04:05Z", "2006-01-02T15:04:05-07:00", "2006-01-02T15-04-05-0700"} {
|
||||
if _, err := time.Parse(layout, d.Name()); err == nil {
|
||||
dirs = append(dirs, filepath.Join(resultsDir, d.Name()))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(dirs, func(i, j int) bool {
|
||||
|
||||
33
go.mod
33
go.mod
@@ -1,6 +1,6 @@
|
||||
module github.com/future-architect/vuls
|
||||
|
||||
go 1.18
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/Azure/azure-sdk-for-go v66.0.0+incompatible
|
||||
@@ -19,6 +19,7 @@ require (
|
||||
github.com/emersion/go-smtp v0.14.0
|
||||
github.com/google/subcommands v1.2.0
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gosnmp/gosnmp v1.35.0
|
||||
github.com/gosuri/uitable v0.0.4
|
||||
github.com/hashicorp/go-uuid v1.0.3
|
||||
github.com/hashicorp/go-version v1.6.0
|
||||
@@ -35,20 +36,23 @@ require (
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/package-url/packageurl-go v0.1.1-0.20220203205134-d70459300c8a
|
||||
github.com/parnurzeal/gorequest v0.2.16
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5
|
||||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/spf13/cobra v1.6.1
|
||||
github.com/vulsio/go-cti v0.0.2-0.20220613013115-8c7e57a6aa86
|
||||
github.com/vulsio/go-cve-dictionary v0.8.2
|
||||
github.com/vulsio/go-cti v0.0.2
|
||||
github.com/vulsio/go-cve-dictionary v0.8.3
|
||||
github.com/vulsio/go-exploitdb v0.4.4
|
||||
github.com/vulsio/go-kev v0.1.1-0.20220118062020-5f69b364106f
|
||||
github.com/vulsio/go-msfdb v0.2.1-0.20211028071756-4a9759bd9f14
|
||||
github.com/vulsio/gost v0.4.2-0.20230203045609-dcfab39a9ff4
|
||||
github.com/vulsio/goval-dictionary v0.8.0
|
||||
github.com/vulsio/go-kev v0.1.1
|
||||
github.com/vulsio/go-msfdb v0.2.1
|
||||
github.com/vulsio/gost v0.4.2
|
||||
github.com/vulsio/goval-dictionary v0.8.2
|
||||
go.etcd.io/bbolt v1.3.6
|
||||
golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb
|
||||
golang.org/x/oauth2 v0.1.0
|
||||
golang.org/x/sync v0.1.0
|
||||
golang.org/x/text v0.7.0
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2
|
||||
)
|
||||
|
||||
@@ -65,9 +69,9 @@ require (
|
||||
github.com/Azure/go-autorest/autorest/to v0.3.0 // indirect
|
||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/PuerkitoBio/goquery v1.6.1 // indirect
|
||||
github.com/PuerkitoBio/goquery v1.8.1 // indirect
|
||||
github.com/VividCortex/ewma v1.2.0 // indirect
|
||||
github.com/andybalholm/cascadia v1.2.0 // indirect
|
||||
github.com/andybalholm/cascadia v1.3.1 // 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
|
||||
@@ -103,7 +107,7 @@ require (
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-getter v1.6.2 // indirect
|
||||
github.com/hashicorp/go-getter v1.7.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
|
||||
github.com/hashicorp/go-safetemp v1.0.0 // indirect
|
||||
@@ -128,13 +132,12 @@ require (
|
||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.16 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||
github.com/mitchellh/go-testing-interface v1.0.0 // indirect
|
||||
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/nsf/termbox-go v1.1.1 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0-rc2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
github.com/rogpeppe/go-internal v1.8.1 // indirect
|
||||
@@ -142,7 +145,7 @@ require (
|
||||
github.com/sergi/go-diff v1.3.1 // indirect
|
||||
github.com/smartystreets/assertions v1.13.0 // indirect
|
||||
github.com/spdx/tools-golang v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.9.3 // indirect
|
||||
github.com/spf13/afero v1.9.4 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
@@ -150,7 +153,7 @@ require (
|
||||
github.com/stretchr/objx v0.5.0 // indirect
|
||||
github.com/stretchr/testify v1.8.1 // indirect
|
||||
github.com/subosito/gotenv v1.4.2 // indirect
|
||||
github.com/ulikunitz/xz v0.5.10 // indirect
|
||||
github.com/ulikunitz/xz v0.5.11 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
@@ -162,7 +165,7 @@ require (
|
||||
golang.org/x/net v0.7.0 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
golang.org/x/term v0.5.0 // indirect
|
||||
golang.org/x/text v0.7.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.6.0 // indirect
|
||||
google.golang.org/api v0.107.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
|
||||
431
go.sum
431
go.sum
@@ -17,35 +17,176 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb
|
||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
|
||||
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
|
||||
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
|
||||
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
|
||||
cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
|
||||
cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
|
||||
cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
|
||||
cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
|
||||
cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
|
||||
cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
|
||||
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
|
||||
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
|
||||
cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
|
||||
cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=
|
||||
cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU=
|
||||
cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA=
|
||||
cloud.google.com/go v0.105.0 h1:DNtEKRBAAzeS4KyIory52wWHuClNaXJ5x1F7xa4q+5Y=
|
||||
cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM=
|
||||
cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw=
|
||||
cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY=
|
||||
cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI=
|
||||
cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4=
|
||||
cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4=
|
||||
cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0=
|
||||
cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ=
|
||||
cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk=
|
||||
cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o=
|
||||
cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s=
|
||||
cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0=
|
||||
cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY=
|
||||
cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw=
|
||||
cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI=
|
||||
cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0=
|
||||
cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA=
|
||||
cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY=
|
||||
cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s=
|
||||
cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM=
|
||||
cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI=
|
||||
cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY=
|
||||
cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI=
|
||||
cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=
|
||||
cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=
|
||||
cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=
|
||||
cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=
|
||||
cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=
|
||||
cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=
|
||||
cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU=
|
||||
cloud.google.com/go/compute v1.14.0 h1:hfm2+FfxVmnRlh6LpB7cg1ZNU+5edAHmW679JePztk0=
|
||||
cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo=
|
||||
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
|
||||
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
|
||||
cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I=
|
||||
cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4=
|
||||
cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0=
|
||||
cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs=
|
||||
cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc=
|
||||
cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM=
|
||||
cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ=
|
||||
cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo=
|
||||
cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE=
|
||||
cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I=
|
||||
cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ=
|
||||
cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo=
|
||||
cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo=
|
||||
cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ=
|
||||
cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4=
|
||||
cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0=
|
||||
cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8=
|
||||
cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU=
|
||||
cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU=
|
||||
cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y=
|
||||
cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg=
|
||||
cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk=
|
||||
cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w=
|
||||
cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk=
|
||||
cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg=
|
||||
cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM=
|
||||
cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA=
|
||||
cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o=
|
||||
cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A=
|
||||
cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0=
|
||||
cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0=
|
||||
cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc=
|
||||
cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=
|
||||
cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc=
|
||||
cloud.google.com/go/iam v0.8.0 h1:E2osAkZzxI/+8pZcxVLcDtAQx/u+hZXVryUaYQ5O0Kk=
|
||||
cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE=
|
||||
cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic=
|
||||
cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI=
|
||||
cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8=
|
||||
cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08=
|
||||
cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs=
|
||||
cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4=
|
||||
cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w=
|
||||
cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE=
|
||||
cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM=
|
||||
cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY=
|
||||
cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s=
|
||||
cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA=
|
||||
cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o=
|
||||
cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ=
|
||||
cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU=
|
||||
cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY=
|
||||
cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34=
|
||||
cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs=
|
||||
cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg=
|
||||
cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E=
|
||||
cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU=
|
||||
cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0=
|
||||
cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA=
|
||||
cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0=
|
||||
cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4=
|
||||
cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o=
|
||||
cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk=
|
||||
cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo=
|
||||
cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg=
|
||||
cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4=
|
||||
cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg=
|
||||
cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c=
|
||||
cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y=
|
||||
cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A=
|
||||
cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4=
|
||||
cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY=
|
||||
cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s=
|
||||
cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI=
|
||||
cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA=
|
||||
cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4=
|
||||
cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0=
|
||||
cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU=
|
||||
cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU=
|
||||
cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc=
|
||||
cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs=
|
||||
cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg=
|
||||
cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM=
|
||||
cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
||||
cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
|
||||
cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc=
|
||||
cloud.google.com/go/storage v1.27.0 h1:YOO045NZI9RKfCj1c5A/ZtuuENUc8OAW+gHdGnDgyMQ=
|
||||
cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s=
|
||||
cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw=
|
||||
cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g=
|
||||
cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU=
|
||||
cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4=
|
||||
cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0=
|
||||
cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo=
|
||||
cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo=
|
||||
cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE=
|
||||
cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg=
|
||||
cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0=
|
||||
cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/Azure/azure-sdk-for-go v66.0.0+incompatible h1:bmmC38SlE8/E81nNADlgmVGurPWMHDX2YNXVQMrBpEE=
|
||||
github.com/Azure/azure-sdk-for-go v66.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
@@ -89,10 +230,11 @@ github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmy
|
||||
github.com/Masterminds/squirrel v1.5.3 h1:YPpoceAcxuzIljlr5iWpNKaql7hLeG1KLSrhvdHpkZc=
|
||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 h1:YoJbenK9C67SkzkDfmQuVln04ygHj3vjZfd9FL+GmQQ=
|
||||
github.com/PuerkitoBio/goquery v1.6.1 h1:FgjbQZKl5HTmcn4sKBgvx8vv63nhyhIpv7lJpFGCWpk=
|
||||
github.com/PuerkitoBio/goquery v1.6.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
|
||||
github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
|
||||
github.com/Ullaakut/nmap/v2 v2.1.2-0.20210406060955-59a52fe80a4f h1:U5oMIt9/cuLbHnVgNddFoJ6ebcMx52Unq2+/Wglo1XU=
|
||||
github.com/Ullaakut/nmap/v2 v2.1.2-0.20210406060955-59a52fe80a4f/go.mod h1:bWPItdcCK9CkZcAaC7yS9N+t2zijtIjAWBcQtOzV9nM=
|
||||
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
|
||||
@@ -102,9 +244,9 @@ github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk
|
||||
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
|
||||
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
|
||||
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/andybalholm/cascadia v1.2.0 h1:vuRCkM5Ozh/BfmsaTm26kbjm0mIOM3yS5Ek/F5h18aE=
|
||||
github.com/andybalholm/cascadia v1.2.0/go.mod h1:YCyR8vOZT9aZ1CHEd8ap0gMVm2aFgxBp0T0eFw1RUQY=
|
||||
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
|
||||
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU=
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
|
||||
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986 h1:2a30xLN2sUZcMXl50hg+PJCIDdJgIvIbVcKqLJ/ZrtM=
|
||||
@@ -127,7 +269,7 @@ github.com/aquasecurity/trivy-db v0.0.0-20220627104749-930461748b63 h1:hgGD7zqlN
|
||||
github.com/aquasecurity/trivy-db v0.0.0-20220627104749-930461748b63/go.mod h1:/nULgnDeq/JMPMVwE1dmf4kWlYn++7VrM3O2naj4BHA=
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ=
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM=
|
||||
github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||
github.com/aws/aws-sdk-go v1.44.136 h1:J1KJJssa8pjU8jETYUxwRS37KTcxjACfKd9GK8t+5ZU=
|
||||
github.com/aws/aws-sdk-go v1.44.136/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/aws/smithy-go v1.13.4 h1:/RN2z1txIJWeXeOkzX+Hk/4Uuvv7dWtCjbmVJcrskyk=
|
||||
@@ -146,6 +288,8 @@ github.com/caarlos0/env/v6 v6.10.1/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
|
||||
@@ -159,6 +303,12 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/containerd/containerd v1.6.8 h1:h4dOFDwzHmqFEP754PgfgTeVXFnLiRc6kiqC7tplDJs=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.12.1 h1:+7nYmHJb0tEkcRaAW+MHqoKaJYZmkikupxCqVtmPuY0=
|
||||
github.com/containerd/typeurl v1.0.2 h1:Chlt8zIieDbzQFzXzAeBEF92KhExuE4p9p92/QmY7aY=
|
||||
@@ -201,6 +351,10 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
|
||||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM=
|
||||
@@ -212,6 +366,7 @@ github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
||||
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
|
||||
github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34=
|
||||
@@ -259,6 +414,8 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
@@ -274,8 +431,10 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
||||
@@ -291,6 +450,9 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-containerregistry v0.12.0 h1:nidOEtFYlgPCRqxCKj/4c/js940HVWplCWc5ftdfdUA=
|
||||
@@ -303,6 +465,7 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.2.1 h1:d8MncMlErDFTwQGBK1xhv026j9kqhvw1Qv9IbWT1VLQ=
|
||||
github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
@@ -313,6 +476,11 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||
github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE=
|
||||
@@ -320,12 +488,23 @@ github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.1 h1:RY7tHKZcRlk788d5WSo/e83gOyyy742E8GSs771ySpg=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
|
||||
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
|
||||
github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
|
||||
github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
|
||||
github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
|
||||
github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo=
|
||||
github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY=
|
||||
github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ=
|
||||
github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8=
|
||||
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
|
||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
|
||||
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
|
||||
@@ -333,17 +512,20 @@ github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gosnmp/gosnmp v1.35.0 h1:EuWWNPxTCdAUx2/NbQcSa3WdNxjzpy4Phv57b4MWpJM=
|
||||
github.com/gosnmp/gosnmp v1.35.0/go.mod h1:2AvKZ3n9aEl5TJEo/fFmf/FGO4Nj4cVeEc5yuk88CYc=
|
||||
github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY=
|
||||
github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-getter v1.6.2 h1:7jX7xcB+uVCliddZgeKyNxv0xoT7qL5KDtH7rU4IqIk=
|
||||
github.com/hashicorp/go-getter v1.6.2/go.mod h1:IZCrswsZPeWv9IkVnLElzRU/gz/QPi6pZHn4tv6vbwA=
|
||||
github.com/hashicorp/go-getter v1.7.0 h1:bzrYP+qu/gMrL1au7/aDvkoOVGUJpeKBgbqRHACAFDY=
|
||||
github.com/hashicorp/go-getter v1.7.0/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744=
|
||||
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||
github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
@@ -354,7 +536,6 @@ github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhE
|
||||
github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
|
||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
|
||||
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
@@ -387,7 +568,6 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr
|
||||
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
@@ -405,7 +585,6 @@ github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3t
|
||||
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
||||
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c=
|
||||
github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
|
||||
github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f h1:GvCU5GXhHq+7LeOzx/haG7HSIZokl3/0GkoUFzsRJjg=
|
||||
@@ -468,11 +647,10 @@ github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182aff
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
|
||||
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
@@ -532,6 +710,7 @@ github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
||||
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
|
||||
@@ -540,6 +719,8 @@ github.com/rubenv/sql-migrate v1.1.2 h1:9M6oj4e//owVVHYrFISmY9LBRw6gzkCNmD9MV36t
|
||||
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA=
|
||||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
|
||||
github.com/samber/lo v1.33.0 h1:2aKucr+rQV6gHpY3bpeZu69uYoQOzVhGT3J22Op6Cjk=
|
||||
github.com/samber/lo v1.33.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8=
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.4.0 h1:b23VGrQhTA8cN2CbBw7/FulN9fTtqYUdS5+Oxzt+DUE=
|
||||
@@ -556,12 +737,13 @@ github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVs
|
||||
github.com/smartystreets/assertions v1.13.0 h1:Dx1kYM01xsSqKPno3aqLnrwac2LetPvN23diwyr69Qs=
|
||||
github.com/smartystreets/assertions v1.13.0/go.mod h1:wDmR7qL282YbGsPy6H/yAsesrxfxaaSlJazyFLYVFx8=
|
||||
github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spdx/gordf v0.0.0-20201111095634-7098f93598fb/go.mod h1:uKWaldnbMnjsSAXRurWqqrdyZen1R7kxl8TkmWk2OyM=
|
||||
github.com/spdx/tools-golang v0.3.0 h1:rtm+DHk3aAt74Fh0Wgucb4pCxjXV8SqHCPEb2iBd30k=
|
||||
github.com/spdx/tools-golang v0.3.0/go.mod h1:RO4Y3IFROJnz+43JKm1YOrbtgQNljW4gAPpA/sY2eqo=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
|
||||
github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
|
||||
github.com/spf13/afero v1.9.4 h1:Sd43wM1IWz/s1aVXdOBkjJvuP8UdyqioeE4AmM0QsBs=
|
||||
github.com/spf13/afero v1.9.4/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
|
||||
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
|
||||
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
|
||||
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
|
||||
@@ -590,25 +772,25 @@ github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8
|
||||
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||
github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes=
|
||||
github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M=
|
||||
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
|
||||
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
|
||||
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME=
|
||||
github.com/vulsio/go-cti v0.0.2-0.20220613013115-8c7e57a6aa86 h1:/Xie1YmCGo+SMpOP5xhZ7bzRBTvTu6zGZlCv1cahE8E=
|
||||
github.com/vulsio/go-cti v0.0.2-0.20220613013115-8c7e57a6aa86/go.mod h1:EBt6G1VZylPciq3CHKmBIth6nDbcPOU59lqOily2aZM=
|
||||
github.com/vulsio/go-cve-dictionary v0.8.2 h1:abj5449xjuHVRPIeNS41TE+MDMZmw+nbjxm3QZbL4Ks=
|
||||
github.com/vulsio/go-cve-dictionary v0.8.2/go.mod h1:GOeHvUi9MaPJgNgnYXry73lnypShLett5yfpw00IJrg=
|
||||
github.com/vulsio/go-cti v0.0.2 h1:EL11fvKgeQxuwlLDrN5szafH364B2VWGuRSoATT/KaU=
|
||||
github.com/vulsio/go-cti v0.0.2/go.mod h1:oICScdF/y+skYH6yORuwSaSYCuIYy30SZRiK+kUUm8k=
|
||||
github.com/vulsio/go-cve-dictionary v0.8.3 h1:76meG1GJrXqUdI0HeliUBsdGuMm55XNEPnkPDdQdqyE=
|
||||
github.com/vulsio/go-cve-dictionary v0.8.3/go.mod h1:aqf+5NVAvmW8iLJImsrWYb7nHetX1dqP0O/8FYfrI4I=
|
||||
github.com/vulsio/go-exploitdb v0.4.4 h1:h5y6xI4wrpzwo6kmLKU7eb/GryP2kcqgjo8C+VvAFXE=
|
||||
github.com/vulsio/go-exploitdb v0.4.4/go.mod h1:nUQwEq6AEp62jeHV1Bf2wq080/7qxu+wguDW/lAnLIo=
|
||||
github.com/vulsio/go-kev v0.1.1-0.20220118062020-5f69b364106f h1:s28XqL35U+N2xkl6bLXPH68IqzmliuqeF37x5pzNLuc=
|
||||
github.com/vulsio/go-kev v0.1.1-0.20220118062020-5f69b364106f/go.mod h1:NrXTTkGG83ZYl7ypHHLqqzx6HvVkWH37qCizU5UoCS8=
|
||||
github.com/vulsio/go-msfdb v0.2.1-0.20211028071756-4a9759bd9f14 h1:2uYZw2gQ0kymwerTS1FXZbNgptnlye+SB7o3QlLDIBo=
|
||||
github.com/vulsio/go-msfdb v0.2.1-0.20211028071756-4a9759bd9f14/go.mod h1:NGdcwWxCK/ES8vZ/crzREqI69S5gH1MivCpSp1pa2Rc=
|
||||
github.com/vulsio/gost v0.4.2-0.20230203045609-dcfab39a9ff4 h1:aitlGPmn5WPb9aR6MFsikt+/EaxJtMNttaeayXsDxs0=
|
||||
github.com/vulsio/gost v0.4.2-0.20230203045609-dcfab39a9ff4/go.mod h1:6xRvzXkpm8nJ/jMmL/TJZvabfVZyy2aB1nr4wtmJ1KI=
|
||||
github.com/vulsio/goval-dictionary v0.8.0 h1:hwxIwSEo7C3yPGOcrzr5jyKhBnxEidtUVNPIlbrBg+8=
|
||||
github.com/vulsio/goval-dictionary v0.8.0/go.mod h1:6gfsQfQN0jkO3ZNJlHP5r+2iyx375CBiMBdCcL8MmwM=
|
||||
github.com/vulsio/go-kev v0.1.1 h1:Xi0FjUj2czQpnurfbXxSrJFbaePolbTrM+gfYxsvj2o=
|
||||
github.com/vulsio/go-kev v0.1.1/go.mod h1:3CiN3/Ojlodj9ACt2SAhAk5L36m27czTKDfSEf8U8Qg=
|
||||
github.com/vulsio/go-msfdb v0.2.1 h1:s3Czz+WdgtaXjHRy+1fUzSdEjZGXie354IvT+9syAY0=
|
||||
github.com/vulsio/go-msfdb v0.2.1/go.mod h1:8A7AyeSqZtFxfd5bljiB1/z2hvkFPe3/jpRtV/mqGbo=
|
||||
github.com/vulsio/gost v0.4.2 h1:WtjSeTkvvmJdhn6Dv2Ew934MC4dGmojjC6cu7Q9sHhA=
|
||||
github.com/vulsio/gost v0.4.2/go.mod h1:PxCHzwylur7/EiP7Jo6UPRYkipi76EhA015FOTjKol0=
|
||||
github.com/vulsio/goval-dictionary v0.8.2 h1:6aI10z/RFZjADzP4fvf7I1zGqbY3EfAsF0I1VOh/ep0=
|
||||
github.com/vulsio/goval-dictionary v0.8.2/go.mod h1:yRO+Xuce12lSQiV6gdMb86uc8V5Vncgzc6U84WvB/5k=
|
||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
@@ -633,8 +815,10 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
||||
@@ -682,6 +866,7 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
@@ -696,7 +881,6 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -728,10 +912,24 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||
@@ -745,6 +943,21 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
|
||||
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
|
||||
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
|
||||
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
|
||||
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
|
||||
golang.org/x/oauth2 v0.1.0 h1:isLCZuhj4v+tYv7eskaN4v/TM+A1begWWgyVJDdl1+Y=
|
||||
golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -758,7 +971,9 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -797,17 +1012,40 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -824,6 +1062,7 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
@@ -832,7 +1071,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
@@ -880,6 +1120,10 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||
@@ -888,6 +1132,9 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
@@ -909,6 +1156,35 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513
|
||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
|
||||
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
|
||||
google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
|
||||
google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
|
||||
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
|
||||
google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
|
||||
google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
|
||||
google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
|
||||
google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
|
||||
google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
|
||||
google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
|
||||
google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=
|
||||
google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g=
|
||||
google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA=
|
||||
google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=
|
||||
google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=
|
||||
google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
|
||||
google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
|
||||
google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
|
||||
google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
|
||||
google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
|
||||
google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g=
|
||||
google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
|
||||
google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
|
||||
google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI=
|
||||
google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
|
||||
google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
|
||||
google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
|
||||
google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70=
|
||||
google.golang.org/api v0.107.0 h1:I2SlFjD8ZWabaIFOfeEDg3pf0BHJDh6iYQ1ic3Yu/UU=
|
||||
google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
@@ -942,6 +1218,7 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
@@ -954,7 +1231,73 @@ google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
|
||||
google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
||||
google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
||||
google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||
google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
|
||||
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||
google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||
google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||
google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||
google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
|
||||
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||
google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||
google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||
google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||
google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||
google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||
google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||
google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||
google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||
google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||
google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||
google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||
google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE=
|
||||
google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc=
|
||||
google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
|
||||
google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
|
||||
google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
|
||||
google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
|
||||
google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
|
||||
google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
|
||||
google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
|
||||
google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
|
||||
google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
|
||||
google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
|
||||
google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw=
|
||||
google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI=
|
||||
google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI=
|
||||
google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U=
|
||||
google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
|
||||
google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
|
||||
google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s=
|
||||
google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef h1:uQ2vjV/sHTsWSqdKeLqmwitzgvjMl7o4IdtHwUDXSJY=
|
||||
google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
@@ -970,11 +1313,31 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
||||
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||
google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||
google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||
google.golang.org/grpc v1.52.0 h1:kd48UiU7EHsV4rnLyOJRuP/Il/UHE7gdDAQ+SZI7nZk=
|
||||
google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@@ -987,6 +1350,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -4,17 +4,23 @@
|
||||
package gost
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff"
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/parnurzeal/gorequest"
|
||||
"golang.org/x/exp/maps"
|
||||
"golang.org/x/exp/slices"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/future-architect/vuls/logging"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/future-architect/vuls/util"
|
||||
gostmodels "github.com/vulsio/gost/models"
|
||||
)
|
||||
|
||||
@@ -23,123 +29,256 @@ type Microsoft struct {
|
||||
Base
|
||||
}
|
||||
|
||||
var kbIDPattern = regexp.MustCompile(`KB(\d{6,7})`)
|
||||
|
||||
// DetectCVEs fills cve information that has in Gost
|
||||
func (ms Microsoft) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err error) {
|
||||
if ms.driver == nil {
|
||||
return 0, nil
|
||||
var applied, unapplied []string
|
||||
if r.WindowsKB != nil {
|
||||
applied = r.WindowsKB.Applied
|
||||
unapplied = r.WindowsKB.Unapplied
|
||||
}
|
||||
if ms.driver == nil {
|
||||
u, err := util.URLPathJoin(ms.baseURL, "microsoft", "kbs")
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("Failed to join URLPath. err: %w", err)
|
||||
}
|
||||
|
||||
var osName string
|
||||
osName, ok := r.Optional["OSName"].(string)
|
||||
if !ok {
|
||||
logging.Log.Warnf("This Windows has wrong type option(OSName). UUID: %s", r.ServerUUID)
|
||||
content := map[string]interface{}{"applied": applied, "unapplied": unapplied}
|
||||
var body []byte
|
||||
var errs []error
|
||||
var resp *http.Response
|
||||
f := func() error {
|
||||
resp, body, errs = gorequest.New().Timeout(10 * time.Second).Post(u).SendStruct(content).Type("json").EndBytes()
|
||||
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
|
||||
return xerrors.Errorf("HTTP POST error. url: %s, resp: %v, err: %+v", u, resp, errs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
notify := func(err error, t time.Duration) {
|
||||
logging.Log.Warnf("Failed to HTTP POST. retrying in %s seconds. err: %+v", t, err)
|
||||
}
|
||||
if err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify); err != nil {
|
||||
return 0, xerrors.Errorf("HTTP Error: %w", err)
|
||||
}
|
||||
|
||||
var r struct {
|
||||
Applied []string `json:"applied"`
|
||||
Unapplied []string `json:"unapplied"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &r); err != nil {
|
||||
return 0, xerrors.Errorf("Failed to Unmarshal. body: %s, err: %w", body, err)
|
||||
}
|
||||
applied = r.Applied
|
||||
unapplied = r.Unapplied
|
||||
} else {
|
||||
applied, unapplied, err = ms.driver.GetExpandKB(applied, unapplied)
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("Failed to detect CVEs. err: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
var products []string
|
||||
if _, ok := r.Optional["InstalledProducts"]; ok {
|
||||
switch ps := r.Optional["InstalledProducts"].(type) {
|
||||
case []interface{}:
|
||||
for _, p := range ps {
|
||||
pname, ok := p.(string)
|
||||
if !ok {
|
||||
logging.Log.Warnf("skip products: %v", p)
|
||||
continue
|
||||
}
|
||||
products = append(products, pname)
|
||||
}
|
||||
case []string:
|
||||
for _, p := range ps {
|
||||
products = append(products, p)
|
||||
}
|
||||
case nil:
|
||||
logging.Log.Warnf("This Windows has no option(InstalledProducts). UUID: %s", r.ServerUUID)
|
||||
}
|
||||
}
|
||||
|
||||
applied, unapplied := map[string]struct{}{}, map[string]struct{}{}
|
||||
if _, ok := r.Optional["KBID"]; ok {
|
||||
switch kbIDs := r.Optional["KBID"].(type) {
|
||||
case []interface{}:
|
||||
for _, kbID := range kbIDs {
|
||||
s, ok := kbID.(string)
|
||||
if !ok {
|
||||
logging.Log.Warnf("skip KBID: %v", kbID)
|
||||
continue
|
||||
}
|
||||
unapplied[strings.TrimPrefix(s, "KB")] = struct{}{}
|
||||
}
|
||||
case []string:
|
||||
for _, kbID := range kbIDs {
|
||||
unapplied[strings.TrimPrefix(kbID, "KB")] = struct{}{}
|
||||
}
|
||||
case nil:
|
||||
logging.Log.Warnf("This Windows has no option(KBID). UUID: %s", r.ServerUUID)
|
||||
if ms.driver == nil {
|
||||
u, err := util.URLPathJoin(ms.baseURL, "microsoft", "products")
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("Failed to join URLPath. err: %w", err)
|
||||
}
|
||||
|
||||
for _, pkg := range r.Packages {
|
||||
matches := kbIDPattern.FindAllStringSubmatch(pkg.Name, -1)
|
||||
for _, match := range matches {
|
||||
applied[match[1]] = struct{}{}
|
||||
content := map[string]interface{}{"release": r.Release, "kbs": append(applied, unapplied...)}
|
||||
var body []byte
|
||||
var errs []error
|
||||
var resp *http.Response
|
||||
f := func() error {
|
||||
resp, body, errs = gorequest.New().Timeout(10 * time.Second).Post(u).SendStruct(content).Type("json").EndBytes()
|
||||
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
|
||||
return xerrors.Errorf("HTTP POST error. url: %s, resp: %v, err: %+v", u, resp, errs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
notify := func(err error, t time.Duration) {
|
||||
logging.Log.Warnf("Failed to HTTP POST. retrying in %s seconds. err: %+v", t, err)
|
||||
}
|
||||
if err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify); err != nil {
|
||||
return 0, xerrors.Errorf("HTTP Error: %w", err)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(body, &products); err != nil {
|
||||
return 0, xerrors.Errorf("Failed to Unmarshal. body: %s, err: %w", body, err)
|
||||
}
|
||||
} else {
|
||||
switch kbIDs := r.Optional["AppliedKBID"].(type) {
|
||||
case []interface{}:
|
||||
for _, kbID := range kbIDs {
|
||||
s, ok := kbID.(string)
|
||||
if !ok {
|
||||
logging.Log.Warnf("skip KBID: %v", kbID)
|
||||
continue
|
||||
}
|
||||
applied[strings.TrimPrefix(s, "KB")] = struct{}{}
|
||||
}
|
||||
case []string:
|
||||
for _, kbID := range kbIDs {
|
||||
applied[strings.TrimPrefix(kbID, "KB")] = struct{}{}
|
||||
}
|
||||
case nil:
|
||||
logging.Log.Warnf("This Windows has no option(AppliedKBID). UUID: %s", r.ServerUUID)
|
||||
}
|
||||
|
||||
switch kbIDs := r.Optional["UnappliedKBID"].(type) {
|
||||
case []interface{}:
|
||||
for _, kbID := range kbIDs {
|
||||
s, ok := kbID.(string)
|
||||
if !ok {
|
||||
logging.Log.Warnf("skip KBID: %v", kbID)
|
||||
continue
|
||||
}
|
||||
unapplied[strings.TrimPrefix(s, "KB")] = struct{}{}
|
||||
}
|
||||
case []string:
|
||||
for _, kbID := range kbIDs {
|
||||
unapplied[strings.TrimPrefix(kbID, "KB")] = struct{}{}
|
||||
}
|
||||
case nil:
|
||||
logging.Log.Warnf("This Windows has no option(UnappliedKBID). UUID: %s", r.ServerUUID)
|
||||
ps, err := ms.driver.GetRelatedProducts(r.Release, append(applied, unapplied...))
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("Failed to detect CVEs. err: %w", err)
|
||||
}
|
||||
products = ps
|
||||
}
|
||||
|
||||
logging.Log.Debugf(`GetCvesByMicrosoftKBID query body {"osName": %s, "installedProducts": %q, "applied": %q, "unapplied: %q"}`, osName, products, maps.Keys(applied), maps.Keys(unapplied))
|
||||
cves, err := ms.driver.GetCvesByMicrosoftKBID(osName, products, maps.Keys(applied), maps.Keys(unapplied))
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("Failed to detect CVEs. err: %w", err)
|
||||
m := map[string]struct{}{}
|
||||
for _, p := range products {
|
||||
m[p] = struct{}{}
|
||||
}
|
||||
for _, n := range []string{"Microsoft Edge (Chromium-based)", fmt.Sprintf("Microsoft Edge on %s", r.Release), fmt.Sprintf("Microsoft Edge (Chromium-based) in IE Mode on %s", r.Release), fmt.Sprintf("Microsoft Edge (EdgeHTML-based) on %s", r.Release)} {
|
||||
delete(m, n)
|
||||
}
|
||||
filtered := []string{r.Release}
|
||||
for _, p := range r.Packages {
|
||||
switch p.Name {
|
||||
case "Microsoft Edge":
|
||||
if ss := strings.Split(p.Version, "."); len(ss) > 0 {
|
||||
v, err := strconv.ParseInt(ss[0], 10, 8)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if v > 44 {
|
||||
filtered = append(filtered, "Microsoft Edge (Chromium-based)", fmt.Sprintf("Microsoft Edge on %s", r.Release), fmt.Sprintf("Microsoft Edge (Chromium-based) in IE Mode on %s", r.Release))
|
||||
} else {
|
||||
filtered = append(filtered, fmt.Sprintf("Microsoft Edge on %s", r.Release), fmt.Sprintf("Microsoft Edge (EdgeHTML-based) on %s", r.Release))
|
||||
}
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
filtered = unique(append(filtered, maps.Keys(m)...))
|
||||
|
||||
var cves map[string]gostmodels.MicrosoftCVE
|
||||
if ms.driver == nil {
|
||||
u, err := util.URLPathJoin(ms.baseURL, "microsoft", "filtered-cves")
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("Failed to join URLPath. err: %w", err)
|
||||
}
|
||||
|
||||
content := map[string]interface{}{"products": filtered, "kbs": append(applied, unapplied...)}
|
||||
var body []byte
|
||||
var errs []error
|
||||
var resp *http.Response
|
||||
f := func() error {
|
||||
resp, body, errs = gorequest.New().Timeout(10 * time.Second).Post(u).SendStruct(content).Type("json").EndBytes()
|
||||
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
|
||||
return xerrors.Errorf("HTTP POST error. url: %s, resp: %v, err: %+v", u, resp, errs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
notify := func(err error, t time.Duration) {
|
||||
logging.Log.Warnf("Failed to HTTP POST. retrying in %s seconds. err: %+v", t, err)
|
||||
}
|
||||
if err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify); err != nil {
|
||||
return 0, xerrors.Errorf("HTTP Error: %w", err)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(body, &cves); err != nil {
|
||||
return 0, xerrors.Errorf("Failed to Unmarshal. body: %s, err: %w", body, err)
|
||||
}
|
||||
} else {
|
||||
cves, err = ms.driver.GetFilteredCvesMicrosoft(filtered, append(applied, unapplied...))
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("Failed to detect CVEs. err: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
for cveID, cve := range cves {
|
||||
var ps []gostmodels.MicrosoftProduct
|
||||
for _, p := range cve.Products {
|
||||
if len(p.KBs) == 0 {
|
||||
ps = append(ps, p)
|
||||
continue
|
||||
}
|
||||
|
||||
var kbs []gostmodels.MicrosoftKB
|
||||
for _, kb := range p.KBs {
|
||||
if _, err := strconv.Atoi(kb.Article); err != nil {
|
||||
switch {
|
||||
case strings.HasPrefix(p.Name, "Microsoft Edge"):
|
||||
p, ok := r.Packages["Microsoft Edge"]
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
if kb.FixedBuild == "" {
|
||||
kbs = append(kbs, kb)
|
||||
break
|
||||
}
|
||||
|
||||
vera, err := version.NewVersion(p.Version)
|
||||
if err != nil {
|
||||
kbs = append(kbs, kb)
|
||||
break
|
||||
}
|
||||
verb, err := version.NewVersion(kb.FixedBuild)
|
||||
if err != nil {
|
||||
kbs = append(kbs, kb)
|
||||
break
|
||||
}
|
||||
if vera.LessThan(verb) {
|
||||
kbs = append(kbs, kb)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if slices.Contains(applied, kb.Article) {
|
||||
kbs = []gostmodels.MicrosoftKB{}
|
||||
break
|
||||
}
|
||||
if slices.Contains(unapplied, kb.Article) {
|
||||
kbs = append(kbs, kb)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(kbs) > 0 {
|
||||
p.KBs = kbs
|
||||
ps = append(ps, p)
|
||||
}
|
||||
}
|
||||
cve.Products = ps
|
||||
if len(cve.Products) == 0 {
|
||||
continue
|
||||
}
|
||||
nCVEs++
|
||||
|
||||
cveCont, mitigations := ms.ConvertToModel(&cve)
|
||||
uniqKB := map[string]struct{}{}
|
||||
var stats models.PackageFixStatuses
|
||||
for _, p := range cve.Products {
|
||||
for _, kb := range p.KBs {
|
||||
if _, err := strconv.Atoi(kb.Article); err == nil {
|
||||
uniqKB[fmt.Sprintf("KB%s", kb.Article)] = struct{}{}
|
||||
if _, err := strconv.Atoi(kb.Article); err != nil {
|
||||
switch {
|
||||
case strings.HasPrefix(p.Name, "Microsoft Edge"):
|
||||
s := models.PackageFixStatus{
|
||||
Name: "Microsoft Edge",
|
||||
FixState: "fixed",
|
||||
FixedIn: kb.FixedBuild,
|
||||
}
|
||||
if kb.FixedBuild == "" {
|
||||
s.FixState = "unknown"
|
||||
}
|
||||
stats = append(stats, s)
|
||||
default:
|
||||
stats = append(stats, models.PackageFixStatus{
|
||||
Name: p.Name,
|
||||
FixState: "unknown",
|
||||
FixedIn: kb.FixedBuild,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
uniqKB[kb.Article] = struct{}{}
|
||||
uniqKB[fmt.Sprintf("KB%s", kb.Article)] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(uniqKB) == 0 && len(stats) == 0 {
|
||||
for _, p := range cve.Products {
|
||||
switch {
|
||||
case strings.HasPrefix(p.Name, "Microsoft Edge"):
|
||||
stats = append(stats, models.PackageFixStatus{
|
||||
Name: "Microsoft Edge",
|
||||
FixState: "unknown",
|
||||
})
|
||||
default:
|
||||
stats = append(stats, models.PackageFixStatus{
|
||||
Name: p.Name,
|
||||
FixState: "unknown",
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
advisories := []models.DistroAdvisory{}
|
||||
for kb := range uniqKB {
|
||||
advisories = append(advisories, models.DistroAdvisory{
|
||||
@@ -149,14 +288,16 @@ func (ms Microsoft) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err err
|
||||
}
|
||||
|
||||
r.ScannedCves[cveID] = models.VulnInfo{
|
||||
CveID: cveID,
|
||||
Confidences: models.Confidences{models.WindowsUpdateSearch},
|
||||
DistroAdvisories: advisories,
|
||||
CveContents: models.NewCveContents(*cveCont),
|
||||
Mitigations: mitigations,
|
||||
CveID: cveID,
|
||||
Confidences: models.Confidences{models.WindowsUpdateSearch},
|
||||
DistroAdvisories: advisories,
|
||||
CveContents: models.NewCveContents(*cveCont),
|
||||
Mitigations: mitigations,
|
||||
AffectedPackages: stats,
|
||||
WindowsKBFixedIns: maps.Keys(uniqKB),
|
||||
}
|
||||
}
|
||||
return len(cves), nil
|
||||
return nCVEs, nil
|
||||
}
|
||||
|
||||
// ConvertToModel converts gost model to vuls model
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/cenkalti/backoff"
|
||||
"github.com/parnurzeal/gorequest"
|
||||
"golang.org/x/exp/maps"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/future-architect/vuls/logging"
|
||||
@@ -189,3 +190,11 @@ func httpGet(url string, req request, resChan chan<- response, errChan chan<- er
|
||||
func major(osVer string) (majorVersion string) {
|
||||
return strings.Split(osVer, ".")[0]
|
||||
}
|
||||
|
||||
func unique[T comparable](s []T) []T {
|
||||
m := map[T]struct{}{}
|
||||
for _, v := range s {
|
||||
m[v] = struct{}{}
|
||||
}
|
||||
return maps.Keys(m)
|
||||
}
|
||||
|
||||
Submodule integration updated: a36b4595ee...fbd9e815f6
@@ -53,6 +53,7 @@ type ScanResult struct {
|
||||
WordPressPackages WordPressPackages `json:",omitempty"`
|
||||
GitHubManifests DependencyGraphManifests `json:"gitHubManifests,omitempty"`
|
||||
LibraryScanners LibraryScanners `json:"libraries,omitempty"`
|
||||
WindowsKB *WindowsKB `json:"windowsKB,omitempty"`
|
||||
CweDict CweDict `json:"cweDict,omitempty"`
|
||||
Optional map[string]interface{} `json:",omitempty"`
|
||||
Config struct {
|
||||
@@ -83,6 +84,12 @@ type Kernel struct {
|
||||
RebootRequired bool `json:"rebootRequired"`
|
||||
}
|
||||
|
||||
// WindowsKB has applied and unapplied KBs
|
||||
type WindowsKB struct {
|
||||
Applied []string `json:"applied,omitempty"`
|
||||
Unapplied []string `json:"unapplied,omitempty"`
|
||||
}
|
||||
|
||||
// FilterInactiveWordPressLibs is filter function.
|
||||
func (r *ScanResult) FilterInactiveWordPressLibs(detectInactive bool) {
|
||||
if detectInactive {
|
||||
|
||||
@@ -267,6 +267,7 @@ type VulnInfo struct {
|
||||
GitHubSecurityAlerts GitHubSecurityAlerts `json:"gitHubSecurityAlerts,omitempty"`
|
||||
WpPackageFixStats WpPackageFixStats `json:"wpPackageFixStats,omitempty"`
|
||||
LibraryFixedIns LibraryFixedIns `json:"libraryFixedIns,omitempty"`
|
||||
WindowsKBFixedIns []string `json:"windowsKBFixedIns,omitempty"`
|
||||
VulnType string `json:"vulnType,omitempty"`
|
||||
DiffStatus DiffStatus `json:"diffStatus,omitempty"`
|
||||
}
|
||||
@@ -531,7 +532,7 @@ func (v VulnInfo) Cvss2Scores() (values []CveContentCvss) {
|
||||
|
||||
// Cvss3Scores returns CVSS V3 Score
|
||||
func (v VulnInfo) Cvss3Scores() (values []CveContentCvss) {
|
||||
order := []CveContentType{RedHatAPI, RedHat, SUSE, Nvd, Jvn}
|
||||
order := []CveContentType{RedHatAPI, RedHat, SUSE, Microsoft, Nvd, Jvn}
|
||||
for _, ctype := range order {
|
||||
if conts, found := v.CveContents[ctype]; found {
|
||||
for _, cont := range conts {
|
||||
@@ -661,6 +662,7 @@ func (v VulnInfo) PatchStatus(packs Packages) string {
|
||||
if len(v.CpeURIs) != 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
for _, p := range v.AffectedPackages {
|
||||
if p.NotFixedYet {
|
||||
return "unfixed"
|
||||
@@ -680,6 +682,13 @@ func (v VulnInfo) PatchStatus(packs Packages) string {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, c := range v.Confidences {
|
||||
if c == WindowsUpdateSearch && len(v.WindowsKBFixedIns) == 0 {
|
||||
return "unfixed"
|
||||
}
|
||||
}
|
||||
|
||||
return "fixed"
|
||||
}
|
||||
|
||||
|
||||
@@ -1717,3 +1717,103 @@ func TestVulnInfos_FilterByConfidenceOver(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestVulnInfo_PatchStatus(t *testing.T) {
|
||||
type fields struct {
|
||||
Confidences Confidences
|
||||
AffectedPackages PackageFixStatuses
|
||||
CpeURIs []string
|
||||
WindowsKBFixedIns []string
|
||||
}
|
||||
type args struct {
|
||||
packs Packages
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "cpe",
|
||||
fields: fields{
|
||||
CpeURIs: []string{"cpe:/a:microsoft:internet_explorer:10"},
|
||||
},
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "package unfixed",
|
||||
fields: fields{
|
||||
AffectedPackages: PackageFixStatuses{
|
||||
{
|
||||
Name: "bash",
|
||||
NotFixedYet: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
want: "unfixed",
|
||||
},
|
||||
{
|
||||
name: "package unknown",
|
||||
fields: fields{
|
||||
AffectedPackages: PackageFixStatuses{
|
||||
{
|
||||
Name: "bash",
|
||||
},
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
packs: Packages{"bash": {
|
||||
Name: "bash",
|
||||
}},
|
||||
},
|
||||
want: "unknown",
|
||||
},
|
||||
{
|
||||
name: "package fixed",
|
||||
fields: fields{
|
||||
AffectedPackages: PackageFixStatuses{
|
||||
{
|
||||
Name: "bash",
|
||||
},
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
packs: Packages{"bash": {
|
||||
Name: "bash",
|
||||
Version: "4.3-9.1",
|
||||
NewVersion: "5.0-4",
|
||||
}},
|
||||
},
|
||||
want: "fixed",
|
||||
},
|
||||
{
|
||||
name: "windows unfixed",
|
||||
fields: fields{
|
||||
Confidences: Confidences{WindowsUpdateSearch},
|
||||
},
|
||||
want: "unfixed",
|
||||
},
|
||||
{
|
||||
name: "windows fixed",
|
||||
fields: fields{
|
||||
Confidences: Confidences{WindowsUpdateSearch},
|
||||
WindowsKBFixedIns: []string{"000000"},
|
||||
},
|
||||
want: "fixed",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
v := VulnInfo{
|
||||
Confidences: tt.fields.Confidences,
|
||||
AffectedPackages: tt.fields.AffectedPackages,
|
||||
CpeURIs: tt.fields.CpeURIs,
|
||||
WindowsKBFixedIns: tt.fields.WindowsKBFixedIns,
|
||||
}
|
||||
if got := v.PatchStatus(tt.args.packs); got != tt.want {
|
||||
t.Errorf("VulnInfo.PatchStatus() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,12 +68,15 @@ func (o RedHatBase) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
|
||||
for _, d := range vuln.DistroAdvisories {
|
||||
if conts, ok := vuln.CveContents[models.Amazon]; ok {
|
||||
for i, cont := range conts {
|
||||
if strings.HasPrefix(d.AdvisoryID, "ALAS2022-") {
|
||||
cont.SourceLink = fmt.Sprintf("https://alas.aws.amazon.com/AL2022/%s.html", strings.ReplaceAll(d.AdvisoryID, "ALAS2022", "ALAS"))
|
||||
} else if strings.HasPrefix(d.AdvisoryID, "ALAS2-") {
|
||||
cont.SourceLink = fmt.Sprintf("https://alas.aws.amazon.com/AL2/%s.html", strings.ReplaceAll(d.AdvisoryID, "ALAS2", "ALAS"))
|
||||
} else if strings.HasPrefix(d.AdvisoryID, "ALAS-") {
|
||||
switch {
|
||||
case strings.HasPrefix(d.AdvisoryID, "ALAS-"):
|
||||
cont.SourceLink = fmt.Sprintf("https://alas.aws.amazon.com/%s.html", d.AdvisoryID)
|
||||
case strings.HasPrefix(d.AdvisoryID, "ALAS2-"):
|
||||
cont.SourceLink = fmt.Sprintf("https://alas.aws.amazon.com/AL2/%s.html", strings.ReplaceAll(d.AdvisoryID, "ALAS2", "ALAS"))
|
||||
case strings.HasPrefix(d.AdvisoryID, "ALAS2022-"):
|
||||
cont.SourceLink = fmt.Sprintf("https://alas.aws.amazon.com/AL2022/%s.html", strings.ReplaceAll(d.AdvisoryID, "ALAS2022", "ALAS"))
|
||||
case strings.HasPrefix(d.AdvisoryID, "ALAS2023-"):
|
||||
cont.SourceLink = fmt.Sprintf("https://alas.aws.amazon.com/AL2023/%s.html", strings.ReplaceAll(d.AdvisoryID, "ALAS2023", "ALAS"))
|
||||
}
|
||||
vuln.CveContents[models.Amazon][i] = cont
|
||||
}
|
||||
|
||||
40
oval/util.go
40
oval/util.go
@@ -112,13 +112,25 @@ func getDefsByPackNameViaHTTP(r *models.ScanResult, url string) (relatedDefs ova
|
||||
case constant.CentOS:
|
||||
ovalRelease = strings.TrimPrefix(r.Release, "stream")
|
||||
case constant.Amazon:
|
||||
switch strings.Fields(r.Release)[0] {
|
||||
case "2022":
|
||||
ovalRelease = "2022"
|
||||
switch s := strings.Fields(r.Release)[0]; s {
|
||||
case "1":
|
||||
ovalRelease = "1"
|
||||
case "2":
|
||||
ovalRelease = "2"
|
||||
case "2022":
|
||||
ovalRelease = "2022"
|
||||
case "2023":
|
||||
ovalRelease = "2023"
|
||||
case "2025":
|
||||
ovalRelease = "2025"
|
||||
case "2027":
|
||||
ovalRelease = "2027"
|
||||
case "2029":
|
||||
ovalRelease = "2029"
|
||||
default:
|
||||
ovalRelease = "1"
|
||||
if _, err := time.Parse("2006.01", s); err == nil {
|
||||
ovalRelease = "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,13 +286,25 @@ func getDefsByPackNameFromOvalDB(r *models.ScanResult, driver ovaldb.DB) (relate
|
||||
case constant.CentOS:
|
||||
ovalRelease = strings.TrimPrefix(r.Release, "stream")
|
||||
case constant.Amazon:
|
||||
switch strings.Fields(r.Release)[0] {
|
||||
case "2022":
|
||||
ovalRelease = "2022"
|
||||
switch s := strings.Fields(r.Release)[0]; s {
|
||||
case "1":
|
||||
ovalRelease = "1"
|
||||
case "2":
|
||||
ovalRelease = "2"
|
||||
case "2022":
|
||||
ovalRelease = "2022"
|
||||
case "2023":
|
||||
ovalRelease = "2023"
|
||||
case "2025":
|
||||
ovalRelease = "2025"
|
||||
case "2027":
|
||||
ovalRelease = "2027"
|
||||
case "2029":
|
||||
ovalRelease = "2029"
|
||||
default:
|
||||
ovalRelease = "1"
|
||||
if _, err := time.Parse("2006.01", s); err == nil {
|
||||
ovalRelease = "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build !windows
|
||||
|
||||
package reporter
|
||||
|
||||
import (
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -81,24 +80,23 @@ func loadOneServerScanResult(jsonFile string) (*models.ScanResult, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// jsonDirPattern is file name pattern of JSON directory
|
||||
// 2016-11-16T10:43:28+09:00
|
||||
// 2016-11-16T10:43:28Z
|
||||
var jsonDirPattern = regexp.MustCompile(
|
||||
`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:Z|[+-]\d{2}:\d{2})$`)
|
||||
|
||||
// ListValidJSONDirs returns valid json directory as array
|
||||
// Returned array is sorted so that recent directories are at the head
|
||||
func ListValidJSONDirs(resultsDir string) (dirs []string, err error) {
|
||||
var dirInfo []fs.DirEntry
|
||||
if dirInfo, err = os.ReadDir(resultsDir); err != nil {
|
||||
err = xerrors.Errorf("Failed to read %s: %w", resultsDir, err)
|
||||
return
|
||||
dirInfo, err := os.ReadDir(resultsDir)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("Failed to read %s: %w", resultsDir, err)
|
||||
}
|
||||
for _, d := range dirInfo {
|
||||
if d.IsDir() && jsonDirPattern.MatchString(d.Name()) {
|
||||
jsonDir := filepath.Join(resultsDir, d.Name())
|
||||
dirs = append(dirs, jsonDir)
|
||||
if !d.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, layout := range []string{"2006-01-02T15:04:05Z", "2006-01-02T15:04:05-07:00", "2006-01-02T15-04-05-0700"} {
|
||||
if _, err := time.Parse(layout, d.Name()); err == nil {
|
||||
dirs = append(dirs, filepath.Join(resultsDir, d.Name()))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(dirs, func(i, j int) bool {
|
||||
@@ -258,9 +256,13 @@ No CVE-IDs are found in updatable packages.
|
||||
// v2max := vinfo.MaxCvss2Score().Value.Score
|
||||
// v3max := vinfo.MaxCvss3Score().Value.Score
|
||||
|
||||
packnames := strings.Join(vinfo.AffectedPackages.Names(), ", ")
|
||||
// packname := vinfo.AffectedPackages.FormatTuiSummary()
|
||||
// packname += strings.Join(vinfo.CpeURIs, ", ")
|
||||
pkgNames := vinfo.AffectedPackages.Names()
|
||||
pkgNames = append(pkgNames, vinfo.CpeURIs...)
|
||||
pkgNames = append(pkgNames, vinfo.GitHubSecurityAlerts.Names()...)
|
||||
pkgNames = append(pkgNames, vinfo.WpPackageFixStats.Names()...)
|
||||
pkgNames = append(pkgNames, vinfo.LibraryFixedIns.Names()...)
|
||||
pkgNames = append(pkgNames, vinfo.WindowsKBFixedIns...)
|
||||
packnames := strings.Join(pkgNames, ", ")
|
||||
|
||||
exploits := ""
|
||||
if 0 < len(vinfo.Exploits) || 0 < len(vinfo.Metasploits) {
|
||||
@@ -431,6 +433,10 @@ No CVE-IDs are found in updatable packages.
|
||||
}
|
||||
}
|
||||
|
||||
if len(vuln.WindowsKBFixedIns) > 0 {
|
||||
data = append(data, []string{"Windows KB", fmt.Sprintf("FixedIn: %s", strings.Join(vuln.WindowsKBFixedIns, ", "))})
|
||||
}
|
||||
|
||||
for _, confidence := range vuln.Confidences {
|
||||
data = append(data, []string{"Confidence", confidence.String()})
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ type base struct {
|
||||
osPackages
|
||||
LibraryScanners []models.LibraryScanner
|
||||
WordPress models.WordPressPackages
|
||||
windowsKB *models.WindowsKB
|
||||
|
||||
log logging.Logger
|
||||
errs []error
|
||||
@@ -506,6 +507,7 @@ func (l *base) convertToModel() models.ScanResult {
|
||||
EnabledDnfModules: l.EnabledDnfModules,
|
||||
WordPressPackages: l.WordPress,
|
||||
LibraryScanners: l.LibraryScanners,
|
||||
WindowsKB: l.windowsKB,
|
||||
Optional: l.ServerInfo.Optional,
|
||||
Errors: errs,
|
||||
Warnings: warns,
|
||||
@@ -815,20 +817,48 @@ func (d *DummyFileInfo) IsDir() bool { return false }
|
||||
// Sys is
|
||||
func (d *DummyFileInfo) Sys() interface{} { return nil }
|
||||
|
||||
func (l *base) buildWpCliCmd(wpCliArgs string, suppressStderr bool, shell string) string {
|
||||
cmd := fmt.Sprintf("%s %s --path=%s", l.ServerInfo.WordPress.CmdPath, wpCliArgs, l.ServerInfo.WordPress.DocRoot)
|
||||
if !l.ServerInfo.WordPress.NoSudo {
|
||||
cmd = fmt.Sprintf("sudo -u %s -i -- %s --allow-root", l.ServerInfo.WordPress.OSUser, cmd)
|
||||
} else if l.ServerInfo.User != l.ServerInfo.WordPress.OSUser {
|
||||
cmd = fmt.Sprintf("su %s -c '%s'", l.ServerInfo.WordPress.OSUser, cmd)
|
||||
}
|
||||
|
||||
if suppressStderr {
|
||||
switch shell {
|
||||
case "csh", "tcsh":
|
||||
cmd = fmt.Sprintf("( %s > /dev/tty ) >& /dev/null", cmd)
|
||||
default:
|
||||
cmd = fmt.Sprintf("%s 2>/dev/null", cmd)
|
||||
}
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (l *base) scanWordPress() error {
|
||||
if l.ServerInfo.WordPress.IsZero() || l.ServerInfo.Type == constant.ServerTypePseudo {
|
||||
return nil
|
||||
}
|
||||
|
||||
shell, err := l.detectShell()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("Failed to detect shell. err: %w", err)
|
||||
}
|
||||
|
||||
l.log.Info("Scanning WordPress...")
|
||||
cmd := fmt.Sprintf("sudo -u %s -i -- %s core version --path=%s --allow-root",
|
||||
l.ServerInfo.WordPress.OSUser,
|
||||
l.ServerInfo.WordPress.CmdPath,
|
||||
l.ServerInfo.WordPress.DocRoot)
|
||||
if l.ServerInfo.WordPress.NoSudo && l.ServerInfo.User != l.ServerInfo.WordPress.OSUser {
|
||||
if r := l.exec(fmt.Sprintf("timeout 2 su %s -c exit", l.ServerInfo.WordPress.OSUser), noSudo); !r.isSuccess() {
|
||||
return xerrors.New("Failed to switch user without password. err: please configure to switch users without password")
|
||||
}
|
||||
}
|
||||
|
||||
cmd := l.buildWpCliCmd("core version", false, shell)
|
||||
if r := exec(l.ServerInfo, cmd, noSudo); !r.isSuccess() {
|
||||
return xerrors.Errorf("Failed to exec `%s`. Check the OS user, command path of wp-cli, DocRoot and permission: %#v", cmd, l.ServerInfo.WordPress)
|
||||
}
|
||||
|
||||
wp, err := l.detectWordPress()
|
||||
wp, err := l.detectWordPress(shell)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("Failed to scan wordpress: %w", err)
|
||||
}
|
||||
@@ -836,18 +866,44 @@ func (l *base) scanWordPress() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *base) detectWordPress() (*models.WordPressPackages, error) {
|
||||
ver, err := l.detectWpCore()
|
||||
func (l *base) detectShell() (string, error) {
|
||||
if r := l.exec("printenv SHELL", noSudo); r.isSuccess() {
|
||||
if t := strings.TrimSpace(r.Stdout); t != "" {
|
||||
return filepath.Base(t), nil
|
||||
}
|
||||
}
|
||||
|
||||
if r := l.exec(fmt.Sprintf(`grep "^%s" /etc/passwd | awk -F: '/%s/ { print $7 }'`, l.ServerInfo.User, l.ServerInfo.User), noSudo); r.isSuccess() {
|
||||
if t := strings.TrimSpace(r.Stdout); t != "" {
|
||||
return filepath.Base(t), nil
|
||||
}
|
||||
}
|
||||
|
||||
if isLocalExec(l.ServerInfo.Port, l.ServerInfo.Host) {
|
||||
if r := l.exec("ps -p $$ | tail +2 | awk '{print $NF}'", noSudo); r.isSuccess() {
|
||||
return strings.TrimSpace(r.Stdout), nil
|
||||
}
|
||||
|
||||
if r := l.exec("ps -p %self | tail +2 | awk '{print $NF}'", noSudo); r.isSuccess() {
|
||||
return strings.TrimSpace(r.Stdout), nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", xerrors.New("shell cannot be determined")
|
||||
}
|
||||
|
||||
func (l *base) detectWordPress(shell string) (*models.WordPressPackages, error) {
|
||||
ver, err := l.detectWpCore(shell)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
themes, err := l.detectWpThemes()
|
||||
themes, err := l.detectWpThemes(shell)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
plugins, err := l.detectWpPlugins()
|
||||
plugins, err := l.detectWpPlugins(shell)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -864,11 +920,8 @@ func (l *base) detectWordPress() (*models.WordPressPackages, error) {
|
||||
return &pkgs, nil
|
||||
}
|
||||
|
||||
func (l *base) detectWpCore() (string, error) {
|
||||
cmd := fmt.Sprintf("sudo -u %s -i -- %s core version --path=%s --allow-root 2>/dev/null",
|
||||
l.ServerInfo.WordPress.OSUser,
|
||||
l.ServerInfo.WordPress.CmdPath,
|
||||
l.ServerInfo.WordPress.DocRoot)
|
||||
func (l *base) detectWpCore(shell string) (string, error) {
|
||||
cmd := l.buildWpCliCmd("core version", true, shell)
|
||||
|
||||
r := exec(l.ServerInfo, cmd, noSudo)
|
||||
if !r.isSuccess() {
|
||||
@@ -877,11 +930,8 @@ func (l *base) detectWpCore() (string, error) {
|
||||
return strings.TrimSpace(r.Stdout), nil
|
||||
}
|
||||
|
||||
func (l *base) detectWpThemes() ([]models.WpPackage, error) {
|
||||
cmd := fmt.Sprintf("sudo -u %s -i -- %s theme list --path=%s --format=json --allow-root 2>/dev/null",
|
||||
l.ServerInfo.WordPress.OSUser,
|
||||
l.ServerInfo.WordPress.CmdPath,
|
||||
l.ServerInfo.WordPress.DocRoot)
|
||||
func (l *base) detectWpThemes(shell string) ([]models.WpPackage, error) {
|
||||
cmd := l.buildWpCliCmd("theme list --format=json", true, shell)
|
||||
|
||||
var themes []models.WpPackage
|
||||
r := exec(l.ServerInfo, cmd, noSudo)
|
||||
@@ -898,11 +948,8 @@ func (l *base) detectWpThemes() ([]models.WpPackage, error) {
|
||||
return themes, nil
|
||||
}
|
||||
|
||||
func (l *base) detectWpPlugins() ([]models.WpPackage, error) {
|
||||
cmd := fmt.Sprintf("sudo -u %s -i -- %s plugin list --path=%s --format=json --allow-root 2>/dev/null",
|
||||
l.ServerInfo.WordPress.OSUser,
|
||||
l.ServerInfo.WordPress.CmdPath,
|
||||
l.ServerInfo.WordPress.DocRoot)
|
||||
func (l *base) detectWpPlugins(shell string) ([]models.WpPackage, error) {
|
||||
cmd := l.buildWpCliCmd("plugin list --format=json", true, shell)
|
||||
|
||||
var plugins []models.WpPackage
|
||||
r := exec(l.ServerInfo, cmd, noSudo)
|
||||
|
||||
@@ -42,16 +42,10 @@ func newDebian(c config.ServerInfo) *debian {
|
||||
|
||||
// Ubuntu, Debian, Raspbian
|
||||
// https://github.com/serverspec/specinfra/blob/master/lib/specinfra/helper/detect_os/debian.rb
|
||||
func detectDebian(c config.ServerInfo) (bool, osTypeInterface, error) {
|
||||
func detectDebian(c config.ServerInfo) (bool, osTypeInterface) {
|
||||
if r := exec(c, "ls /etc/debian_version", noSudo); !r.isSuccess() {
|
||||
if r.Error != nil {
|
||||
return false, nil, nil
|
||||
}
|
||||
if r.ExitStatus == 255 {
|
||||
return false, &unknown{base{ServerInfo: c}}, xerrors.Errorf("Unable to connect via SSH. Scan with -vvv option to print SSH debugging messages and check SSH settings.\n%s", r)
|
||||
}
|
||||
logging.Log.Debugf("Not Debian like Linux. %s", r)
|
||||
return false, nil, nil
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Raspbian
|
||||
@@ -64,7 +58,7 @@ func detectDebian(c config.ServerInfo) (bool, osTypeInterface, error) {
|
||||
if len(result) > 2 && result[0] == constant.Raspbian {
|
||||
deb := newDebian(c)
|
||||
deb.setDistro(strings.ToLower(trim(result[0])), trim(result[2]))
|
||||
return true, deb, nil
|
||||
return true, deb
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +78,7 @@ func detectDebian(c config.ServerInfo) (bool, osTypeInterface, error) {
|
||||
distro := strings.ToLower(trim(result[1]))
|
||||
deb.setDistro(distro, trim(result[2]))
|
||||
}
|
||||
return true, deb, nil
|
||||
return true, deb
|
||||
}
|
||||
|
||||
if r := exec(c, "cat /etc/lsb-release", noSudo); r.isSuccess() {
|
||||
@@ -104,7 +98,7 @@ func detectDebian(c config.ServerInfo) (bool, osTypeInterface, error) {
|
||||
distro := strings.ToLower(trim(result[1]))
|
||||
deb.setDistro(distro, trim(result[2]))
|
||||
}
|
||||
return true, deb, nil
|
||||
return true, deb
|
||||
}
|
||||
|
||||
// Debian
|
||||
@@ -112,11 +106,11 @@ func detectDebian(c config.ServerInfo) (bool, osTypeInterface, error) {
|
||||
if r := exec(c, cmd, noSudo); r.isSuccess() {
|
||||
deb := newDebian(c)
|
||||
deb.setDistro(constant.Debian, trim(r.Stdout))
|
||||
return true, deb, nil
|
||||
return true, deb
|
||||
}
|
||||
|
||||
logging.Log.Debugf("Not Debian like Linux: %s", c.ServerName)
|
||||
return false, nil, nil
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func trim(str string) string {
|
||||
|
||||
@@ -3,17 +3,24 @@ package scanner
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
ex "os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
homedir "github.com/mitchellh/go-homedir"
|
||||
"github.com/saintfish/chardet"
|
||||
"golang.org/x/text/encoding/japanese"
|
||||
"golang.org/x/text/encoding/unicode"
|
||||
"golang.org/x/text/transform"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/constant"
|
||||
"github.com/future-architect/vuls/logging"
|
||||
homedir "github.com/mitchellh/go-homedir"
|
||||
)
|
||||
|
||||
type execResult struct {
|
||||
@@ -152,15 +159,14 @@ func localExec(c config.ServerInfo, cmdstr string, sudo bool) (result execResult
|
||||
cmdstr = decorateCmd(c, cmdstr, sudo)
|
||||
var cmd *ex.Cmd
|
||||
switch c.Distro.Family {
|
||||
// case conf.FreeBSD, conf.Alpine, conf.Debian:
|
||||
// cmd = ex.Command("/bin/sh", "-c", cmdstr)
|
||||
case constant.Windows:
|
||||
cmd = ex.Command("powershell.exe", "-NoProfile", "-NonInteractive", cmdstr)
|
||||
default:
|
||||
cmd = ex.Command("/bin/sh", "-c", cmdstr)
|
||||
}
|
||||
var stdoutBuf, stderrBuf bytes.Buffer
|
||||
cmd.Stdout = &stdoutBuf
|
||||
cmd.Stderr = &stderrBuf
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
result.Error = err
|
||||
if exitError, ok := err.(*ex.ExitError); ok {
|
||||
@@ -172,42 +178,47 @@ func localExec(c config.ServerInfo, cmdstr string, sudo bool) (result execResult
|
||||
} else {
|
||||
result.ExitStatus = 0
|
||||
}
|
||||
|
||||
result.Stdout = stdoutBuf.String()
|
||||
result.Stderr = stderrBuf.String()
|
||||
result.Stdout = toUTF8(stdoutBuf.String())
|
||||
result.Stderr = toUTF8(stderrBuf.String())
|
||||
result.Cmd = strings.Replace(cmdstr, "\n", "", -1)
|
||||
return
|
||||
}
|
||||
|
||||
func sshExecExternal(c config.ServerInfo, cmd string, sudo bool) (result execResult) {
|
||||
func sshExecExternal(c config.ServerInfo, cmdstr string, sudo bool) (result execResult) {
|
||||
sshBinaryPath, err := ex.LookPath("ssh")
|
||||
if err != nil {
|
||||
return execResult{Error: err}
|
||||
}
|
||||
if runtime.GOOS == "windows" {
|
||||
sshBinaryPath = "ssh.exe"
|
||||
}
|
||||
|
||||
args := []string{"-tt"}
|
||||
var args []string
|
||||
|
||||
if c.SSHConfigPath != "" {
|
||||
args = append(args, "-F", c.SSHConfigPath)
|
||||
} else {
|
||||
home, err := homedir.Dir()
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Failed to get HOME directory: %s", err)
|
||||
result.Stderr = msg
|
||||
result.ExitStatus = 997
|
||||
return
|
||||
}
|
||||
controlPath := filepath.Join(home, ".vuls", `controlmaster-%r-`+c.ServerName+`.%p`)
|
||||
|
||||
args = append(args,
|
||||
"-o", "StrictHostKeyChecking=yes",
|
||||
"-o", "LogLevel=quiet",
|
||||
"-o", "ConnectionAttempts=3",
|
||||
"-o", "ConnectTimeout=10",
|
||||
"-o", "ControlMaster=auto",
|
||||
"-o", fmt.Sprintf("ControlPath=%s", controlPath),
|
||||
"-o", "Controlpersist=10m",
|
||||
)
|
||||
if runtime.GOOS != "windows" {
|
||||
home, err := homedir.Dir()
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Failed to get HOME directory: %s", err)
|
||||
result.Stderr = msg
|
||||
result.ExitStatus = 997
|
||||
return
|
||||
}
|
||||
|
||||
controlPath := filepath.Join(home, ".vuls", `controlmaster-%r-`+c.ServerName+`.%p`)
|
||||
args = append(args,
|
||||
"-o", "ControlMaster=auto",
|
||||
"-o", fmt.Sprintf("ControlPath=%s", controlPath),
|
||||
"-o", "Controlpersist=10m")
|
||||
}
|
||||
}
|
||||
|
||||
if config.Conf.Vvv {
|
||||
@@ -228,16 +239,18 @@ func sshExecExternal(c config.ServerInfo, cmd string, sudo bool) (result execRes
|
||||
}
|
||||
args = append(args, c.Host)
|
||||
|
||||
cmd = decorateCmd(c, cmd, sudo)
|
||||
cmd = fmt.Sprintf("stty cols 1000; %s", cmd)
|
||||
|
||||
args = append(args, cmd)
|
||||
execCmd := ex.Command(sshBinaryPath, args...)
|
||||
|
||||
cmdstr = decorateCmd(c, cmdstr, sudo)
|
||||
var cmd *ex.Cmd
|
||||
switch c.Distro.Family {
|
||||
case constant.Windows:
|
||||
cmd = ex.Command(sshBinaryPath, append(args, "powershell.exe", "-NoProfile", "-NonInteractive", fmt.Sprintf(`"%s`, cmdstr))...)
|
||||
default:
|
||||
cmd = ex.Command(sshBinaryPath, append(args, fmt.Sprintf("stty cols 1000; %s", cmdstr))...)
|
||||
}
|
||||
var stdoutBuf, stderrBuf bytes.Buffer
|
||||
execCmd.Stdout = &stdoutBuf
|
||||
execCmd.Stderr = &stderrBuf
|
||||
if err := execCmd.Run(); err != nil {
|
||||
cmd.Stdout = &stdoutBuf
|
||||
cmd.Stderr = &stderrBuf
|
||||
if err := cmd.Run(); err != nil {
|
||||
if e, ok := err.(*ex.ExitError); ok {
|
||||
if s, ok := e.Sys().(syscall.WaitStatus); ok {
|
||||
result.ExitStatus = s.ExitStatus()
|
||||
@@ -250,9 +263,8 @@ func sshExecExternal(c config.ServerInfo, cmd string, sudo bool) (result execRes
|
||||
} else {
|
||||
result.ExitStatus = 0
|
||||
}
|
||||
|
||||
result.Stdout = stdoutBuf.String()
|
||||
result.Stderr = stderrBuf.String()
|
||||
result.Stdout = toUTF8(stdoutBuf.String())
|
||||
result.Stderr = toUTF8(stderrBuf.String())
|
||||
result.Servername = c.ServerName
|
||||
result.Container = c.Container
|
||||
result.Host = c.Host
|
||||
@@ -280,7 +292,7 @@ func dockerShell(family string) string {
|
||||
|
||||
func decorateCmd(c config.ServerInfo, cmd string, sudo bool) string {
|
||||
if sudo && c.User != "root" && !c.IsContainer() {
|
||||
cmd = fmt.Sprintf("sudo -S %s", cmd)
|
||||
cmd = fmt.Sprintf("sudo %s", cmd)
|
||||
}
|
||||
|
||||
// If you are using pipe and you want to detect preprocessing errors, remove comment out
|
||||
@@ -306,10 +318,40 @@ func decorateCmd(c config.ServerInfo, cmd string, sudo bool) string {
|
||||
c.Container.Name, dockerShell(c.Distro.Family), cmd)
|
||||
// LXC required root privilege
|
||||
if c.User != "root" {
|
||||
cmd = fmt.Sprintf("sudo -S %s", cmd)
|
||||
cmd = fmt.Sprintf("sudo %s", cmd)
|
||||
}
|
||||
}
|
||||
}
|
||||
// cmd = fmt.Sprintf("set -x; %s", cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func toUTF8(s string) string {
|
||||
d := chardet.NewTextDetector()
|
||||
res, err := d.DetectBest([]byte(s))
|
||||
if err != nil {
|
||||
return s
|
||||
}
|
||||
|
||||
var bs []byte
|
||||
switch res.Charset {
|
||||
case "UTF-8":
|
||||
bs, err = []byte(s), nil
|
||||
case "UTF-16LE":
|
||||
bs, err = io.ReadAll(transform.NewReader(strings.NewReader(s), unicode.UTF16(unicode.LittleEndian, unicode.UseBOM).NewDecoder()))
|
||||
case "UTF-16BE":
|
||||
bs, err = io.ReadAll(transform.NewReader(strings.NewReader(s), unicode.UTF16(unicode.BigEndian, unicode.UseBOM).NewDecoder()))
|
||||
case "Shift_JIS":
|
||||
bs, err = io.ReadAll(transform.NewReader(strings.NewReader(s), japanese.ShiftJIS.NewDecoder()))
|
||||
case "EUC-JP":
|
||||
bs, err = io.ReadAll(transform.NewReader(strings.NewReader(s), japanese.EUCJP.NewDecoder()))
|
||||
case "ISO-2022-JP":
|
||||
bs, err = io.ReadAll(transform.NewReader(strings.NewReader(s), japanese.ISO2022JP.NewDecoder()))
|
||||
default:
|
||||
bs, err = []byte(s), nil
|
||||
}
|
||||
if err != nil {
|
||||
return s
|
||||
}
|
||||
return string(bs)
|
||||
}
|
||||
|
||||
@@ -39,14 +39,14 @@ func TestDecorateCmd(t *testing.T) {
|
||||
conf: config.ServerInfo{User: "non-root"},
|
||||
cmd: "ls",
|
||||
sudo: true,
|
||||
expected: "sudo -S ls",
|
||||
expected: "sudo ls",
|
||||
},
|
||||
// non-root sudo true
|
||||
{
|
||||
conf: config.ServerInfo{User: "non-root"},
|
||||
cmd: "ls | grep hoge",
|
||||
sudo: true,
|
||||
expected: "sudo -S ls | grep hoge",
|
||||
expected: "sudo ls | grep hoge",
|
||||
},
|
||||
// -------------docker-------------
|
||||
// root sudo false docker
|
||||
@@ -192,7 +192,7 @@ func TestDecorateCmd(t *testing.T) {
|
||||
},
|
||||
cmd: "ls",
|
||||
sudo: false,
|
||||
expected: `sudo -S lxc-attach -n def 2>/dev/null -- /bin/sh -c 'ls'`,
|
||||
expected: `sudo lxc-attach -n def 2>/dev/null -- /bin/sh -c 'ls'`,
|
||||
},
|
||||
// non-root sudo true, lxc
|
||||
{
|
||||
@@ -203,7 +203,7 @@ func TestDecorateCmd(t *testing.T) {
|
||||
},
|
||||
cmd: "ls",
|
||||
sudo: true,
|
||||
expected: `sudo -S lxc-attach -n def 2>/dev/null -- /bin/sh -c 'ls'`,
|
||||
expected: `sudo lxc-attach -n def 2>/dev/null -- /bin/sh -c 'ls'`,
|
||||
},
|
||||
// non-root sudo true lxc
|
||||
{
|
||||
@@ -214,7 +214,7 @@ func TestDecorateCmd(t *testing.T) {
|
||||
},
|
||||
cmd: "ls | grep hoge",
|
||||
sudo: true,
|
||||
expected: `sudo -S lxc-attach -n def 2>/dev/null -- /bin/sh -c 'ls | grep hoge'`,
|
||||
expected: `sudo lxc-attach -n def 2>/dev/null -- /bin/sh -c 'ls | grep hoge'`,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -188,6 +188,39 @@ func detectRedhat(c config.ServerInfo) (bool, osTypeInterface) {
|
||||
}
|
||||
}
|
||||
|
||||
if r := exec(c, "ls /etc/amazon-linux-release", noSudo); r.isSuccess() {
|
||||
// $ cat /etc/amazon-linux-release
|
||||
// Amazon Linux release 2022 (Amazon Linux)
|
||||
// Amazon Linux release 2023 (Amazon Linux)
|
||||
if r := exec(c, "cat /etc/amazon-linux-release", noSudo); r.isSuccess() {
|
||||
amazon := newAmazon(c)
|
||||
result := releasePattern.FindStringSubmatch(strings.TrimSpace(r.Stdout))
|
||||
if len(result) != 3 {
|
||||
amazon.setErrs([]error{xerrors.Errorf("Failed to parse /etc/amazon-linux-release. r.Stdout: %s", r.Stdout)})
|
||||
return true, amazon
|
||||
}
|
||||
|
||||
release := result[2]
|
||||
major, err := strconv.Atoi(util.Major(release))
|
||||
if err != nil {
|
||||
amazon.setErrs([]error{xerrors.Errorf("Failed to parse major version from release: %s", release)})
|
||||
return true, amazon
|
||||
}
|
||||
if major < 2022 {
|
||||
amazon.setErrs([]error{xerrors.Errorf("Failed to init Amazon Linux. err: not supported major version. versions prior to Amazon Linux 2022 are not supported, detected version is %s", release)})
|
||||
return true, amazon
|
||||
}
|
||||
switch strings.ToLower(result[1]) {
|
||||
case "amazon", "amazon linux":
|
||||
amazon.setDistro(constant.Amazon, release)
|
||||
return true, amazon
|
||||
default:
|
||||
amazon.setErrs([]error{xerrors.Errorf("Failed to parse Amazon Linux Name. release: %s", release)})
|
||||
return true, amazon
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
@@ -266,19 +299,24 @@ func detectRedhat(c config.ServerInfo) (bool, osTypeInterface) {
|
||||
family := constant.Amazon
|
||||
release := "unknown"
|
||||
if r := exec(c, "cat /etc/system-release", noSudo); r.isSuccess() {
|
||||
if strings.HasPrefix(r.Stdout, "Amazon Linux release 2022") {
|
||||
fields := strings.Fields(r.Stdout)
|
||||
release = strings.Join(fields[3:], " ")
|
||||
} else if strings.HasPrefix(r.Stdout, "Amazon Linux 2022") {
|
||||
fields := strings.Fields(r.Stdout)
|
||||
release = strings.Join(fields[2:], " ")
|
||||
} else if strings.HasPrefix(r.Stdout, "Amazon Linux release 2") {
|
||||
fields := strings.Fields(r.Stdout)
|
||||
release = fmt.Sprintf("%s %s", fields[3], fields[4])
|
||||
} else if strings.HasPrefix(r.Stdout, "Amazon Linux 2") {
|
||||
fields := strings.Fields(r.Stdout)
|
||||
release = strings.Join(fields[2:], " ")
|
||||
} else {
|
||||
switch {
|
||||
case strings.HasPrefix(r.Stdout, "Amazon Linux AMI release"):
|
||||
// Amazon Linux AMI release 2017.09
|
||||
// Amazon Linux AMI release 2018.03
|
||||
release = "1"
|
||||
case strings.HasPrefix(r.Stdout, "Amazon Linux 2"), strings.HasPrefix(r.Stdout, "Amazon Linux release 2"):
|
||||
// Amazon Linux 2 (Karoo)
|
||||
// Amazon Linux release 2 (Karoo)
|
||||
release = "2"
|
||||
case strings.HasPrefix(r.Stdout, "Amazon Linux 2022"), strings.HasPrefix(r.Stdout, "Amazon Linux release 2022"):
|
||||
// Amazon Linux 2022 (Amazon Linux)
|
||||
// Amazon Linux release 2022 (Amazon Linux)
|
||||
release = "2022"
|
||||
case strings.HasPrefix(r.Stdout, "Amazon Linux 2023"), strings.HasPrefix(r.Stdout, "Amazon Linux release 2023"):
|
||||
// Amazon Linux 2023 (Amazon Linux)
|
||||
// Amazon Linux release 2023 (Amazon Linux)
|
||||
release = "2023"
|
||||
default:
|
||||
fields := strings.Fields(r.Stdout)
|
||||
if len(fields) == 5 {
|
||||
release = fields[4]
|
||||
|
||||
@@ -6,10 +6,12 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
ex "os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
debver "github.com/knqyf263/go-deb-version"
|
||||
"golang.org/x/exp/maps"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/future-architect/vuls/cache"
|
||||
@@ -149,64 +151,123 @@ func (s Scanner) Configtest() error {
|
||||
|
||||
// ViaHTTP scans servers by HTTP header and body
|
||||
func ViaHTTP(header http.Header, body string, toLocalFile bool) (models.ScanResult, error) {
|
||||
family := header.Get("X-Vuls-OS-Family")
|
||||
if family == "" {
|
||||
return models.ScanResult{}, errOSFamilyHeader
|
||||
}
|
||||
|
||||
release := header.Get("X-Vuls-OS-Release")
|
||||
if release == "" {
|
||||
return models.ScanResult{}, errOSReleaseHeader
|
||||
}
|
||||
|
||||
kernelRelease := header.Get("X-Vuls-Kernel-Release")
|
||||
if kernelRelease == "" {
|
||||
logging.Log.Warn("If X-Vuls-Kernel-Release is not specified, there is a possibility of false detection")
|
||||
}
|
||||
|
||||
kernelVersion := header.Get("X-Vuls-Kernel-Version")
|
||||
if family == constant.Debian {
|
||||
if kernelVersion == "" {
|
||||
logging.Log.Warn("X-Vuls-Kernel-Version is empty. skip kernel vulnerability detection.")
|
||||
} else {
|
||||
if _, err := debver.NewVersion(kernelVersion); err != nil {
|
||||
logging.Log.Warnf("X-Vuls-Kernel-Version is invalid. skip kernel vulnerability detection. actual kernelVersion: %s, err: %s", kernelVersion, err)
|
||||
kernelVersion = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
serverName := header.Get("X-Vuls-Server-Name")
|
||||
if toLocalFile && serverName == "" {
|
||||
return models.ScanResult{}, errServerNameHeader
|
||||
}
|
||||
|
||||
distro := config.Distro{
|
||||
Family: family,
|
||||
Release: release,
|
||||
family := header.Get("X-Vuls-OS-Family")
|
||||
if family == "" {
|
||||
return models.ScanResult{}, errOSFamilyHeader
|
||||
}
|
||||
|
||||
kernel := models.Kernel{
|
||||
Release: kernelRelease,
|
||||
Version: kernelVersion,
|
||||
}
|
||||
installedPackages, srcPackages, err := ParseInstalledPkgs(distro, kernel, body)
|
||||
if err != nil {
|
||||
return models.ScanResult{}, err
|
||||
}
|
||||
switch family {
|
||||
case constant.Windows:
|
||||
osInfo, hotfixs, err := parseSystemInfo(toUTF8(body))
|
||||
if err != nil {
|
||||
return models.ScanResult{}, xerrors.Errorf("Failed to parse systeminfo.exe. err: %w", err)
|
||||
}
|
||||
|
||||
return models.ScanResult{
|
||||
ServerName: serverName,
|
||||
Family: family,
|
||||
Release: release,
|
||||
RunningKernel: models.Kernel{
|
||||
release := header.Get("X-Vuls-OS-Release")
|
||||
if release == "" {
|
||||
logging.Log.Debugf("osInfo(systeminfo.exe): %+v", osInfo)
|
||||
release, err = detectOSName(osInfo)
|
||||
if err != nil {
|
||||
return models.ScanResult{}, xerrors.Errorf("Failed to detect os name. err: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
kernelVersion := header.Get("X-Vuls-Kernel-Version")
|
||||
if kernelVersion == "" {
|
||||
kernelVersion = formatKernelVersion(osInfo)
|
||||
}
|
||||
|
||||
w := &windows{
|
||||
base: base{
|
||||
Distro: config.Distro{Family: family, Release: release},
|
||||
osPackages: osPackages{
|
||||
Kernel: models.Kernel{Version: kernelVersion},
|
||||
},
|
||||
log: logging.Log,
|
||||
},
|
||||
}
|
||||
|
||||
kbs, err := w.detectKBsFromKernelVersion()
|
||||
if err != nil {
|
||||
return models.ScanResult{}, xerrors.Errorf("Failed to detect KBs from kernel version. err: %w", err)
|
||||
}
|
||||
|
||||
applied, unapplied := map[string]struct{}{}, map[string]struct{}{}
|
||||
for _, kb := range hotfixs {
|
||||
applied[kb] = struct{}{}
|
||||
}
|
||||
for _, kb := range kbs.Applied {
|
||||
applied[kb] = struct{}{}
|
||||
}
|
||||
for _, kb := range kbs.Unapplied {
|
||||
unapplied[kb] = struct{}{}
|
||||
}
|
||||
|
||||
return models.ScanResult{
|
||||
ServerName: serverName,
|
||||
Family: family,
|
||||
Release: release,
|
||||
RunningKernel: models.Kernel{
|
||||
Version: kernelVersion,
|
||||
},
|
||||
WindowsKB: &models.WindowsKB{Applied: maps.Keys(applied), Unapplied: maps.Keys(unapplied)},
|
||||
ScannedCves: models.VulnInfos{},
|
||||
}, nil
|
||||
default:
|
||||
release := header.Get("X-Vuls-OS-Release")
|
||||
if release == "" {
|
||||
return models.ScanResult{}, errOSReleaseHeader
|
||||
}
|
||||
|
||||
kernelRelease := header.Get("X-Vuls-Kernel-Release")
|
||||
if kernelRelease == "" {
|
||||
logging.Log.Warn("If X-Vuls-Kernel-Release is not specified, there is a possibility of false detection")
|
||||
}
|
||||
|
||||
kernelVersion := header.Get("X-Vuls-Kernel-Version")
|
||||
if family == constant.Debian {
|
||||
if kernelVersion == "" {
|
||||
logging.Log.Warn("X-Vuls-Kernel-Version is empty. skip kernel vulnerability detection.")
|
||||
} else {
|
||||
if _, err := debver.NewVersion(kernelVersion); err != nil {
|
||||
logging.Log.Warnf("X-Vuls-Kernel-Version is invalid. skip kernel vulnerability detection. actual kernelVersion: %s, err: %s", kernelVersion, err)
|
||||
kernelVersion = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
distro := config.Distro{
|
||||
Family: family,
|
||||
Release: release,
|
||||
}
|
||||
|
||||
kernel := models.Kernel{
|
||||
Release: kernelRelease,
|
||||
Version: kernelVersion,
|
||||
},
|
||||
Packages: installedPackages,
|
||||
SrcPackages: srcPackages,
|
||||
ScannedCves: models.VulnInfos{},
|
||||
}, nil
|
||||
}
|
||||
installedPackages, srcPackages, err := ParseInstalledPkgs(distro, kernel, body)
|
||||
if err != nil {
|
||||
return models.ScanResult{}, err
|
||||
}
|
||||
|
||||
return models.ScanResult{
|
||||
ServerName: serverName,
|
||||
Family: family,
|
||||
Release: release,
|
||||
RunningKernel: models.Kernel{
|
||||
Release: kernelRelease,
|
||||
Version: kernelVersion,
|
||||
},
|
||||
Packages: installedPackages,
|
||||
SrcPackages: srcPackages,
|
||||
ScannedCves: models.VulnInfos{},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// ParseInstalledPkgs parses installed pkgs line
|
||||
@@ -342,7 +403,14 @@ func validateSSHConfig(c *config.ServerInfo) error {
|
||||
|
||||
logging.Log.Debugf("Validating SSH Settings for Server:%s ...", c.GetServerName())
|
||||
|
||||
sshBinaryPath, err := ex.LookPath("ssh")
|
||||
if runtime.GOOS == "windows" {
|
||||
c.Distro.Family = constant.Windows
|
||||
}
|
||||
defer func(c *config.ServerInfo) {
|
||||
c.Distro.Family = ""
|
||||
}(c)
|
||||
|
||||
sshBinaryPath, err := lookpath(c.Distro.Family, "ssh")
|
||||
if err != nil {
|
||||
return xerrors.Errorf("Failed to lookup ssh binary path. err: %w", err)
|
||||
}
|
||||
@@ -351,6 +419,10 @@ func validateSSHConfig(c *config.ServerInfo) error {
|
||||
logging.Log.Debugf("Executing... %s", strings.Replace(sshConfigCmd, "\n", "", -1))
|
||||
configResult := localExec(*c, sshConfigCmd, noSudo)
|
||||
if !configResult.isSuccess() {
|
||||
if strings.Contains(configResult.Stderr, "unknown option -- G") {
|
||||
logging.Log.Warn("SSH configuration validation is skipped. To enable validation, G option introduced in OpenSSH 6.8 must be enabled.")
|
||||
return nil
|
||||
}
|
||||
return xerrors.Errorf("Failed to print SSH configuration. err: %w", configResult.Error)
|
||||
}
|
||||
sshConfig := parseSSHConfiguration(configResult.Stdout)
|
||||
@@ -381,7 +453,7 @@ func validateSSHConfig(c *config.ServerInfo) error {
|
||||
return xerrors.New("Failed to find any known_hosts to use. Please check the UserKnownHostsFile and GlobalKnownHostsFile settings for SSH")
|
||||
}
|
||||
|
||||
sshKeyscanBinaryPath, err := ex.LookPath("ssh-keyscan")
|
||||
sshKeyscanBinaryPath, err := lookpath(c.Distro.Family, "ssh-keyscan")
|
||||
if err != nil {
|
||||
return xerrors.Errorf("Failed to lookup ssh-keyscan binary path. err: %w", err)
|
||||
}
|
||||
@@ -392,7 +464,7 @@ func validateSSHConfig(c *config.ServerInfo) error {
|
||||
}
|
||||
serverKeys := parseSSHScan(r.Stdout)
|
||||
|
||||
sshKeygenBinaryPath, err := ex.LookPath("ssh-keygen")
|
||||
sshKeygenBinaryPath, err := lookpath(c.Distro.Family, "ssh-keygen")
|
||||
if err != nil {
|
||||
return xerrors.Errorf("Failed to lookup ssh-keygen binary path. err: %w", err)
|
||||
}
|
||||
@@ -428,6 +500,19 @@ func validateSSHConfig(c *config.ServerInfo) error {
|
||||
buildSSHKeyScanCmd(sshKeyscanBinaryPath, c.Port, knownHostsPaths[0], sshConfig))
|
||||
}
|
||||
|
||||
func lookpath(family, file string) (string, error) {
|
||||
switch family {
|
||||
case constant.Windows:
|
||||
return fmt.Sprintf("%s.exe", strings.TrimPrefix(file, ".exe")), nil
|
||||
default:
|
||||
p, err := ex.LookPath(file)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
|
||||
func buildSSHBaseCmd(sshBinaryPath string, c *config.ServerInfo, options []string) []string {
|
||||
cmd := []string{sshBinaryPath}
|
||||
if len(options) > 0 {
|
||||
@@ -483,6 +568,7 @@ type sshConfiguration struct {
|
||||
func parseSSHConfiguration(stdout string) sshConfiguration {
|
||||
sshConfig := sshConfiguration{}
|
||||
for _, line := range strings.Split(stdout, "\n") {
|
||||
line = strings.TrimSuffix(line, "\r")
|
||||
switch {
|
||||
case strings.HasPrefix(line, "user "):
|
||||
sshConfig.user = strings.TrimPrefix(line, "user ")
|
||||
@@ -512,6 +598,7 @@ func parseSSHConfiguration(stdout string) sshConfiguration {
|
||||
func parseSSHScan(stdout string) map[string]string {
|
||||
keys := map[string]string{}
|
||||
for _, line := range strings.Split(stdout, "\n") {
|
||||
line = strings.TrimSuffix(line, "\r")
|
||||
if line == "" || strings.HasPrefix(line, "# ") {
|
||||
continue
|
||||
}
|
||||
@@ -524,6 +611,7 @@ func parseSSHScan(stdout string) map[string]string {
|
||||
|
||||
func parseSSHKeygen(stdout string) (string, string, error) {
|
||||
for _, line := range strings.Split(stdout, "\n") {
|
||||
line = strings.TrimSuffix(line, "\r")
|
||||
if line == "" || strings.HasPrefix(line, "# ") {
|
||||
continue
|
||||
}
|
||||
@@ -669,10 +757,20 @@ func (s Scanner) detectOS(c config.ServerInfo) osTypeInterface {
|
||||
return osType
|
||||
}
|
||||
|
||||
if itsMe, osType, fatalErr := s.detectDebianWithRetry(c); fatalErr != nil {
|
||||
osType.setErrs([]error{xerrors.Errorf("Failed to detect OS: %w", fatalErr)})
|
||||
if !isLocalExec(c.Port, c.Host) {
|
||||
if err := testFirstSSHConnection(c); err != nil {
|
||||
osType := &unknown{base{ServerInfo: c}}
|
||||
osType.setErrs([]error{xerrors.Errorf("Failed to test first SSH Connection. err: %w", err)})
|
||||
return osType
|
||||
}
|
||||
}
|
||||
|
||||
if itsMe, osType := detectWindows(c); itsMe {
|
||||
logging.Log.Debugf("Windows. Host: %s:%s", c.Host, c.Port)
|
||||
return osType
|
||||
} else if itsMe {
|
||||
}
|
||||
|
||||
if itsMe, osType := detectDebian(c); itsMe {
|
||||
logging.Log.Debugf("Debian based Linux. Host: %s:%s", c.Host, c.Port)
|
||||
return osType
|
||||
}
|
||||
@@ -702,28 +800,23 @@ func (s Scanner) detectOS(c config.ServerInfo) osTypeInterface {
|
||||
return osType
|
||||
}
|
||||
|
||||
// Retry as it may stall on the first SSH connection
|
||||
// https://github.com/future-architect/vuls/pull/753
|
||||
func (s Scanner) detectDebianWithRetry(c config.ServerInfo) (itsMe bool, deb osTypeInterface, err error) {
|
||||
type Response struct {
|
||||
itsMe bool
|
||||
deb osTypeInterface
|
||||
err error
|
||||
}
|
||||
resChan := make(chan Response, 1)
|
||||
go func(c config.ServerInfo) {
|
||||
itsMe, osType, fatalErr := detectDebian(c)
|
||||
resChan <- Response{itsMe, osType, fatalErr}
|
||||
}(c)
|
||||
|
||||
timeout := time.After(time.Duration(3) * time.Second)
|
||||
select {
|
||||
case res := <-resChan:
|
||||
return res.itsMe, res.deb, res.err
|
||||
case <-timeout:
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
return detectDebian(c)
|
||||
func testFirstSSHConnection(c config.ServerInfo) error {
|
||||
for i := 3; i > 0; i-- {
|
||||
rChan := make(chan execResult, 1)
|
||||
go func() {
|
||||
rChan <- exec(c, "exit", noSudo)
|
||||
}()
|
||||
select {
|
||||
case r := <-rChan:
|
||||
if r.ExitStatus == 255 {
|
||||
return xerrors.Errorf("Unable to connect via SSH. Scan with -vvv option to print SSH debugging messages and check SSH settings.\n%s", r)
|
||||
}
|
||||
return nil
|
||||
case <-time.After(time.Duration(3) * time.Second):
|
||||
}
|
||||
}
|
||||
logging.Log.Warnf("First SSH Connection to Host: %s:%s timeout", c.Host, c.Port)
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkScanModes checks scan mode
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/constant"
|
||||
"github.com/future-architect/vuls/models"
|
||||
@@ -104,6 +106,74 @@ func TestViaHTTP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
header: map[string]string{
|
||||
"X-Vuls-OS-Family": "windows",
|
||||
},
|
||||
body: `
|
||||
Host Name: DESKTOP
|
||||
OS Name: Microsoft Windows 10 Pro
|
||||
OS Version: 10.0.19044 N/A Build 19044
|
||||
OS Manufacturer: Microsoft Corporation
|
||||
OS Configuration: Member Workstation
|
||||
OS Build Type: Multiprocessor Free
|
||||
Registered Owner: Windows User
|
||||
Registered Organization:
|
||||
Product ID: 00000-00000-00000-AA000
|
||||
Original Install Date: 2022/04/13, 12:25:41
|
||||
System Boot Time: 2022/06/06, 16:43:45
|
||||
System Manufacturer: HP
|
||||
System Model: HP EliteBook 830 G7 Notebook PC
|
||||
System Type: x64-based PC
|
||||
Processor(s): 1 Processor(s) Installed.
|
||||
[01]: Intel64 Family 6 Model 142 Stepping 12 GenuineIntel ~1803 Mhz
|
||||
BIOS Version: HP S70 Ver. 01.05.00, 2021/04/26
|
||||
Windows Directory: C:\WINDOWS
|
||||
System Directory: C:\WINDOWS\system32
|
||||
Boot Device: \Device\HarddiskVolume2
|
||||
System Locale: en-us;English (United States)
|
||||
Input Locale: en-us;English (United States)
|
||||
Time Zone: (UTC-08:00) Pacific Time (US & Canada)
|
||||
Total Physical Memory: 15,709 MB
|
||||
Available Physical Memory: 12,347 MB
|
||||
Virtual Memory: Max Size: 18,141 MB
|
||||
Virtual Memory: Available: 14,375 MB
|
||||
Virtual Memory: In Use: 3,766 MB
|
||||
Page File Location(s): C:\pagefile.sys
|
||||
Domain: WORKGROUP
|
||||
Logon Server: \\DESKTOP
|
||||
Hotfix(s): 7 Hotfix(s) Installed.
|
||||
[01]: KB5012117
|
||||
[02]: KB4562830
|
||||
[03]: KB5003791
|
||||
[04]: KB5007401
|
||||
[05]: KB5012599
|
||||
[06]: KB5011651
|
||||
[07]: KB5005699
|
||||
Network Card(s): 1 NIC(s) Installed.
|
||||
[01]: Intel(R) Wi-Fi 6 AX201 160MHz
|
||||
Connection Name: Wi-Fi
|
||||
DHCP Enabled: Yes
|
||||
DHCP Server: 192.168.0.1
|
||||
IP address(es)
|
||||
[01]: 192.168.0.205
|
||||
Hyper-V Requirements: VM Monitor Mode Extensions: Yes
|
||||
Virtualization Enabled In Firmware: Yes
|
||||
Second Level Address Translation: Yes
|
||||
Data Execution Prevention Available: Yes
|
||||
`,
|
||||
expectedResult: models.ScanResult{
|
||||
Family: "windows",
|
||||
Release: "Windows 10 Version 21H2 for x64-based Systems",
|
||||
RunningKernel: models.Kernel{
|
||||
Version: "10.0.19044",
|
||||
},
|
||||
WindowsKB: &models.WindowsKB{
|
||||
Applied: []string{"5012117", "4562830", "5003791", "5007401", "5012599", "5011651", "5005699"},
|
||||
Unapplied: []string{},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
@@ -144,6 +214,18 @@ func TestViaHTTP(t *testing.T) {
|
||||
t.Errorf("release: expected %s, actual %s", expectedPack.Release, pack.Release)
|
||||
}
|
||||
}
|
||||
|
||||
if tt.expectedResult.WindowsKB != nil {
|
||||
slices.Sort(tt.expectedResult.WindowsKB.Applied)
|
||||
slices.Sort(tt.expectedResult.WindowsKB.Unapplied)
|
||||
}
|
||||
if result.WindowsKB != nil {
|
||||
slices.Sort(result.WindowsKB.Applied)
|
||||
slices.Sort(result.WindowsKB.Unapplied)
|
||||
}
|
||||
if !reflect.DeepEqual(tt.expectedResult.WindowsKB, result.WindowsKB) {
|
||||
t.Errorf("windows KB: expected %s, actual %s", tt.expectedResult.WindowsKB, result.WindowsKB)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ func isRunningKernel(pack models.Package, family string, kernel models.Kernel) (
|
||||
|
||||
// EnsureResultDir ensures the directory for scan results
|
||||
func EnsureResultDir(resultsDir string, scannedAt time.Time) (currentDir string, err error) {
|
||||
jsonDirName := scannedAt.Format(time.RFC3339)
|
||||
jsonDirName := scannedAt.Format("2006-01-02T15-04-05-0700")
|
||||
if resultsDir == "" {
|
||||
wd, _ := os.Getwd()
|
||||
resultsDir = filepath.Join(wd, "results")
|
||||
@@ -51,19 +51,6 @@ func EnsureResultDir(resultsDir string, scannedAt time.Time) (currentDir string,
|
||||
if err := os.MkdirAll(jsonDir, 0700); err != nil {
|
||||
return "", xerrors.Errorf("Failed to create dir: %w", err)
|
||||
}
|
||||
|
||||
symlinkPath := filepath.Join(resultsDir, "current")
|
||||
if _, err := os.Lstat(symlinkPath); err == nil {
|
||||
if err := os.Remove(symlinkPath); err != nil {
|
||||
return "", xerrors.Errorf(
|
||||
"Failed to remove symlink. path: %s, err: %w", symlinkPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := os.Symlink(jsonDir, symlinkPath); err != nil {
|
||||
return "", xerrors.Errorf(
|
||||
"Failed to create symlink: path: %s, err: %w", symlinkPath, err)
|
||||
}
|
||||
return jsonDir, nil
|
||||
}
|
||||
|
||||
|
||||
4452
scanner/windows.go
Normal file
4452
scanner/windows.go
Normal file
File diff suppressed because it is too large
Load Diff
905
scanner/windows_test.go
Normal file
905
scanner/windows_test.go
Normal file
@@ -0,0 +1,905 @@
|
||||
package scanner
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
func Test_parseSystemInfo(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args string
|
||||
osInfo osInfo
|
||||
kbs []string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Workstation",
|
||||
args: `
|
||||
Host Name: DESKTOP
|
||||
OS Name: Microsoft Windows 10 Pro
|
||||
OS Version: 10.0.19044 N/A Build 19044
|
||||
OS Manufacturer: Microsoft Corporation
|
||||
OS Configuration: Member Workstation
|
||||
OS Build Type: Multiprocessor Free
|
||||
Registered Owner: Windows User
|
||||
Registered Organization:
|
||||
Product ID: 00000-00000-00000-AA000
|
||||
Original Install Date: 2022/04/13, 12:25:41
|
||||
System Boot Time: 2022/06/06, 16:43:45
|
||||
System Manufacturer: HP
|
||||
System Model: HP EliteBook 830 G7 Notebook PC
|
||||
System Type: x64-based PC
|
||||
Processor(s): 1 Processor(s) Installed.
|
||||
[01]: Intel64 Family 6 Model 142 Stepping 12 GenuineIntel ~1803 Mhz
|
||||
BIOS Version: HP S70 Ver. 01.05.00, 2021/04/26
|
||||
Windows Directory: C:\WINDOWS
|
||||
System Directory: C:\WINDOWS\system32
|
||||
Boot Device: \Device\HarddiskVolume2
|
||||
System Locale: en-us;English (United States)
|
||||
Input Locale: en-us;English (United States)
|
||||
Time Zone: (UTC-08:00) Pacific Time (US & Canada)
|
||||
Total Physical Memory: 15,709 MB
|
||||
Available Physical Memory: 12,347 MB
|
||||
Virtual Memory: Max Size: 18,141 MB
|
||||
Virtual Memory: Available: 14,375 MB
|
||||
Virtual Memory: In Use: 3,766 MB
|
||||
Page File Location(s): C:\pagefile.sys
|
||||
Domain: WORKGROUP
|
||||
Logon Server: \\DESKTOP
|
||||
Hotfix(s): 7 Hotfix(s) Installed.
|
||||
[01]: KB5012117
|
||||
[02]: KB4562830
|
||||
[03]: KB5003791
|
||||
[04]: KB5007401
|
||||
[05]: KB5012599
|
||||
[06]: KB5011651
|
||||
[07]: KB5005699
|
||||
Network Card(s): 1 NIC(s) Installed.
|
||||
[01]: Intel(R) Wi-Fi 6 AX201 160MHz
|
||||
Connection Name: Wi-Fi
|
||||
DHCP Enabled: Yes
|
||||
DHCP Server: 192.168.0.1
|
||||
IP address(es)
|
||||
[01]: 192.168.0.205
|
||||
Hyper-V Requirements: VM Monitor Mode Extensions: Yes
|
||||
Virtualization Enabled In Firmware: Yes
|
||||
Second Level Address Translation: Yes
|
||||
Data Execution Prevention Available: Yes
|
||||
`,
|
||||
osInfo: osInfo{
|
||||
productName: "Microsoft Windows 10 Pro",
|
||||
version: "10.0",
|
||||
build: "19044",
|
||||
revision: "",
|
||||
edition: "",
|
||||
servicePack: "",
|
||||
arch: "x64-based",
|
||||
installationType: "Client",
|
||||
},
|
||||
kbs: []string{"5012117", "4562830", "5003791", "5007401", "5012599", "5011651", "5005699"},
|
||||
},
|
||||
{
|
||||
name: "Server",
|
||||
args: `
|
||||
Host Name: WIN-RIBN7SM07BK
|
||||
OS Name: Microsoft Windows Server 2022 Standard
|
||||
OS Version: 10.0.20348 N/A Build 20348
|
||||
OS Manufacturer: Microsoft Corporation
|
||||
OS Configuration: Standalone Server
|
||||
OS Build Type: Multiprocessor Free
|
||||
Registered Owner: Windows User
|
||||
Registered Organization:
|
||||
Product ID: 00454-10000-00001-AA483
|
||||
Original Install Date: 10/1/2021, 4:15:34 PM
|
||||
System Boot Time: 10/22/2021, 8:36:55 AM
|
||||
System Manufacturer: Microsoft Corporation
|
||||
System Model: Virtual Machine
|
||||
System Type: x64-based PC
|
||||
Processor(s): 1 Processor(s) Installed.
|
||||
[01]: Intel64 Family 6 Model 158 Stepping 9 GenuineIntel ~2808 Mhz
|
||||
BIOS Version: Microsoft Corporation Hyper-V UEFI Release v4.0, 12/17/2019
|
||||
Windows Directory: C:\Windows
|
||||
System Directory: C:\Windows\system32
|
||||
Boot Device: \Device\HarddiskVolume1
|
||||
System Locale: en-us;English (United States)
|
||||
Input Locale: en-us;English (United States)
|
||||
Time Zone: (UTC-08:00) Pacific Time (US & Canada)
|
||||
Total Physical Memory: 2,047 MB
|
||||
Available Physical Memory: 900 MB
|
||||
Virtual Memory: Max Size: 3,199 MB
|
||||
Virtual Memory: Available: 2,143 MB
|
||||
Virtual Memory: In Use: 1,056 MB
|
||||
Page File Location(s): C:\pagefile.sys
|
||||
Domain: WORKGROUP
|
||||
Logon Server: \\WIN-RIBN7SM07BK
|
||||
Hotfix(s): 3 Hotfix(s) Installed.
|
||||
[01]: KB5004330
|
||||
[02]: KB5005039
|
||||
[03]: KB5005552
|
||||
Network Card(s): 1 NIC(s) Installed.
|
||||
[01]: Microsoft Hyper-V Network Adapter
|
||||
Connection Name: Ethernet
|
||||
DHCP Enabled: Yes
|
||||
DHCP Server: 192.168.254.254
|
||||
IP address(es)
|
||||
[01]: 192.168.254.172
|
||||
[02]: fe80::b4a1:11cc:2c4:4f57
|
||||
Hyper-V Requirements: A hypervisor has been detected. Features required for Hyper-V will not be displayed.
|
||||
`,
|
||||
osInfo: osInfo{
|
||||
productName: "Microsoft Windows Server 2022 Standard",
|
||||
version: "10.0",
|
||||
build: "20348",
|
||||
revision: "",
|
||||
edition: "",
|
||||
servicePack: "",
|
||||
arch: "x64-based",
|
||||
installationType: "Server",
|
||||
},
|
||||
kbs: []string{"5004330", "5005039", "5005552"},
|
||||
},
|
||||
{
|
||||
name: "Domain Controller",
|
||||
args: `
|
||||
Host Name: vuls
|
||||
OS Name: Microsoft Windows Server 2019 Datacenter
|
||||
OS Version: 10.0.17763 N/A Build 17763
|
||||
OS Manufacturer: Microsoft Corporation
|
||||
OS Configuration: Primary Domain Controller
|
||||
OS Build Type: Multiprocessor Free
|
||||
Registered Owner: N/A
|
||||
Registered Organization: N/A
|
||||
Product ID: 00430-00000-00000-AA602
|
||||
Original Install Date: 1/16/2023, 10:04:07 AM
|
||||
System Boot Time: 3/28/2023, 8:37:14 AM
|
||||
System Manufacturer: Microsoft Corporation
|
||||
System Model: Virtual Machine
|
||||
System Type: x64-based PC
|
||||
Processor(s): 1 Processor(s) Installed.
|
||||
[01]: Intel64 Family 6 Model 85 Stepping 4 GenuineIntel ~2095 Mhz
|
||||
BIOS Version: Microsoft Corporation Hyper-V UEFI Release v4.1, 5/9/2022
|
||||
Windows Directory: C:\Windows
|
||||
System Directory: C:\Windows\system32
|
||||
Boot Device: \Device\HarddiskVolume3
|
||||
System Locale: en-us;English (United States)
|
||||
Input Locale: en-us;English (United States)
|
||||
Time Zone: (UTC) Coordinated Universal Time
|
||||
Total Physical Memory: 16,383 MB
|
||||
Available Physical Memory: 13,170 MB
|
||||
Virtual Memory: Max Size: 18,431 MB
|
||||
Virtual Memory: Available: 15,208 MB
|
||||
Virtual Memory: In Use: 3,223 MB
|
||||
Page File Location(s): C:\pagefile.sys
|
||||
Domain: vuls
|
||||
Logon Server: \\vuls
|
||||
Hotfix(s): 5 Hotfix(s) Installed.
|
||||
[01]: KB5022511
|
||||
[02]: KB5012170
|
||||
[03]: KB5023702
|
||||
[04]: KB5020374
|
||||
[05]: KB5023789
|
||||
Hyper-V Requirements: A hypervisor has been detected. Features required for Hyper-V will not be displayed.
|
||||
`,
|
||||
osInfo: osInfo{
|
||||
productName: "Microsoft Windows Server 2019 Datacenter",
|
||||
version: "10.0",
|
||||
build: "17763",
|
||||
revision: "",
|
||||
edition: "",
|
||||
servicePack: "",
|
||||
arch: "x64-based",
|
||||
installationType: "Domain Controller",
|
||||
},
|
||||
kbs: []string{"5022511", "5012170", "5023702", "5020374", "5023789"},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
osInfo, kbs, err := parseSystemInfo(tt.args)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("parseSystemInfo() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if osInfo != tt.osInfo {
|
||||
t.Errorf("parseSystemInfo() got = %v, want %v", osInfo, tt.osInfo)
|
||||
}
|
||||
if !reflect.DeepEqual(kbs, tt.kbs) {
|
||||
t.Errorf("parseSystemInfo() got = %v, want %v", kbs, tt.kbs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_parseGetComputerInfo(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args string
|
||||
want osInfo
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "happy",
|
||||
args: `
|
||||
WindowsProductName : Windows 10 Pro
|
||||
OsVersion : 10.0.19044
|
||||
WindowsEditionId : Professional
|
||||
OsCSDVersion :
|
||||
CsSystemType : x64-based PC
|
||||
WindowsInstallationType : Client
|
||||
`,
|
||||
want: osInfo{
|
||||
productName: "Windows 10 Pro",
|
||||
version: "10.0",
|
||||
build: "19044",
|
||||
revision: "",
|
||||
edition: "Professional",
|
||||
servicePack: "",
|
||||
arch: "x64-based",
|
||||
installationType: "Client",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := parseGetComputerInfo(tt.args)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("parseGetComputerInfo() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("parseGetComputerInfo() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_parseWmiObject(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args string
|
||||
want osInfo
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "happy",
|
||||
args: `
|
||||
Caption : Microsoft Windows 10 Pro
|
||||
Version : 10.0.19044
|
||||
OperatingSystemSKU : 48
|
||||
CSDVersion :
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
DomainRole : 1
|
||||
SystemType : x64-based PC`,
|
||||
want: osInfo{
|
||||
productName: "Microsoft Windows 10 Pro",
|
||||
version: "10.0",
|
||||
build: "19044",
|
||||
revision: "",
|
||||
edition: "Professional",
|
||||
servicePack: "",
|
||||
arch: "x64-based",
|
||||
installationType: "Client",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := parseWmiObject(tt.args)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("parseWmiObject() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("parseWmiObject() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_parseRegistry(t *testing.T) {
|
||||
type args struct {
|
||||
stdout string
|
||||
arch string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want osInfo
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "happy",
|
||||
args: args{
|
||||
stdout: `
|
||||
ProductName : Windows 10 Pro
|
||||
CurrentVersion : 6.3
|
||||
CurrentMajorVersionNumber : 10
|
||||
CurrentMinorVersionNumber : 0
|
||||
CurrentBuildNumber : 19044
|
||||
UBR : 2364
|
||||
EditionID : Professional
|
||||
InstallationType : Client`,
|
||||
arch: "AMD64",
|
||||
},
|
||||
want: osInfo{
|
||||
productName: "Windows 10 Pro",
|
||||
version: "10.0",
|
||||
build: "19044",
|
||||
revision: "2364",
|
||||
edition: "Professional",
|
||||
servicePack: "",
|
||||
arch: "x64-based",
|
||||
installationType: "Client",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := parseRegistry(tt.args.stdout, tt.args.arch)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("parseRegistry() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("parseRegistry() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_detectOSName(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args osInfo
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Windows 10 for x64-based Systems",
|
||||
args: osInfo{
|
||||
productName: "Microsoft Windows 10 Pro",
|
||||
version: "10.0",
|
||||
build: "10585",
|
||||
revision: "",
|
||||
edition: "Professional",
|
||||
servicePack: "",
|
||||
arch: "x64-based",
|
||||
installationType: "Client",
|
||||
},
|
||||
want: "Windows 10 for x64-based Systems",
|
||||
},
|
||||
{
|
||||
name: "Windows 10 Version 21H2 for x64-based Systems",
|
||||
args: osInfo{
|
||||
productName: "Microsoft Windows 10 Pro",
|
||||
version: "10.0",
|
||||
build: "19044",
|
||||
revision: "",
|
||||
edition: "Professional",
|
||||
servicePack: "",
|
||||
arch: "x64-based",
|
||||
installationType: "Client",
|
||||
},
|
||||
want: "Windows 10 Version 21H2 for x64-based Systems",
|
||||
},
|
||||
{
|
||||
name: "Windows Server 2022",
|
||||
args: osInfo{
|
||||
productName: "Windows Server",
|
||||
version: "10.0",
|
||||
build: "30000",
|
||||
revision: "",
|
||||
edition: "",
|
||||
servicePack: "",
|
||||
arch: "x64-based",
|
||||
installationType: "Server",
|
||||
},
|
||||
want: "Windows Server 2022",
|
||||
},
|
||||
{
|
||||
name: "Windows Server 2019",
|
||||
args: osInfo{
|
||||
productName: "Microsoft Windows Server 2019 Datacenter",
|
||||
version: "10.0",
|
||||
build: "17763",
|
||||
revision: "",
|
||||
edition: "",
|
||||
servicePack: "",
|
||||
arch: "x64-based",
|
||||
installationType: "Domain Controller",
|
||||
},
|
||||
want: "Windows Server 2019",
|
||||
},
|
||||
{
|
||||
name: "err",
|
||||
args: osInfo{
|
||||
productName: "Microsoft Windows 10 Pro",
|
||||
version: "10.0",
|
||||
build: "build",
|
||||
revision: "",
|
||||
edition: "Professional",
|
||||
servicePack: "",
|
||||
arch: "x64-based",
|
||||
installationType: "Client",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := detectOSName(tt.args)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("detectOSName() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("detectOSName() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_formatKernelVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args osInfo
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "major.minor.build.revision",
|
||||
args: osInfo{
|
||||
version: "10.0",
|
||||
build: "19045",
|
||||
revision: "2130",
|
||||
},
|
||||
want: "10.0.19045.2130",
|
||||
},
|
||||
{
|
||||
name: "major.minor.build",
|
||||
args: osInfo{
|
||||
version: "10.0",
|
||||
build: "19045",
|
||||
},
|
||||
want: "10.0.19045",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := formatKernelVersion(tt.args); got != tt.want {
|
||||
t.Errorf("formatKernelVersion() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_parseInstalledPackages(t *testing.T) {
|
||||
type args struct {
|
||||
stdout string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want models.Packages
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "happy",
|
||||
args: args{
|
||||
stdout: `
|
||||
Name : Git
|
||||
Version : 2.35.1.2
|
||||
ProviderName : Programs
|
||||
|
||||
Name : Oracle Database 11g Express Edition
|
||||
Version : 11.2.0
|
||||
ProviderName : msi
|
||||
|
||||
Name : 2022-12 x64 ベース システム用 Windows 10 Version 21H2 の累積更新プログラム (KB5021233)
|
||||
Version :
|
||||
ProviderName : msu
|
||||
`,
|
||||
},
|
||||
want: models.Packages{
|
||||
"Git": {
|
||||
Name: "Git",
|
||||
Version: "2.35.1.2",
|
||||
},
|
||||
"Oracle Database 11g Express Edition": {
|
||||
Name: "Oracle Database 11g Express Edition",
|
||||
Version: "11.2.0",
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
o := &windows{}
|
||||
got, _, err := o.parseInstalledPackages(tt.args.stdout)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("windows.parseInstalledPackages() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("windows.parseInstalledPackages() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_parseGetHotfix(t *testing.T) {
|
||||
type args struct {
|
||||
stdout string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "happy",
|
||||
args: args{
|
||||
stdout: `
|
||||
HotFixID : KB5020872
|
||||
|
||||
HotFixID : KB4562830
|
||||
`,
|
||||
},
|
||||
want: []string{"5020872", "4562830"},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
o := &windows{}
|
||||
got, err := o.parseGetHotfix(tt.args.stdout)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("windows.parseGetHotfix() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("windows.parseGetHotfix() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_parseGetPackageMSU(t *testing.T) {
|
||||
type args struct {
|
||||
stdout string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "happy",
|
||||
args: args{
|
||||
stdout: `
|
||||
Name : Git
|
||||
Version : 2.35.1.2
|
||||
ProviderName : Programs
|
||||
|
||||
Name : Oracle Database 11g Express Edition
|
||||
Version : 11.2.0
|
||||
ProviderName : msi
|
||||
|
||||
Name : 2022-12 x64 ベース システム用 Windows 10 Version 21H2 の累積更新プログラム (KB5021233)
|
||||
Version :
|
||||
ProviderName : msu
|
||||
`,
|
||||
},
|
||||
want: []string{"5021233"},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
o := &windows{}
|
||||
got, err := o.parseGetPackageMSU(tt.args.stdout)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("windows.parseGetPackageMSU() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("windows.parseGetPackageMSU() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_parseWindowsUpdaterSearch(t *testing.T) {
|
||||
type args struct {
|
||||
stdout string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "happy",
|
||||
args: args{
|
||||
stdout: `5012170
|
||||
5021233
|
||||
5021088
|
||||
`,
|
||||
},
|
||||
want: []string{"5012170", "5021233", "5021088"},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
o := &windows{}
|
||||
got, err := o.parseWindowsUpdaterSearch(tt.args.stdout)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("windows.parseWindowsUpdaterSearch() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("windows.parseWindowsUpdaterSearch() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_parseWindowsUpdateHistory(t *testing.T) {
|
||||
type args struct {
|
||||
stdout string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "happy",
|
||||
args: args{
|
||||
stdout: `
|
||||
Title : 2022-10 x64 ベース システム用 Windows 10 Version 21H2 の累積更新プログラム (KB5020435)
|
||||
Operation : 1
|
||||
ResultCode : 2
|
||||
|
||||
Title : 2022-10 x64 ベース システム用 Windows 10 Version 21H2 の累積更新プログラム (KB5020435)
|
||||
Operation : 2
|
||||
ResultCode : 2
|
||||
|
||||
Title : 2022-12 x64 (KB5021088) 向け Windows 10 Version 21H2 用 .NET Framework 3.5、4.8 および 4.8.1 の累積的な更新プログラム
|
||||
Operation : 1
|
||||
ResultCode : 2
|
||||
|
||||
Title : 2022-12 x64 ベース システム用 Windows 10 Version 21H2 の累積更新プログラム (KB5021233)
|
||||
Operation : 1
|
||||
ResultCode : 2
|
||||
`,
|
||||
},
|
||||
want: []string{"5021088", "5021233"},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
o := &windows{}
|
||||
got, err := o.parseWindowsUpdateHistory(tt.args.stdout)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("windows.parseWindowsUpdateHistory() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
slices.Sort(got)
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("windows.parseWindowsUpdateHistory() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_windows_detectKBsFromKernelVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
base base
|
||||
want models.WindowsKB
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "10.0.19045.2129",
|
||||
base: base{
|
||||
Distro: config.Distro{Release: "Windows 10 Version 22H2 for x64-based Systems"},
|
||||
osPackages: osPackages{Kernel: models.Kernel{Version: "10.0.19045.2129"}},
|
||||
},
|
||||
want: models.WindowsKB{
|
||||
Applied: nil,
|
||||
Unapplied: []string{"5020953", "5019959", "5020030", "5021233", "5022282", "5019275", "5022834", "5022906"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "10.0.19045.2130",
|
||||
base: base{
|
||||
Distro: config.Distro{Release: "Windows 10 Version 22H2 for x64-based Systems"},
|
||||
osPackages: osPackages{Kernel: models.Kernel{Version: "10.0.19045.2130"}},
|
||||
},
|
||||
want: models.WindowsKB{
|
||||
Applied: nil,
|
||||
Unapplied: []string{"5020953", "5019959", "5020030", "5021233", "5022282", "5019275", "5022834", "5022906"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "10.0.22621.1105",
|
||||
base: base{
|
||||
Distro: config.Distro{Release: "Windows 11 Version 22H2 for x64-based Systems"},
|
||||
osPackages: osPackages{Kernel: models.Kernel{Version: "10.0.22621.1105"}},
|
||||
},
|
||||
want: models.WindowsKB{
|
||||
Applied: []string{"5019311", "5017389", "5018427", "5019509", "5018496", "5019980", "5020044", "5021255", "5022303"},
|
||||
Unapplied: []string{"5022360", "5022845"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "10.0.20348.1547",
|
||||
base: base{
|
||||
Distro: config.Distro{Release: "Windows Server 2022"},
|
||||
osPackages: osPackages{Kernel: models.Kernel{Version: "10.0.20348.1547"}},
|
||||
},
|
||||
want: models.WindowsKB{
|
||||
Applied: []string{"5005575", "5005619", "5006699", "5006745", "5007205", "5007254", "5008223", "5010197", "5009555", "5010796", "5009608", "5010354", "5010421", "5011497", "5011558", "5012604", "5012637", "5013944", "5015013", "5014021", "5014678", "5014665", "5015827", "5015879", "5016627", "5016693", "5017316", "5017381", "5018421", "5020436", "5018485", "5019081", "5021656", "5020032", "5021249", "5022553", "5022291", "5022842"},
|
||||
Unapplied: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "err",
|
||||
base: base{
|
||||
Distro: config.Distro{Release: "Windows 10 Version 22H2 for x64-based Systems"},
|
||||
osPackages: osPackages{Kernel: models.Kernel{Version: "10.0"}},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
o := &windows{
|
||||
base: tt.base,
|
||||
}
|
||||
got, err := o.detectKBsFromKernelVersion()
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("windows.detectKBsFromKernelVersion() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("windows.detectKBsFromKernelVersion() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_windows_parseIP(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args string
|
||||
ipv4Addrs []string
|
||||
ipv6Addrs []string
|
||||
}{
|
||||
{
|
||||
name: "en",
|
||||
args: `
|
||||
|
||||
Windows IP Configuration
|
||||
|
||||
|
||||
Ethernet adapter イーサネット 4:
|
||||
|
||||
Connection-specific DNS Suffix . : vuls.local
|
||||
Link-local IPv6 Address . . . . . : fe80::19b6:ae27:d1fe:2041%33
|
||||
Link-local IPv6 Address . . . . . : fe80::7080:8828:5cc8:c0ba%33
|
||||
IPv4 Address. . . . . . . . . . . : 10.145.8.50
|
||||
Subnet Mask . . . . . . . . . . . : 255.255.0.0
|
||||
Default Gateway . . . . . . . . . : ::
|
||||
|
||||
Ethernet adapter イーサネット 2:
|
||||
|
||||
Connection-specific DNS Suffix . :
|
||||
Link-local IPv6 Address . . . . . : fe80::f49d:2c16:4270:759d%9
|
||||
IPv4 Address. . . . . . . . . . . : 192.168.56.1
|
||||
Subnet Mask . . . . . . . . . . . : 255.255.255.0
|
||||
Default Gateway . . . . . . . . . :
|
||||
|
||||
Wireless LAN adapter ローカル エリア接続* 1:
|
||||
|
||||
Media State . . . . . . . . . . . : Media disconnected
|
||||
Connection-specific DNS Suffix . :
|
||||
|
||||
Wireless LAN adapter ローカル エリア接続* 2:
|
||||
|
||||
Media State . . . . . . . . . . . : Media disconnected
|
||||
Connection-specific DNS Suffix . :
|
||||
|
||||
Wireless LAN adapter Wi-Fi:
|
||||
|
||||
Connection-specific DNS Suffix . :
|
||||
IPv4 Address. . . . . . . . . . . : 192.168.0.205
|
||||
Subnet Mask . . . . . . . . . . . : 255.255.255.0
|
||||
Default Gateway . . . . . . . . . : 192.168.0.1
|
||||
|
||||
Ethernet adapter Bluetooth ネットワーク接続:
|
||||
|
||||
Media State . . . . . . . . . . . : Media disconnected
|
||||
Connection-specific DNS Suffix . :
|
||||
`,
|
||||
ipv4Addrs: []string{"10.145.8.50", "192.168.56.1", "192.168.0.205"},
|
||||
ipv6Addrs: []string{"fe80::19b6:ae27:d1fe:2041", "fe80::7080:8828:5cc8:c0ba", "fe80::f49d:2c16:4270:759d"},
|
||||
},
|
||||
{
|
||||
name: "ja",
|
||||
args: `
|
||||
|
||||
Windows IP 構成
|
||||
|
||||
|
||||
イーサネット アダプター イーサネット 4:
|
||||
|
||||
接続固有の DNS サフィックス . . . . .: future.co.jp
|
||||
リンクローカル IPv6 アドレス. . . . .: fe80::19b6:ae27:d1fe:2041%33
|
||||
リンクローカル IPv6 アドレス. . . . .: fe80::7080:8828:5cc8:c0ba%33
|
||||
IPv4 アドレス . . . . . . . . . . . .: 10.145.8.50
|
||||
サブネット マスク . . . . . . . . . .: 255.255.0.0
|
||||
デフォルト ゲートウェイ . . . . . . .: ::
|
||||
|
||||
イーサネット アダプター イーサネット 2:
|
||||
|
||||
接続固有の DNS サフィックス . . . . .:
|
||||
リンクローカル IPv6 アドレス. . . . .: fe80::f49d:2c16:4270:759d%9
|
||||
IPv4 アドレス . . . . . . . . . . . .: 192.168.56.1
|
||||
サブネット マスク . . . . . . . . . .: 255.255.255.0
|
||||
デフォルト ゲートウェイ . . . . . . .:
|
||||
|
||||
Wireless LAN adapter ローカル エリア接続* 1:
|
||||
|
||||
メディアの状態. . . . . . . . . . . .: メディアは接続されていません
|
||||
接続固有の DNS サフィックス . . . . .:
|
||||
|
||||
Wireless LAN adapter ローカル エリア接続* 2:
|
||||
|
||||
メディアの状態. . . . . . . . . . . .: メディアは接続されていません
|
||||
接続固有の DNS サフィックス . . . . .:
|
||||
|
||||
Wireless LAN adapter Wi-Fi:
|
||||
|
||||
接続固有の DNS サフィックス . . . . .:
|
||||
IPv4 アドレス . . . . . . . . . . . .: 192.168.0.205
|
||||
サブネット マスク . . . . . . . . . .: 255.255.255.0
|
||||
デフォルト ゲートウェイ . . . . . . .: 192.168.0.1
|
||||
|
||||
イーサネット アダプター Bluetooth ネットワーク接続:
|
||||
|
||||
メディアの状態. . . . . . . . . . . .: メディアは接続されていません
|
||||
接続固有の DNS サフィックス . . . . .:
|
||||
`,
|
||||
ipv4Addrs: []string{"10.145.8.50", "192.168.56.1", "192.168.0.205"},
|
||||
ipv6Addrs: []string{"fe80::19b6:ae27:d1fe:2041", "fe80::7080:8828:5cc8:c0ba", "fe80::f49d:2c16:4270:759d"},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gotIPv4s, gotIPv6s := (&windows{}).parseIP(tt.args)
|
||||
if !reflect.DeepEqual(gotIPv4s, tt.ipv4Addrs) {
|
||||
t.Errorf("windows.parseIP() got = %v, want %v", gotIPv4s, tt.ipv4Addrs)
|
||||
}
|
||||
if !reflect.DeepEqual(gotIPv6s, tt.ipv6Addrs) {
|
||||
t.Errorf("windows.parseIP() got = %v, want %v", gotIPv6s, tt.ipv6Addrs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -39,13 +39,14 @@ func (h VulsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if mediatype == "application/json" {
|
||||
switch mediatype {
|
||||
case "application/json":
|
||||
if err = json.NewDecoder(req.Body).Decode(&r); err != nil {
|
||||
logging.Log.Error(err)
|
||||
http.Error(w, "Invalid JSON", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
} else if mediatype == "text/plain" {
|
||||
case "text/plain":
|
||||
buf := new(bytes.Buffer)
|
||||
if _, err := io.Copy(buf, req.Body); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
@@ -56,7 +57,7 @@ func (h VulsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
default:
|
||||
logging.Log.Error(mediatype)
|
||||
http.Error(w, fmt.Sprintf("Invalid Content-Type: %s", contentType), http.StatusUnsupportedMediaType)
|
||||
return
|
||||
|
||||
@@ -240,6 +240,7 @@ host = "{{$ip}}"
|
||||
#cmdPath = "/usr/local/bin/wp"
|
||||
#osUser = "wordpress"
|
||||
#docRoot = "/path/to/DocumentRoot/"
|
||||
#noSudo = false
|
||||
|
||||
#[servers.{{index $names $i}}.portscan]
|
||||
#scannerBinPath = "/usr/bin/nmap"
|
||||
@@ -247,6 +248,10 @@ host = "{{$ip}}"
|
||||
#scanTechniques = ["sS"]
|
||||
#sourcePort = "65535"
|
||||
|
||||
#[servers.{{index $names $i}}.windows]
|
||||
#serverSelection = 3
|
||||
#cabPath = "/path/to/wsusscn2.cab"
|
||||
|
||||
#[servers.{{index $names $i}}.optional]
|
||||
#key = "value1"
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build !scanner
|
||||
// +build !scanner
|
||||
//go:build !scanner && !windows
|
||||
|
||||
package subcmds
|
||||
|
||||
|
||||
372
subcmds/report_windows.go
Normal file
372
subcmds/report_windows.go
Normal file
@@ -0,0 +1,372 @@
|
||||
//go:build !scanner && windows
|
||||
|
||||
package subcmds
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/utils"
|
||||
"github.com/google/subcommands"
|
||||
"github.com/k0kubun/pp"
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/detector"
|
||||
"github.com/future-architect/vuls/logging"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/future-architect/vuls/reporter"
|
||||
)
|
||||
|
||||
// ReportCmd is subcommand for reporting
|
||||
type ReportCmd struct {
|
||||
configPath string
|
||||
|
||||
formatJSON bool
|
||||
formatOneEMail bool
|
||||
formatCsv bool
|
||||
formatFullText bool
|
||||
formatOneLineText bool
|
||||
formatList bool
|
||||
formatCycloneDXJSON bool
|
||||
formatCycloneDXXML bool
|
||||
gzip bool
|
||||
|
||||
toSlack bool
|
||||
toChatWork bool
|
||||
toGoogleChat bool
|
||||
toTelegram bool
|
||||
toEmail bool
|
||||
toLocalFile bool
|
||||
toS3 bool
|
||||
toAzureBlob bool
|
||||
toHTTP bool
|
||||
}
|
||||
|
||||
// Name return subcommand name
|
||||
func (*ReportCmd) Name() string { return "report" }
|
||||
|
||||
// Synopsis return synopsis
|
||||
func (*ReportCmd) Synopsis() string { return "Reporting" }
|
||||
|
||||
// Usage return usage
|
||||
func (*ReportCmd) Usage() string {
|
||||
return `report:
|
||||
report
|
||||
[-lang=en|ja]
|
||||
[-config=/path/to/config.toml]
|
||||
[-results-dir=/path/to/results]
|
||||
[-log-to-file]
|
||||
[-log-dir=/path/to/log]
|
||||
[-refresh-cve]
|
||||
[-cvss-over=7]
|
||||
[-confidence-over=80]
|
||||
[-diff]
|
||||
[-diff-minus]
|
||||
[-diff-plus]
|
||||
[-ignore-unscored-cves]
|
||||
[-ignore-unfixed]
|
||||
[-to-email]
|
||||
[-to-http]
|
||||
[-to-slack]
|
||||
[-to-chatwork]
|
||||
[-to-googlechat]
|
||||
[-to-telegram]
|
||||
[-to-localfile]
|
||||
[-to-s3]
|
||||
[-to-azure-blob]
|
||||
[-format-json]
|
||||
[-format-one-email]
|
||||
[-format-one-line-text]
|
||||
[-format-list]
|
||||
[-format-full-text]
|
||||
[-format-csv]
|
||||
[-format-cyclonedx-json]
|
||||
[-format-cyclonedx-xml]
|
||||
[-gzip]
|
||||
[-http-proxy=http://192.168.0.1:8080]
|
||||
[-debug]
|
||||
[-debug-sql]
|
||||
[-quiet]
|
||||
[-no-progress]
|
||||
[-pipe]
|
||||
[-http="http://vuls-report-server"]
|
||||
[-trivy-cachedb-dir=/path/to/dir]
|
||||
|
||||
[RFC3339 datetime format under results dir]
|
||||
`
|
||||
}
|
||||
|
||||
// SetFlags set flag
|
||||
func (p *ReportCmd) SetFlags(f *flag.FlagSet) {
|
||||
f.StringVar(&config.Conf.Lang, "lang", "en", "[en|ja]")
|
||||
f.BoolVar(&config.Conf.Debug, "debug", false, "debug mode")
|
||||
f.BoolVar(&config.Conf.DebugSQL, "debug-sql", false, "SQL debug mode")
|
||||
f.BoolVar(&config.Conf.Quiet, "quiet", false, "Quiet mode. No output on stdout")
|
||||
f.BoolVar(&config.Conf.NoProgress, "no-progress", false, "Suppress progress bar")
|
||||
|
||||
wd, _ := os.Getwd()
|
||||
defaultConfPath := filepath.Join(wd, "config.toml")
|
||||
f.StringVar(&p.configPath, "config", defaultConfPath, "/path/to/toml")
|
||||
|
||||
defaultResultsDir := filepath.Join(wd, "results")
|
||||
f.StringVar(&config.Conf.ResultsDir, "results-dir", defaultResultsDir, "/path/to/results")
|
||||
|
||||
defaultLogDir := logging.GetDefaultLogDir()
|
||||
f.StringVar(&config.Conf.LogDir, "log-dir", defaultLogDir, "/path/to/log")
|
||||
f.BoolVar(&config.Conf.LogToFile, "log-to-file", false, "Output log to file")
|
||||
|
||||
f.BoolVar(&config.Conf.RefreshCve, "refresh-cve", false,
|
||||
"Refresh CVE information in JSON file under results dir")
|
||||
|
||||
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")
|
||||
|
||||
f.BoolVar(&config.Conf.DiffPlus, "diff-plus", false,
|
||||
"Plus Difference between previous result and current result")
|
||||
|
||||
f.BoolVar(&config.Conf.Diff, "diff", false,
|
||||
"Plus & Minus Difference between previous result and current result")
|
||||
|
||||
f.BoolVar(&config.Conf.IgnoreUnscoredCves, "ignore-unscored-cves", false,
|
||||
"Don't report the unscored CVEs")
|
||||
|
||||
f.BoolVar(&config.Conf.IgnoreUnfixed, "ignore-unfixed", false,
|
||||
"Don't report the unfixed CVEs")
|
||||
|
||||
f.StringVar(
|
||||
&config.Conf.HTTPProxy, "http-proxy", "",
|
||||
"http://proxy-url:port (default: empty)")
|
||||
|
||||
f.BoolVar(&p.formatJSON, "format-json", false, "JSON format")
|
||||
f.BoolVar(&p.formatCsv, "format-csv", false, "CSV format")
|
||||
f.BoolVar(&p.formatOneEMail, "format-one-email", false,
|
||||
"Send all the host report via only one EMail (Specify with -to-email)")
|
||||
f.BoolVar(&p.formatOneLineText, "format-one-line-text", false,
|
||||
"One line summary in plain text")
|
||||
f.BoolVar(&p.formatList, "format-list", false, "Display as list format")
|
||||
f.BoolVar(&p.formatFullText, "format-full-text", false,
|
||||
"Detail report in plain text")
|
||||
f.BoolVar(&p.formatCycloneDXJSON, "format-cyclonedx-json", false, "CycloneDX JSON format")
|
||||
f.BoolVar(&p.formatCycloneDXXML, "format-cyclonedx-xml", false, "CycloneDX XML format")
|
||||
|
||||
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.toLocalFile, "to-localfile", false, "Write report to localfile")
|
||||
f.BoolVar(&p.toS3, "to-s3", false, "Write report to S3 (bucket/yyyyMMdd_HHmm/servername.json/txt)")
|
||||
f.BoolVar(&p.toHTTP, "to-http", false, "Send report via HTTP POST")
|
||||
f.BoolVar(&p.toAzureBlob, "to-azure-blob", false,
|
||||
"Write report to Azure Storage blob (container/yyyyMMdd_HHmm/servername.json/txt)")
|
||||
|
||||
f.BoolVar(&p.gzip, "gzip", false, "gzip compression")
|
||||
f.BoolVar(&config.Conf.Pipe, "pipe", false, "Use args passed via PIPE")
|
||||
|
||||
f.StringVar(&config.Conf.TrivyCacheDBDir, "trivy-cachedb-dir",
|
||||
utils.DefaultCacheDir(), "/path/to/dir")
|
||||
}
|
||||
|
||||
// Execute execute
|
||||
func (p *ReportCmd) 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 p.configPath == "" {
|
||||
for _, cnf := range []config.VulnDictInterface{
|
||||
&config.Conf.CveDict,
|
||||
&config.Conf.OvalDict,
|
||||
&config.Conf.Gost,
|
||||
&config.Conf.Exploit,
|
||||
&config.Conf.Metasploit,
|
||||
&config.Conf.KEVuln,
|
||||
} {
|
||||
cnf.Init()
|
||||
}
|
||||
} else {
|
||||
if err := config.Load(p.configPath); err != nil {
|
||||
logging.Log.Errorf("Error loading %s. err: %+v", p.configPath, err)
|
||||
return subcommands.ExitUsageError
|
||||
}
|
||||
}
|
||||
|
||||
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.AWS.Enabled = p.toS3
|
||||
config.Conf.Azure.Enabled = p.toAzureBlob
|
||||
config.Conf.HTTP.Enabled = p.toHTTP
|
||||
|
||||
if config.Conf.Diff {
|
||||
config.Conf.DiffPlus, config.Conf.DiffMinus = true, true
|
||||
}
|
||||
|
||||
var dir string
|
||||
var err error
|
||||
if config.Conf.DiffPlus || config.Conf.DiffMinus {
|
||||
dir, err = reporter.JSONDir(config.Conf.ResultsDir, []string{})
|
||||
} else {
|
||||
dir, err = reporter.JSONDir(config.Conf.ResultsDir, f.Args())
|
||||
}
|
||||
if err != nil {
|
||||
logging.Log.Errorf("Failed to read from JSON: %+v", err)
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
|
||||
logging.Log.Info("Validating config...")
|
||||
if !config.Conf.ValidateOnReport() {
|
||||
return subcommands.ExitUsageError
|
||||
}
|
||||
|
||||
if !(p.formatJSON || p.formatOneLineText ||
|
||||
p.formatList || p.formatFullText || p.formatCsv ||
|
||||
p.formatCycloneDXJSON || p.formatCycloneDXXML) {
|
||||
p.formatList = true
|
||||
}
|
||||
|
||||
var loaded models.ScanResults
|
||||
if loaded, err = reporter.LoadScanResults(dir); err != nil {
|
||||
logging.Log.Error(err)
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
logging.Log.Infof("Loaded: %s", dir)
|
||||
|
||||
var res models.ScanResults
|
||||
hasError := false
|
||||
for _, r := range loaded {
|
||||
if len(r.Errors) == 0 {
|
||||
res = append(res, r)
|
||||
} else {
|
||||
logging.Log.Errorf("Ignored since errors occurred during scanning: %s, err: %v",
|
||||
r.ServerName, r.Errors)
|
||||
hasError = true
|
||||
}
|
||||
}
|
||||
|
||||
if len(res) == 0 {
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
|
||||
for _, r := range res {
|
||||
logging.Log.Debugf("%s: %s",
|
||||
r.ServerInfo(), pp.Sprintf("%s", config.Conf.Servers[r.ServerName]))
|
||||
}
|
||||
|
||||
if res, err = detector.Detect(res, dir); err != nil {
|
||||
logging.Log.Errorf("%+v", err)
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
|
||||
// report
|
||||
reports := []reporter.ResultWriter{
|
||||
reporter.StdoutWriter{
|
||||
FormatFullText: p.formatFullText,
|
||||
FormatOneLineText: p.formatOneLineText,
|
||||
FormatList: p.formatList,
|
||||
},
|
||||
}
|
||||
|
||||
if p.toSlack {
|
||||
reports = append(reports, reporter.SlackWriter{
|
||||
FormatOneLineText: p.formatOneLineText,
|
||||
Cnf: config.Conf.Slack,
|
||||
Proxy: config.Conf.HTTPProxy,
|
||||
})
|
||||
}
|
||||
|
||||
if p.toChatWork {
|
||||
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})
|
||||
}
|
||||
|
||||
if p.toEmail {
|
||||
reports = append(reports, reporter.EMailWriter{
|
||||
FormatOneEMail: p.formatOneEMail,
|
||||
FormatOneLineText: p.formatOneLineText,
|
||||
FormatList: p.formatList,
|
||||
Cnf: config.Conf.EMail,
|
||||
})
|
||||
}
|
||||
|
||||
if p.toHTTP {
|
||||
reports = append(reports, reporter.HTTPRequestWriter{URL: config.Conf.HTTP.URL})
|
||||
}
|
||||
|
||||
if p.toLocalFile {
|
||||
reports = append(reports, reporter.LocalFileWriter{
|
||||
CurrentDir: dir,
|
||||
DiffPlus: config.Conf.DiffPlus,
|
||||
DiffMinus: config.Conf.DiffMinus,
|
||||
FormatJSON: p.formatJSON,
|
||||
FormatCsv: p.formatCsv,
|
||||
FormatFullText: p.formatFullText,
|
||||
FormatOneLineText: p.formatOneLineText,
|
||||
FormatList: p.formatList,
|
||||
FormatCycloneDXJSON: p.formatCycloneDXJSON,
|
||||
FormatCycloneDXXML: p.formatCycloneDXXML,
|
||||
Gzip: p.gzip,
|
||||
})
|
||||
}
|
||||
|
||||
if p.toS3 {
|
||||
w := reporter.S3Writer{
|
||||
FormatJSON: p.formatJSON,
|
||||
FormatFullText: p.formatFullText,
|
||||
FormatOneLineText: p.formatOneLineText,
|
||||
FormatList: p.formatList,
|
||||
Gzip: p.gzip,
|
||||
AWSConf: config.Conf.AWS,
|
||||
}
|
||||
if err := w.Validate(); err != nil {
|
||||
logging.Log.Errorf("Check if there is a bucket beforehand: %s, err: %+v", config.Conf.AWS.S3Bucket, err)
|
||||
return subcommands.ExitUsageError
|
||||
}
|
||||
reports = append(reports, w)
|
||||
}
|
||||
|
||||
if p.toAzureBlob {
|
||||
w := reporter.AzureBlobWriter{
|
||||
FormatJSON: p.formatJSON,
|
||||
FormatFullText: p.formatFullText,
|
||||
FormatOneLineText: p.formatOneLineText,
|
||||
FormatList: p.formatList,
|
||||
Gzip: p.gzip,
|
||||
AzureConf: config.Conf.Azure,
|
||||
}
|
||||
if err := w.Validate(); err != nil {
|
||||
logging.Log.Errorf("Check if there is a container beforehand: %s, err: %+v", config.Conf.Azure.ContainerName, err)
|
||||
return subcommands.ExitUsageError
|
||||
}
|
||||
reports = append(reports, w)
|
||||
}
|
||||
|
||||
for _, w := range reports {
|
||||
if err := w.Write(res...); err != nil {
|
||||
logging.Log.Errorf("Failed to report. err: %+v", err)
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
}
|
||||
|
||||
if hasError {
|
||||
return subcommands.ExitFailure
|
||||
}
|
||||
|
||||
return subcommands.ExitSuccess
|
||||
}
|
||||
@@ -91,9 +91,8 @@ func (p *SaaSCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{})
|
||||
var res models.ScanResults
|
||||
hasError := false
|
||||
for _, r := range loaded {
|
||||
if len(r.Errors) == 0 {
|
||||
res = append(res, r)
|
||||
} else {
|
||||
res = append(res, r)
|
||||
if len(r.Errors) != 0 {
|
||||
logging.Log.Errorf("Ignored since errors occurred during scanning: %s, err: %v",
|
||||
r.ServerName, r.Errors)
|
||||
hasError = true
|
||||
|
||||
@@ -614,6 +614,7 @@ func summaryLines(r models.ScanResult) string {
|
||||
pkgNames = append(pkgNames, vinfo.GitHubSecurityAlerts.Names()...)
|
||||
pkgNames = append(pkgNames, vinfo.WpPackageFixStats.Names()...)
|
||||
pkgNames = append(pkgNames, vinfo.LibraryFixedIns.Names()...)
|
||||
pkgNames = append(pkgNames, vinfo.WindowsKBFixedIns...)
|
||||
|
||||
av := vinfo.AttackVector()
|
||||
for _, pname := range vinfo.AffectedPackages.Names() {
|
||||
|
||||
Reference in New Issue
Block a user